diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..5cde165
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,7 @@
+version: 2
+updates:
+- package-ecosystem: cargo
+ directory: "/"
+ schedule:
+ interval: daily
+ open-pull-requests-limit: 10
diff --git a/.github/workflows/cbc.yaml b/.github/workflows/cbc.yaml
new file mode 100644
index 0000000..41a3fc4
--- /dev/null
+++ b/.github/workflows/cbc.yaml
@@ -0,0 +1,55 @@
+name: cbc
+
+on:
+ pull_request:
+ paths:
+ - "cbc/**"
+ - "Cargo.*"
+ push:
+ branches: master
+
+defaults:
+ run:
+ working-directory: cbc
+
+env:
+ CARGO_INCREMENTAL: 0
+ RUSTFLAGS: "-Dwarnings"
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ rust:
+ - 1.56.0 # MSRV
+ - stable
+ target:
+ - thumbv7em-none-eabi
+ - wasm32-unknown-unknown
+ steps:
+ - uses: actions/checkout@v1
+ - uses: actions-rs/toolchain@v1
+ with:
+ toolchain: ${{ matrix.rust }}
+ target: ${{ matrix.target }}
+ override: true
+ profile: minimal
+ - run: cargo build --no-default-features --release --target ${{ matrix.target }}
+
+ test:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ rust:
+ - 1.56.0 # MSRV
+ - stable
+ steps:
+ - uses: actions/checkout@v1
+ - uses: actions-rs/toolchain@v1
+ with:
+ toolchain: ${{ matrix.rust }}
+ override: true
+ profile: minimal
+ - run: cargo test
+ - run: cargo test --all-features
diff --git a/.github/workflows/cfb-mode.yaml b/.github/workflows/cfb-mode.yaml
new file mode 100644
index 0000000..41880b5
--- /dev/null
+++ b/.github/workflows/cfb-mode.yaml
@@ -0,0 +1,55 @@
+name: cfb-mode
+
+on:
+ pull_request:
+ paths:
+ - "cfb-mode/**"
+ - "Cargo.*"
+ push:
+ branches: master
+
+defaults:
+ run:
+ working-directory: cfb-mode
+
+env:
+ CARGO_INCREMENTAL: 0
+ RUSTFLAGS: "-Dwarnings"
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ rust:
+ - 1.56.0 # MSRV
+ - stable
+ target:
+ - thumbv7em-none-eabi
+ - wasm32-unknown-unknown
+ steps:
+ - uses: actions/checkout@v1
+ - uses: actions-rs/toolchain@v1
+ with:
+ toolchain: ${{ matrix.rust }}
+ target: ${{ matrix.target }}
+ override: true
+ profile: minimal
+ - run: cargo build --no-default-features --release --target ${{ matrix.target }}
+
+ test:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ rust:
+ - 1.56.0 # MSRV
+ - stable
+ steps:
+ - uses: actions/checkout@v1
+ - uses: actions-rs/toolchain@v1
+ with:
+ toolchain: ${{ matrix.rust }}
+ override: true
+ profile: minimal
+ - run: cargo test
+ - run: cargo test --all-features
diff --git a/.github/workflows/cfb8.yaml b/.github/workflows/cfb8.yaml
new file mode 100644
index 0000000..53ea01e
--- /dev/null
+++ b/.github/workflows/cfb8.yaml
@@ -0,0 +1,55 @@
+name: cfb8
+
+on:
+ pull_request:
+ paths:
+ - "cfb8/**"
+ - "Cargo.*"
+ push:
+ branches: master
+
+defaults:
+ run:
+ working-directory: cfb8
+
+env:
+ CARGO_INCREMENTAL: 0
+ RUSTFLAGS: "-Dwarnings"
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ rust:
+ - 1.56.0 # MSRV
+ - stable
+ target:
+ - thumbv7em-none-eabi
+ - wasm32-unknown-unknown
+ steps:
+ - uses: actions/checkout@v1
+ - uses: actions-rs/toolchain@v1
+ with:
+ toolchain: ${{ matrix.rust }}
+ target: ${{ matrix.target }}
+ override: true
+ profile: minimal
+ - run: cargo build --no-default-features --release --target ${{ matrix.target }}
+
+ test:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ rust:
+ - 1.56.0 # MSRV
+ - stable
+ steps:
+ - uses: actions/checkout@v1
+ - uses: actions-rs/toolchain@v1
+ with:
+ toolchain: ${{ matrix.rust }}
+ override: true
+ profile: minimal
+ - run: cargo test
+ - run: cargo test --all-features
diff --git a/.github/workflows/ctr.yaml b/.github/workflows/ctr.yaml
new file mode 100644
index 0000000..4baac54
--- /dev/null
+++ b/.github/workflows/ctr.yaml
@@ -0,0 +1,55 @@
+name: ctr
+
+on:
+ pull_request:
+ paths:
+ - "ctr/**"
+ - "Cargo.*"
+ push:
+ branches: master
+
+defaults:
+ run:
+ working-directory: ctr
+
+env:
+ CARGO_INCREMENTAL: 0
+ RUSTFLAGS: "-Dwarnings"
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ rust:
+ - 1.56.0 # MSRV
+ - stable
+ target:
+ - thumbv7em-none-eabi
+ - wasm32-unknown-unknown
+ steps:
+ - uses: actions/checkout@v1
+ - uses: actions-rs/toolchain@v1
+ with:
+ toolchain: ${{ matrix.rust }}
+ target: ${{ matrix.target }}
+ override: true
+ profile: minimal
+ - run: cargo build --no-default-features --release --target ${{ matrix.target }}
+
+ test:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ rust:
+ - 1.56.0 # MSRV
+ - stable
+ steps:
+ - uses: actions/checkout@v1
+ - uses: actions-rs/toolchain@v1
+ with:
+ toolchain: ${{ matrix.rust }}
+ override: true
+ profile: minimal
+ - run: cargo test
+ - run: cargo test --all-features
diff --git a/.github/workflows/ige.yaml b/.github/workflows/ige.yaml
new file mode 100644
index 0000000..6792c36
--- /dev/null
+++ b/.github/workflows/ige.yaml
@@ -0,0 +1,55 @@
+name: ige
+
+on:
+ pull_request:
+ paths:
+ - "ige/**"
+ - "Cargo.*"
+ push:
+ branches: master
+
+defaults:
+ run:
+ working-directory: ige
+
+env:
+ CARGO_INCREMENTAL: 0
+ RUSTFLAGS: "-Dwarnings"
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ rust:
+ - 1.56.0 # MSRV
+ - stable
+ target:
+ - thumbv7em-none-eabi
+ - wasm32-unknown-unknown
+ steps:
+ - uses: actions/checkout@v1
+ - uses: actions-rs/toolchain@v1
+ with:
+ toolchain: ${{ matrix.rust }}
+ target: ${{ matrix.target }}
+ override: true
+ profile: minimal
+ - run: cargo build --no-default-features --release --target ${{ matrix.target }}
+
+ test:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ rust:
+ - 1.56.0 # MSRV
+ - stable
+ steps:
+ - uses: actions/checkout@v1
+ - uses: actions-rs/toolchain@v1
+ with:
+ toolchain: ${{ matrix.rust }}
+ override: true
+ profile: minimal
+ - run: cargo test
+ - run: cargo test --all-features
diff --git a/.github/workflows/ofb.yaml b/.github/workflows/ofb.yaml
new file mode 100644
index 0000000..a2b3e0e
--- /dev/null
+++ b/.github/workflows/ofb.yaml
@@ -0,0 +1,55 @@
+name: ofb
+
+on:
+ pull_request:
+ paths:
+ - "ofb/**"
+ - "Cargo.*"
+ push:
+ branches: master
+
+defaults:
+ run:
+ working-directory: ofb
+
+env:
+ CARGO_INCREMENTAL: 0
+ RUSTFLAGS: "-Dwarnings"
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ rust:
+ - 1.56.0 # MSRV
+ - stable
+ target:
+ - thumbv7em-none-eabi
+ - wasm32-unknown-unknown
+ steps:
+ - uses: actions/checkout@v1
+ - uses: actions-rs/toolchain@v1
+ with:
+ toolchain: ${{ matrix.rust }}
+ target: ${{ matrix.target }}
+ override: true
+ profile: minimal
+ - run: cargo build --no-default-features --release --target ${{ matrix.target }}
+
+ test:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ rust:
+ - 1.56.0 # MSRV
+ - stable
+ steps:
+ - uses: actions/checkout@v1
+ - uses: actions-rs/toolchain@v1
+ with:
+ toolchain: ${{ matrix.rust }}
+ override: true
+ profile: minimal
+ - run: cargo test
+ - run: cargo test --all-features
diff --git a/.github/workflows/pcbc.yaml b/.github/workflows/pcbc.yaml
new file mode 100644
index 0000000..7f26013
--- /dev/null
+++ b/.github/workflows/pcbc.yaml
@@ -0,0 +1,55 @@
+name: pcbc
+
+on:
+ pull_request:
+ paths:
+ - "pcbc/**"
+ - "Cargo.*"
+ push:
+ branches: master
+
+defaults:
+ run:
+ working-directory: pcbc
+
+env:
+ CARGO_INCREMENTAL: 0
+ RUSTFLAGS: "-Dwarnings"
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ rust:
+ - 1.56.0 # MSRV
+ - stable
+ target:
+ - thumbv7em-none-eabi
+ - wasm32-unknown-unknown
+ steps:
+ - uses: actions/checkout@v1
+ - uses: actions-rs/toolchain@v1
+ with:
+ toolchain: ${{ matrix.rust }}
+ target: ${{ matrix.target }}
+ override: true
+ profile: minimal
+ - run: cargo build --no-default-features --release --target ${{ matrix.target }}
+
+ test:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ rust:
+ - 1.56.0 # MSRV
+ - stable
+ steps:
+ - uses: actions/checkout@v1
+ - uses: actions-rs/toolchain@v1
+ with:
+ toolchain: ${{ matrix.rust }}
+ override: true
+ profile: minimal
+ - run: cargo test
+ - run: cargo test --all-features
diff --git a/.github/workflows/security-audit.yml b/.github/workflows/security-audit.yml
new file mode 100644
index 0000000..0d82d54
--- /dev/null
+++ b/.github/workflows/security-audit.yml
@@ -0,0 +1,24 @@
+name: Security Audit
+on:
+ pull_request:
+ paths: Cargo.lock
+ push:
+ branches: master
+ paths: Cargo.lock
+ schedule:
+ - cron: "0 0 * * *"
+
+jobs:
+ security_audit:
+ name: Security Audit
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v1
+ - name: Cache cargo bin
+ uses: actions/cache@v1
+ with:
+ path: ~/.cargo/bin
+ key: ${{ runner.os }}-cargo-audit-v0.12.0
+ - uses: actions-rs/audit-check@v1
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/workspace.yml b/.github/workflows/workspace.yml
new file mode 100644
index 0000000..599f211
--- /dev/null
+++ b/.github/workflows/workspace.yml
@@ -0,0 +1,53 @@
+name: Workspace
+
+on:
+ pull_request:
+ paths-ignore:
+ - README.md
+ push:
+ branches: master
+ paths-ignore:
+ - README.md
+
+jobs:
+ clippy:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v1
+ - uses: actions-rs/toolchain@v1
+ with:
+ toolchain: 1.56.0 # MSRV
+ components: clippy
+ override: true
+ profile: minimal
+ - run: cargo clippy --all --all-features -- -D warnings
+
+ rustfmt:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout sources
+ uses: actions/checkout@v1
+
+ - name: Install stable toolchain
+ uses: actions-rs/toolchain@v1
+ with:
+ toolchain: stable
+ components: rustfmt
+ override: true
+ profile: minimal
+ - name: Run cargo fmt
+ uses: actions-rs/cargo@v1
+ with:
+ command: fmt
+ args: --all -- --check
+
+ benches:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v1
+ - uses: actions-rs/toolchain@v1
+ with:
+ toolchain: nightly
+ profile: minimal
+ override: true
+ - run: cargo build --all --benches
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..53ecea4
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,198 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "aes"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f6c3373fb58bb23c6ed0f191f915f0e9459c6929fc430c0d74b8237c521953a"
+dependencies = [
+ "cfg-if",
+ "cipher",
+ "cpufeatures",
+]
+
+[[package]]
+name = "blobby"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "847495c209977a90e8aad588b959d0ca9f5dc228096d29a6bd3defd53f35eaec"
+
+[[package]]
+name = "block-padding"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5808df4b2412175c4db3afb115c83d8d0cd26ca4f30a042026cddef8580e526a"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "cbc"
+version = "0.1.0"
+dependencies = [
+ "aes",
+ "cipher",
+ "hex-literal",
+]
+
+[[package]]
+name = "cfb-mode"
+version = "0.8.0"
+dependencies = [
+ "aes",
+ "cipher",
+ "hex-literal",
+]
+
+[[package]]
+name = "cfb8"
+version = "0.8.0"
+dependencies = [
+ "aes",
+ "cipher",
+ "hex-literal",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "cipher"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4f3e8c9be82c31c331bc9db0fd70a1068f8a288d980b2414dcaa25ab17ac1e0"
+dependencies = [
+ "blobby",
+ "crypto-common",
+ "inout",
+ "zeroize",
+]
+
+[[package]]
+name = "cpufeatures"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "crypto-common"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4600d695eb3f6ce1cd44e6e291adceb2cc3ab12f20a33777ecd0bf6eba34e06"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "ctr"
+version = "0.9.0"
+dependencies = [
+ "aes",
+ "cipher",
+ "hex-literal",
+ "kuznyechik",
+ "magma",
+]
+
+[[package]]
+name = "generic-array"
+version = "0.14.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803"
+dependencies = [
+ "typenum",
+ "version_check",
+]
+
+[[package]]
+name = "hex-literal"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0"
+
+[[package]]
+name = "ige"
+version = "0.1.0"
+dependencies = [
+ "aes",
+ "cipher",
+ "hex-literal",
+]
+
+[[package]]
+name = "inout"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1d8734d7f28aaff861d726dc3bc8003e2987d2fc26add21f5dab0c35d5c348a"
+dependencies = [
+ "block-padding",
+ "generic-array",
+]
+
+[[package]]
+name = "kuznyechik"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c6b8a760d5bebee051e542981fd2a562a6e8265c3262bfec1fd0ee3a0ea37f65"
+dependencies = [
+ "cipher",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.117"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e74d72e0f9b65b5b4ca49a346af3976df0f9c61d550727f349ecd559f251a26c"
+
+[[package]]
+name = "magma"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c6a003780e63ac83d9e21e3ee2ec69e9ca860b220ea97476bde316ad1a5bb071"
+dependencies = [
+ "cipher",
+]
+
+[[package]]
+name = "ofb"
+version = "0.6.0"
+dependencies = [
+ "aes",
+ "cipher",
+ "hex-literal",
+]
+
+[[package]]
+name = "pcbc"
+version = "0.1.0"
+dependencies = [
+ "aes",
+ "cipher",
+ "hex-literal",
+]
+
+[[package]]
+name = "typenum"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
+
+[[package]]
+name = "version_check"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+
+[[package]]
+name = "zeroize"
+version = "1.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c88870063c39ee00ec285a2f8d6a966e5b6fb2becc4e8dac77ed0d370ed6006"
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..e82a512
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,10 @@
+[workspace]
+members = [
+ "cbc",
+ "cfb8",
+ "cfb-mode",
+ "ctr",
+ "ige",
+ "ofb",
+ "pcbc",
+]
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..5a3e49d
--- /dev/null
+++ b/README.md
@@ -0,0 +1,81 @@
+# RustCrypto: block modes
+
+[![Project Chat][chat-image]][chat-link]
+[![dependency status][deps-image]][deps-link]
+![Apache2/MIT licensed][license-image]
+[![HAZMAT][hazmat-image]][hazmat-link]
+
+Collection of [block modes] written in pure Rust generic over
+block ciphers.
+
+## ⚠️ Security Warning: [Hazmat!][hazmat-link]
+
+Crates in this repository do not ensure ciphertexts are authentic
+(i.e. by using a MAC to verify ciphertext integrity), which can lead to
+serious vulnerabilities if used incorrectly!
+
+**USE AT YOUR OWN RISK!**
+
+## Supported algorithms
+
+| Name | Crate name | crates.io | Docs | MSRV |
+|------|------------|-----------|--------|------|
+| [Cipher Block Chaining][CBC] | [`cbc`] | [](https://crates.io/crates/cbc) | [](https://docs.rs/cbc) | ![MSRV 1.56][msrv-1.56] |
+| [8-bit Cipher Feedback][CFB-8] | [`cfb8`] | [](https://crates.io/crates/cfb8) | [](https://docs.rs/cfb8) | ![MSRV 1.56][msrv-1.56] |
+| [Full-block Cipher Feedback][CFB] | [`cfb-mode`] | [](https://crates.io/crates/cfb-mode) | [](https://docs.rs/cfb-mode) | ![MSRV 1.56][msrv-1.56] |
+| [Counter][CTR] | [`ctr`] | [](https://crates.io/crates/ctr) | [](https://docs.rs/ctr) | ![MSRV 1.56][msrv-1.56] |
+| [GOST R 34.13-2015] | [`gost-modes`] | [](https://crates.io/crates/gost-modes) | [](https://docs.rs/gost-modes) | ![MSRV 1.56][msrv-1.56] |
+| [Infinite Garble Extension][IGE] | [`ige`] | [](https://crates.io/crates/ige) | [](https://docs.rs/ige) | ![MSRV 1.56][msrv-1.56] |
+| [Output Feedback][OFB] | [`ofb`] | [](https://crates.io/crates/ofb) | [](https://docs.rs/ofb) | ![MSRV 1.56][msrv-1.56] |
+| [Propagating Cipher Block Chaining][PCBC] | [`pcbc`] | [](https://crates.io/crates/pcbc) | [](https://docs.rs/pcbc) | ![MSRV 1.56][msrv-1.56] |
+
+### Minimum Supported Rust Version (MSRV) Policy
+
+MSRV bumps are considered breaking changes and will be performed only with minor version bump.
+
+## License
+
+All crates licensed under either of
+
+ * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
+ * [MIT license](http://opensource.org/licenses/MIT)
+
+at your option.
+
+### Contribution
+
+Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
+
+[//]: # (badges)
+
+[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg
+[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/308460-block-modes
+[deps-image]: https://deps.rs/repo/github/RustCrypto/block-modes/status.svg
+[deps-link]: https://deps.rs/repo/github/RustCrypto/block-modes
+[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg
+[hazmat-image]: https://img.shields.io/badge/crypto-hazmat%E2%9A%A0-red.svg
+[hazmat-link]: https://github.com/RustCrypto/meta/blob/master/HAZMAT.md
+[msrv-1.56]: https://img.shields.io/badge/rustc-1.56.0+-blue.svg
+
+[//]: # (crates)
+
+[`cbc`]: ./cbc
+[`cfb8`]: ./cfb8
+[`cfb-mode`]: ./cfb-mode
+[`ctr`]: ./ctr
+[`gost-modes`]: ./gost-modes
+[`ige`]: ./ige
+[`ofb`]: ./ofb
+[`pcbc`]: ./pcbc
+
+[//]: # (links)
+
+[block modes]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation
+[CBC]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_block_chaining_(CBC)
+[CFB-8]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#CFB-1,_CFB-8,_CFB-64,_CFB-128,_etc.
+[CFB]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Full-block_CFB
+[CTR]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_(CTR)
+[GOST R 34.13-2015]: https://tc26.ru/standard/gost/GOST_R_3413-2015.pdf
+[IGE]: https://www.links.org/files/openssl-ige.pdf
+[OFB]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Output_feedback_(OFB)
+[PCBC]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Propagating_cipher_block_chaining_(PCBC)
diff --git a/cbc/CHANGELOG.md b/cbc/CHANGELOG.md
new file mode 100644
index 0000000..b6059ab
--- /dev/null
+++ b/cbc/CHANGELOG.md
@@ -0,0 +1,11 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## 0.1.0 (2022-02-10)
+- Initial release ([#2])
+
+[#2]: https://github.com/RustCrypto/block-modes/pull/2
diff --git a/cbc/Cargo.toml b/cbc/Cargo.toml
new file mode 100644
index 0000000..541af0e
--- /dev/null
+++ b/cbc/Cargo.toml
@@ -0,0 +1,30 @@
+[package]
+name = "cbc"
+version = "0.1.0" # Also update html_root_url in lib.rs when bumping this
+description = "Cipher Block Chaining (CBC) block cipher mode of operation"
+authors = ["RustCrypto Developers"]
+license = "MIT OR Apache-2.0"
+edition = "2021"
+rust-version = "1.56"
+readme = "README.md"
+documentation = "https://docs.rs/cbc"
+repository = "https://github.com/RustCrypto/block-modes"
+keywords = ["crypto", "block-mode", "ciphers"]
+categories = ["cryptography", "no-std"]
+
+[dependencies]
+cipher = "0.4"
+
+[dev-dependencies]
+aes = "0.8"
+cipher = { version = "0.4", features = ["dev"] }
+hex-literal = "0.3.3"
+
+[features]
+default = ["block-padding"]
+block-padding = ["cipher/block-padding"]
+zeroize = ["cipher/zeroize"]
+
+[package.metadata.docs.rs]
+all-features = true
+rustdoc-args = ["--cfg", "docsrs"]
diff --git a/cbc/LICENSE-APACHE b/cbc/LICENSE-APACHE
new file mode 100644
index 0000000..78173fa
--- /dev/null
+++ b/cbc/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/cbc/LICENSE-MIT b/cbc/LICENSE-MIT
new file mode 100644
index 0000000..d19d409
--- /dev/null
+++ b/cbc/LICENSE-MIT
@@ -0,0 +1,26 @@
+Copyright (c) 2018-2022 RustCrypto Developers
+Copyright (c) 2018 Artyom Pavlov
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/cbc/README.md b/cbc/README.md
new file mode 100644
index 0000000..f99efea
--- /dev/null
+++ b/cbc/README.md
@@ -0,0 +1,60 @@
+# RustCrypto: CBC
+
+[![crate][crate-image]][crate-link]
+[![Docs][docs-image]][docs-link]
+![Apache2/MIT licensed][license-image]
+![Rust Version][rustc-image]
+[![Project Chat][chat-image]][chat-link]
+[![Build Status][build-image]][build-link]
+
+Generic implementation of the [Cipher Block Chaining][CBC] (CBC) block cipher
+mode of operation.
+
+
+
+See [documentation][cipher-doc] of the `cipher` crate for additional information.
+
+## Minimum Supported Rust Version
+
+Rust **1.56** or higher.
+
+Minimum supported Rust version can be changed in the future, but it will be
+done with a minor version bump.
+
+## SemVer Policy
+
+- All on-by-default features of this library are covered by SemVer
+- MSRV is considered exempt from SemVer as noted above
+
+## License
+
+Licensed under either of:
+
+ * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
+ * [MIT license](http://opensource.org/licenses/MIT)
+
+at your option.
+
+### Contribution
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
+dual licensed as above, without any additional terms or conditions.
+
+[//]: # (badges)
+
+[crate-image]: https://img.shields.io/crates/v/cbc.svg
+[crate-link]: https://crates.io/crates/cbc
+[docs-image]: https://docs.rs/cbc/badge.svg
+[docs-link]: https://docs.rs/cbc/
+[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg
+[rustc-image]: https://img.shields.io/badge/rustc-1.56+-blue.svg
+[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg
+[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/308460-block-modes
+[build-image]: https://github.com/RustCrypto/block-modes/workflows/cbc/badge.svg?branch=master&event=push
+[build-link]: https://github.com/RustCrypto/block-modes/actions?query=workflow%3Acbc+branch%3Amaster
+
+[//]: # (general links)
+
+[CBC]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#CBC
+[cipher-doc]: https://docs.rs/cipher/
diff --git a/cbc/benches/aes128.rs b/cbc/benches/aes128.rs
new file mode 100644
index 0000000..b478146
--- /dev/null
+++ b/cbc/benches/aes128.rs
@@ -0,0 +1,16 @@
+#![feature(test)]
+extern crate test;
+
+use aes::Aes128;
+
+cipher::block_encryptor_bench!(
+ KeyIv: cbc::Encryptor,
+ cbc_aes128_encrypt_block,
+ cbc_aes128_encrypt_blocks,
+);
+
+cipher::block_decryptor_bench!(
+ KeyIv: cbc::Decryptor,
+ cbc_aes128_decrypt_block,
+ cbc_aes128_decrypt_blocks,
+);
diff --git a/cbc/src/decrypt.rs b/cbc/src/decrypt.rs
new file mode 100644
index 0000000..b3fe6a5
--- /dev/null
+++ b/cbc/src/decrypt.rs
@@ -0,0 +1,191 @@
+use crate::xor;
+use cipher::{
+ crypto_common::{InnerUser, IvSizeUser},
+ generic_array::{ArrayLength, GenericArray},
+ inout::InOut,
+ AlgorithmName, Block, BlockBackend, BlockCipher, BlockClosure, BlockDecryptMut, BlockSizeUser,
+ InnerIvInit, Iv, IvState, ParBlocks, ParBlocksSizeUser,
+};
+use core::fmt;
+
+#[cfg(feature = "zeroize")]
+use cipher::zeroize::{Zeroize, ZeroizeOnDrop};
+
+/// CBC mode decryptor.
+#[derive(Clone)]
+pub struct Decryptor
+where
+ C: BlockDecryptMut + BlockCipher,
+{
+ cipher: C,
+ iv: Block,
+}
+
+impl BlockSizeUser for Decryptor
+where
+ C: BlockDecryptMut + BlockCipher,
+{
+ type BlockSize = C::BlockSize;
+}
+
+impl BlockDecryptMut for Decryptor
+where
+ C: BlockDecryptMut + BlockCipher,
+{
+ fn decrypt_with_backend_mut(&mut self, f: impl BlockClosure) {
+ let Self { cipher, iv } = self;
+ cipher.decrypt_with_backend_mut(Closure { iv, f })
+ }
+}
+
+impl InnerUser for Decryptor
+where
+ C: BlockDecryptMut + BlockCipher,
+{
+ type Inner = C;
+}
+
+impl IvSizeUser for Decryptor
+where
+ C: BlockDecryptMut + BlockCipher,
+{
+ type IvSize = C::BlockSize;
+}
+
+impl InnerIvInit for Decryptor
+where
+ C: BlockDecryptMut + BlockCipher,
+{
+ #[inline]
+ fn inner_iv_init(cipher: C, iv: &Iv) -> Self {
+ Self {
+ cipher,
+ iv: iv.clone(),
+ }
+ }
+}
+
+impl IvState for Decryptor
+where
+ C: BlockDecryptMut + BlockCipher,
+{
+ #[inline]
+ fn iv_state(&self) -> Iv {
+ self.iv.clone()
+ }
+}
+
+impl AlgorithmName for Decryptor
+where
+ C: BlockDecryptMut + BlockCipher + AlgorithmName,
+{
+ fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("cbc::Decryptor<")?;
+ ::write_alg_name(f)?;
+ f.write_str(">")
+ }
+}
+
+impl fmt::Debug for Decryptor
+where
+ C: BlockDecryptMut + BlockCipher + AlgorithmName,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("cbc::Decryptor<")?;
+ ::write_alg_name(f)?;
+ f.write_str("> { ... }")
+ }
+}
+
+#[cfg(feature = "zeroize")]
+#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))]
+impl Drop for Decryptor {
+ fn drop(&mut self) {
+ self.iv.zeroize();
+ }
+}
+
+#[cfg(feature = "zeroize")]
+#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))]
+impl ZeroizeOnDrop for Decryptor {}
+
+struct Closure<'a, BS, BC>
+where
+ BS: ArrayLength,
+ BC: BlockClosure,
+{
+ iv: &'a mut GenericArray,
+ f: BC,
+}
+
+impl<'a, BS, BC> BlockSizeUser for Closure<'a, BS, BC>
+where
+ BS: ArrayLength,
+ BC: BlockClosure,
+{
+ type BlockSize = BS;
+}
+
+impl<'a, BS, BC> BlockClosure for Closure<'a, BS, BC>
+where
+ BS: ArrayLength,
+ BC: BlockClosure,
+{
+ #[inline(always)]
+ fn call>(self, backend: &mut B) {
+ let Self { iv, f } = self;
+ f.call(&mut Backend { iv, backend });
+ }
+}
+
+struct Backend<'a, BS, BK>
+where
+ BS: ArrayLength,
+ BK: BlockBackend,
+{
+ iv: &'a mut GenericArray,
+ backend: &'a mut BK,
+}
+
+impl<'a, BS, BK> BlockSizeUser for Backend<'a, BS, BK>
+where
+ BS: ArrayLength,
+ BK: BlockBackend,
+{
+ type BlockSize = BS;
+}
+
+impl<'a, BS, BK> ParBlocksSizeUser for Backend<'a, BS, BK>
+where
+ BS: ArrayLength,
+ BK: BlockBackend,
+{
+ type ParBlocksSize = BK::ParBlocksSize;
+}
+
+impl<'a, BS, BK> BlockBackend for Backend<'a, BS, BK>
+where
+ BS: ArrayLength,
+ BK: BlockBackend,
+{
+ #[inline(always)]
+ fn proc_block(&mut self, mut block: InOut<'_, '_, Block>) {
+ let enc_block = block.clone_in();
+ self.backend.proc_block(block.reborrow());
+ xor(block.get_out(), self.iv);
+ *self.iv = enc_block;
+ }
+
+ #[inline(always)]
+ fn proc_par_blocks(&mut self, mut blocks: InOut<'_, '_, ParBlocks>) {
+ let t = blocks.clone_in();
+ self.backend.proc_par_blocks(blocks.reborrow());
+ let out = blocks.get_out();
+ let n = out.len();
+ xor(&mut out[0], self.iv);
+ for i in 1..n {
+ xor(&mut out[i], &t[i - 1])
+ }
+ *self.iv = t[n - 1].clone();
+ }
+}
diff --git a/cbc/src/encrypt.rs b/cbc/src/encrypt.rs
new file mode 100644
index 0000000..cb19070
--- /dev/null
+++ b/cbc/src/encrypt.rs
@@ -0,0 +1,179 @@
+use crate::xor;
+use cipher::{
+ consts::U1,
+ crypto_common::{InnerUser, IvSizeUser},
+ generic_array::{ArrayLength, GenericArray},
+ inout::InOut,
+ AlgorithmName, Block, BlockBackend, BlockCipher, BlockClosure, BlockEncryptMut, BlockSizeUser,
+ InnerIvInit, Iv, IvState, ParBlocksSizeUser,
+};
+use core::fmt;
+
+#[cfg(feature = "zeroize")]
+use cipher::zeroize::{Zeroize, ZeroizeOnDrop};
+
+/// CBC mode encryptor.
+#[derive(Clone)]
+pub struct Encryptor
+where
+ C: BlockEncryptMut + BlockCipher,
+{
+ cipher: C,
+ iv: Block,
+}
+
+impl BlockSizeUser for Encryptor
+where
+ C: BlockEncryptMut + BlockCipher,
+{
+ type BlockSize = C::BlockSize;
+}
+
+impl BlockEncryptMut for Encryptor
+where
+ C: BlockEncryptMut + BlockCipher,
+{
+ fn encrypt_with_backend_mut(&mut self, f: impl BlockClosure) {
+ let Self { cipher, iv } = self;
+ cipher.encrypt_with_backend_mut(Closure { iv, f })
+ }
+}
+
+impl InnerUser for Encryptor
+where
+ C: BlockEncryptMut + BlockCipher,
+{
+ type Inner = C;
+}
+
+impl IvSizeUser for Encryptor
+where
+ C: BlockEncryptMut + BlockCipher,
+{
+ type IvSize = C::BlockSize;
+}
+
+impl InnerIvInit for Encryptor
+where
+ C: BlockEncryptMut + BlockCipher,
+{
+ #[inline]
+ fn inner_iv_init(cipher: C, iv: &Iv) -> Self {
+ Self {
+ cipher,
+ iv: iv.clone(),
+ }
+ }
+}
+
+impl IvState for Encryptor
+where
+ C: BlockEncryptMut + BlockCipher,
+{
+ #[inline]
+ fn iv_state(&self) -> Iv {
+ self.iv.clone()
+ }
+}
+
+impl AlgorithmName for Encryptor
+where
+ C: BlockEncryptMut + BlockCipher + AlgorithmName,
+{
+ fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("cbc::Encryptor<")?;
+ ::write_alg_name(f)?;
+ f.write_str(">")
+ }
+}
+
+impl fmt::Debug for Encryptor
+where
+ C: BlockEncryptMut + BlockCipher + AlgorithmName,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("cbc::Encryptor<")?;
+ ::write_alg_name(f)?;
+ f.write_str("> { ... }")
+ }
+}
+
+#[cfg(feature = "zeroize")]
+#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))]
+impl Drop for Encryptor {
+ fn drop(&mut self) {
+ self.iv.zeroize();
+ }
+}
+
+#[cfg(feature = "zeroize")]
+#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))]
+impl ZeroizeOnDrop for Encryptor {}
+
+struct Closure<'a, BS, BC>
+where
+ BS: ArrayLength,
+ BC: BlockClosure,
+{
+ iv: &'a mut GenericArray,
+ f: BC,
+}
+
+impl<'a, BS, BC> BlockSizeUser for Closure<'a, BS, BC>
+where
+ BS: ArrayLength,
+ BC: BlockClosure,
+{
+ type BlockSize = BS;
+}
+
+impl<'a, BS, BC> BlockClosure for Closure<'a, BS, BC>
+where
+ BS: ArrayLength,
+ BC: BlockClosure,
+{
+ #[inline(always)]
+ fn call>(self, backend: &mut B) {
+ let Self { iv, f } = self;
+ f.call(&mut Backend { iv, backend });
+ }
+}
+
+struct Backend<'a, BS, BK>
+where
+ BS: ArrayLength,
+ BK: BlockBackend,
+{
+ iv: &'a mut GenericArray,
+ backend: &'a mut BK,
+}
+
+impl<'a, BS, BK> BlockSizeUser for Backend<'a, BS, BK>
+where
+ BS: ArrayLength,
+ BK: BlockBackend,
+{
+ type BlockSize = BS;
+}
+
+impl<'a, BS, BK> ParBlocksSizeUser for Backend<'a, BS, BK>
+where
+ BS: ArrayLength,
+ BK: BlockBackend,
+{
+ type ParBlocksSize = U1;
+}
+
+impl<'a, BS, BK> BlockBackend for Backend<'a, BS, BK>
+where
+ BS: ArrayLength,
+ BK: BlockBackend,
+{
+ #[inline(always)]
+ fn proc_block(&mut self, mut block: InOut<'_, '_, Block>) {
+ let mut t = block.clone_in();
+ xor(&mut t, self.iv);
+ self.backend.proc_block((&t, block.get_out()).into());
+ *self.iv = block.get_out().clone();
+ }
+}
diff --git a/cbc/src/lib.rs b/cbc/src/lib.rs
new file mode 100644
index 0000000..4929ad0
--- /dev/null
+++ b/cbc/src/lib.rs
@@ -0,0 +1,85 @@
+//! [Cipher Block Chaining][1] (CBC) mode.
+//!
+//!
+//!
+//!
+//! Mode functionality is accessed using traits from re-exported [`cipher`] crate.
+//!
+//! # ⚠️ Security Warning: Hazmat!
+//!
+//! This crate does not ensure ciphertexts are authentic! Thus ciphertext integrity
+//! is not verified, which can lead to serious vulnerabilities!
+//!
+//! # Example
+//! ```
+//! use aes::cipher::{block_padding::Pkcs7, BlockDecryptMut, BlockEncryptMut, KeyIvInit};
+//! use hex_literal::hex;
+//!
+//! type Aes128CbcEnc = cbc::Encryptor;
+//! type Aes128CbcDec = cbc::Decryptor;
+//!
+//! let key = [0x42; 16];
+//! let iv = [0x24; 16];
+//! let plaintext = b"hello world! this is my plaintext.";
+//! let ciphertext = hex!(
+//! "c7fe247ef97b21f07cbdd26cb5d346bf"
+//! "d27867cb00d9486723e159978fb9a5f9"
+//! "14cfb228a710de4171e396e7b6cf859e"
+//! );
+//!
+//! // encrypt/decrypt in-place
+//! // buffer must be big enough for padded plaintext
+//! let mut buf = vec![0u8; 48];
+//! let pt_len = plaintext.len();
+//! buf[..pt_len].copy_from_slice(&plaintext[..]);
+//! let ct = Aes128CbcEnc::new(&key.into(), &iv.into())
+//! .encrypt_padded_mut::(&mut buf, pt_len)
+//! .unwrap();
+//! assert_eq!(ct, &ciphertext[..]);
+//!
+//! let pt = Aes128CbcDec::new(&key.into(), &iv.into())
+//! .decrypt_padded_mut::(&mut buf)
+//! .unwrap();
+//! assert_eq!(pt, &plaintext[..]);
+//!
+//! // encrypt/decrypt from buffer to buffer
+//! let mut buf = vec![0u8; 48];
+//! let ct = Aes128CbcEnc::new(&key.into(), &iv.into())
+//! .encrypt_padded_b2b_mut::(&plaintext[..], &mut buf)
+//! .unwrap();
+//! assert_eq!(ct, &ciphertext[..]);
+//!
+//! let mut buf = vec![0u8; 48];
+//! let pt = Aes128CbcDec::new(&key.into(), &iv.into())
+//! .decrypt_padded_b2b_mut::(&ct, &mut buf)
+//! .unwrap();
+//! assert_eq!(pt, &plaintext[..]);
+//! ```
+//!
+//! [1]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#CBC
+
+#![no_std]
+#![doc(
+ html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg",
+ html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg",
+ html_root_url = "https://docs.rs/cbc/0.1.0"
+)]
+#![forbid(unsafe_code)]
+#![cfg_attr(docsrs, feature(doc_cfg))]
+#![warn(missing_docs, rust_2018_idioms)]
+
+mod decrypt;
+mod encrypt;
+
+pub use cipher;
+pub use decrypt::Decryptor;
+pub use encrypt::Encryptor;
+
+use cipher::generic_array::{ArrayLength, GenericArray};
+
+#[inline(always)]
+fn xor>(out: &mut GenericArray, buf: &GenericArray) {
+ for (a, b) in out.iter_mut().zip(buf) {
+ *a ^= *b;
+ }
+}
diff --git a/cbc/tests/aes.rs b/cbc/tests/aes.rs
new file mode 100644
index 0000000..5513bf1
--- /dev/null
+++ b/cbc/tests/aes.rs
@@ -0,0 +1,25 @@
+use aes::*;
+use cbc::{Decryptor, Encryptor};
+use cipher::{block_mode_dec_test, block_mode_enc_test, iv_state_test};
+
+iv_state_test!(aes128_cbc_enc_iv_state, Encryptor, encrypt);
+iv_state_test!(aes128_cbc_dec_iv_state, Decryptor, decrypt);
+iv_state_test!(aes192_cbc_enc_iv_state, Encryptor, encrypt);
+iv_state_test!(aes192_cbc_dec_iv_state, Decryptor, decrypt);
+iv_state_test!(aes256_cbc_enc_iv_state, Encryptor, encrypt);
+iv_state_test!(aes256_cbc_dec_iv_state, Decryptor, decrypt);
+
+// Test vectors from CVAP "AES Multiblock Message Test (MMT) Sample Vectors":
+//
+block_mode_enc_test!(aes128_cbc_enc_test, "aes128", Encryptor);
+block_mode_dec_test!(aes128_cbc_dec_test, "aes128", Decryptor);
+block_mode_enc_test!(aes128enc_cbc_enc_test, "aes128", Encryptor);
+block_mode_dec_test!(aes128dec_cbc_dec_test, "aes128", Decryptor);
+block_mode_enc_test!(aes192_cbc_enc_test, "aes192", Encryptor);
+block_mode_dec_test!(aes192_cbc_dec_test, "aes192", Decryptor);
+block_mode_enc_test!(aes192enc_cbc_enc_test, "aes192", Encryptor);
+block_mode_dec_test!(aes192dec_cbc_dec_test, "aes192", Decryptor);
+block_mode_enc_test!(aes256_cbc_enc_test, "aes256", Encryptor);
+block_mode_dec_test!(aes256_cbc_dec_test, "aes256", Decryptor);
+block_mode_enc_test!(aes256enc_cbc_enc_test, "aes256", Encryptor);
+block_mode_dec_test!(aes256dec_cbc_dec_test, "aes256", Decryptor);
diff --git a/cbc/tests/data/aes128.blb b/cbc/tests/data/aes128.blb
new file mode 100644
index 0000000..b74b505
Binary files /dev/null and b/cbc/tests/data/aes128.blb differ
diff --git a/cbc/tests/data/aes192.blb b/cbc/tests/data/aes192.blb
new file mode 100644
index 0000000..f2fccb1
Binary files /dev/null and b/cbc/tests/data/aes192.blb differ
diff --git a/cbc/tests/data/aes256.blb b/cbc/tests/data/aes256.blb
new file mode 100644
index 0000000..c4a7002
Binary files /dev/null and b/cbc/tests/data/aes256.blb differ
diff --git a/cfb-mode/CHANGELOG.md b/cfb-mode/CHANGELOG.md
new file mode 100644
index 0000000..2d49421
--- /dev/null
+++ b/cfb-mode/CHANGELOG.md
@@ -0,0 +1,58 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## 0.8.0 (2022-02-10)
+### Changed
+- Update `cipher` dependency to v0.4 and move crate
+to the [RustCrypto/block-modes] repository ([#2])
+
+[#2]: https://github.com/RustCrypto/block-modes/pull/2
+[RustCrypto/block-modes]: https://github.com/RustCrypto/block-modes
+
+## 0.7.1 (2021-04-30)
+### Changed
+- Removed redundant `NewBlockCipher` bound from `FromBlockCipher` implementation ([#236])
+
+[#236]: https://github.com/RustCrypto/stream-ciphers/pull/236
+
+## 0.7.0 (2021-04-29)
+### Changed
+- Bump `cipher` dependency to v0.3 release ([#226])
+- Bump `aes` dev dependency to v0.7 release ([#232])
+
+[#226]: https://github.com/RustCrypto/stream-ciphers/pull/226
+[#232]: https://github.com/RustCrypto/stream-ciphers/pull/232
+
+## 0.6.0 (2020-10-16)
+### Changed
+- Replace `block-cipher`/`stream-cipher` with `cipher` crate ([#177])
+
+[#177]: https://github.com/RustCrypto/stream-ciphers/pull/177
+
+## 0.5.0 (2020-08-25)
+### Changed
+- Bump `stream-cipher` dependency to v0.7, implement the `FromBlockCipher` trait ([#161], [#164])
+
+[#161]: https://github.com/RustCrypto/stream-ciphers/pull/161
+[#164]: https://github.com/RustCrypto/stream-ciphers/pull/164
+
+## 0.4.0 (2020-06-08)
+### Changed
+- Bump `stream-cipher` dependency to v0.4 ([#119])
+- Upgrade to Rust 2018 edition ([#119])
+
+[#119]: https://github.com/RustCrypto/stream-ciphers/pull/119
+
+## 0.3.2 (2019-03-11)
+
+## 0.3.1 (2018-11-01)
+
+## 0.3.0 (2018-11-01)
+
+## 0.2.0 (2018-10-13)
+
+## 0.1.0 (2018-10-01)
diff --git a/cfb-mode/Cargo.toml b/cfb-mode/Cargo.toml
new file mode 100644
index 0000000..90f773a
--- /dev/null
+++ b/cfb-mode/Cargo.toml
@@ -0,0 +1,29 @@
+[package]
+name = "cfb-mode"
+version = "0.8.0" # Also update html_root_url in lib.rs when bumping this
+description = "Cipher Feedback (CFB) block cipher mode of operation"
+authors = ["RustCrypto Developers"]
+license = "MIT OR Apache-2.0"
+edition = "2021"
+rust-version = "1.56"
+readme = "README.md"
+documentation = "https://docs.rs/cfb-mode"
+repository = "https://github.com/RustCrypto/block-modes"
+keywords = ["crypto", "block-mode", "stream-cipher", "ciphers"]
+categories = ["cryptography", "no-std"]
+
+[dependencies]
+cipher = "0.4"
+
+[dev-dependencies]
+aes = "0.8"
+cipher = { version = "0.4", features = ["dev"] }
+hex-literal = "0.3"
+
+[features]
+block-padding = ["cipher/block-padding"]
+zeroize = ["cipher/zeroize"]
+
+[package.metadata.docs.rs]
+all-features = true
+rustdoc-args = ["--cfg", "docsrs"]
diff --git a/cfb-mode/LICENSE-APACHE b/cfb-mode/LICENSE-APACHE
new file mode 100644
index 0000000..78173fa
--- /dev/null
+++ b/cfb-mode/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/cfb-mode/LICENSE-MIT b/cfb-mode/LICENSE-MIT
new file mode 100644
index 0000000..d19d409
--- /dev/null
+++ b/cfb-mode/LICENSE-MIT
@@ -0,0 +1,26 @@
+Copyright (c) 2018-2022 RustCrypto Developers
+Copyright (c) 2018 Artyom Pavlov
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/cfb-mode/README.md b/cfb-mode/README.md
new file mode 100644
index 0000000..4015f24
--- /dev/null
+++ b/cfb-mode/README.md
@@ -0,0 +1,60 @@
+# RustCrypto: CFB
+
+[![crate][crate-image]][crate-link]
+[![Docs][docs-image]][docs-link]
+![Apache2/MIT licensed][license-image]
+![Rust Version][rustc-image]
+[![Project Chat][chat-image]][chat-link]
+[![Build Status][build-image]][build-link]
+
+Generic implementation of the [Cipher Feedback][CFB] (CFB) block cipher mode
+of operation.
+
+
+
+See [documentation][cipher-doc] of the `cipher` crate for additional information.
+
+## Minimum Supported Rust Version
+
+Rust **1.56** or higher.
+
+Minimum supported Rust version can be changed in the future, but it will be
+done with a minor version bump.
+
+## SemVer Policy
+
+- All on-by-default features of this library are covered by SemVer
+- MSRV is considered exempt from SemVer as noted above
+
+## License
+
+Licensed under either of:
+
+ * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
+ * [MIT license](http://opensource.org/licenses/MIT)
+
+at your option.
+
+### Contribution
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
+dual licensed as above, without any additional terms or conditions.
+
+[//]: # (badges)
+
+[crate-image]: https://img.shields.io/crates/v/cfb-mode.svg
+[crate-link]: https://crates.io/crates/cfb-mode
+[docs-image]: https://docs.rs/cfb-mode/badge.svg
+[docs-link]: https://docs.rs/cfb-mode/
+[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg
+[rustc-image]: https://img.shields.io/badge/rustc-1.56+-blue.svg
+[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg
+[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/308460-block-modes
+[build-image]: https://github.com/RustCrypto/block-modes/workflows/cfb-mode/badge.svg?branch=master&event=push
+[build-link]: https://github.com/RustCrypto/block-modes/actions?query=workflow%3Acfb-mode+branch%3Amaster
+
+[//]: # (general links)
+
+[CFB]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_feedback_(CFB)
+[cipher-doc]: https://docs.rs/cipher/
diff --git a/cfb-mode/benches/aes128.rs b/cfb-mode/benches/aes128.rs
new file mode 100644
index 0000000..1d5c9df
--- /dev/null
+++ b/cfb-mode/benches/aes128.rs
@@ -0,0 +1,16 @@
+#![feature(test)]
+extern crate test;
+
+use aes::Aes128;
+
+cipher::block_encryptor_bench!(
+ KeyIv: cfb_mode::Encryptor,
+ cfb_aes128_encrypt_block,
+ cfb_aes128_encrypt_blocks,
+);
+
+cipher::block_decryptor_bench!(
+ KeyIv: cfb_mode::Decryptor,
+ cfb_aes128_decrypt_block,
+ cfb_aes128_decrypt_blocks,
+);
diff --git a/cfb-mode/src/decrypt.rs b/cfb-mode/src/decrypt.rs
new file mode 100644
index 0000000..b188a89
--- /dev/null
+++ b/cfb-mode/src/decrypt.rs
@@ -0,0 +1,195 @@
+use cipher::{
+ crypto_common::{InnerUser, IvSizeUser},
+ generic_array::{ArrayLength, GenericArray},
+ inout::InOut,
+ AlgorithmName, AsyncStreamCipher, Block, BlockBackend, BlockCipher, BlockClosure, BlockDecrypt,
+ BlockDecryptMut, BlockEncryptMut, BlockSizeUser, InnerIvInit, Iv, IvState, ParBlocks,
+ ParBlocksSizeUser,
+};
+use core::fmt;
+
+#[cfg(feature = "zeroize")]
+use cipher::zeroize::{Zeroize, ZeroizeOnDrop};
+
+/// CFB mode decryptor.
+#[derive(Clone)]
+pub struct Decryptor
+where
+ C: BlockEncryptMut + BlockCipher,
+{
+ cipher: C,
+ iv: Block,
+}
+
+impl BlockSizeUser for Decryptor
+where
+ C: BlockEncryptMut + BlockCipher,
+{
+ type BlockSize = C::BlockSize;
+}
+
+impl BlockDecryptMut for Decryptor
+where
+ C: BlockEncryptMut + BlockCipher,
+{
+ fn decrypt_with_backend_mut(&mut self, f: impl BlockClosure) {
+ let Self { cipher, iv } = self;
+ cipher.encrypt_with_backend_mut(Closure { iv, f })
+ }
+}
+
+impl AsyncStreamCipher for Decryptor where C: BlockEncryptMut + BlockCipher {}
+
+impl InnerUser for Decryptor
+where
+ C: BlockEncryptMut + BlockCipher,
+{
+ type Inner = C;
+}
+
+impl IvSizeUser for Decryptor
+where
+ C: BlockEncryptMut + BlockCipher,
+{
+ type IvSize = C::BlockSize;
+}
+
+impl InnerIvInit for Decryptor
+where
+ C: BlockEncryptMut + BlockCipher,
+{
+ #[inline]
+ fn inner_iv_init(mut cipher: C, iv: &Iv) -> Self {
+ let mut iv = iv.clone();
+ cipher.encrypt_block_mut(&mut iv);
+ Self { cipher, iv }
+ }
+}
+
+impl IvState for Decryptor
+where
+ C: BlockEncryptMut + BlockDecrypt + BlockCipher,
+{
+ #[inline]
+ fn iv_state(&self) -> Iv {
+ let mut res = self.iv.clone();
+ self.cipher.decrypt_block(&mut res);
+ res
+ }
+}
+
+impl AlgorithmName for Decryptor
+where
+ C: BlockEncryptMut + BlockCipher + AlgorithmName,
+{
+ fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("cfb::Decryptor<")?;
+ ::write_alg_name(f)?;
+ f.write_str(">")
+ }
+}
+
+impl fmt::Debug for Decryptor
+where
+ C: BlockEncryptMut + BlockCipher + AlgorithmName,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("cfb::Decryptor<")?;
+ ::write_alg_name(f)?;
+ f.write_str("> { ... }")
+ }
+}
+
+#[cfg(feature = "zeroize")]
+#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))]
+impl Drop for Decryptor {
+ fn drop(&mut self) {
+ self.iv.zeroize();
+ }
+}
+
+#[cfg(feature = "zeroize")]
+#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))]
+impl ZeroizeOnDrop for Decryptor {}
+
+struct Closure<'a, BS, BC>
+where
+ BS: ArrayLength,
+ BC: BlockClosure,
+{
+ iv: &'a mut GenericArray,
+ f: BC,
+}
+
+impl<'a, BS, BC> BlockSizeUser for Closure<'a, BS, BC>
+where
+ BS: ArrayLength,
+ BC: BlockClosure,
+{
+ type BlockSize = BS;
+}
+
+impl<'a, BS, BC> BlockClosure for Closure<'a, BS, BC>
+where
+ BS: ArrayLength,
+ BC: BlockClosure,
+{
+ #[inline(always)]
+ fn call>(self, backend: &mut B) {
+ let Self { iv, f } = self;
+ f.call(&mut Backend { iv, backend });
+ }
+}
+
+struct Backend<'a, BS, BK>
+where
+ BS: ArrayLength,
+ BK: BlockBackend,
+{
+ iv: &'a mut GenericArray,
+ backend: &'a mut BK,
+}
+
+impl<'a, BS, BK> BlockSizeUser for Backend<'a, BS, BK>
+where
+ BS: ArrayLength,
+ BK: BlockBackend,
+{
+ type BlockSize = BS;
+}
+
+impl<'a, BS, BK> ParBlocksSizeUser for Backend<'a, BS, BK>
+where
+ BS: ArrayLength,
+ BK: BlockBackend,
+{
+ type ParBlocksSize = BK::ParBlocksSize;
+}
+
+impl<'a, BS, BK> BlockBackend for Backend<'a, BS, BK>
+where
+ BS: ArrayLength,
+ BK: BlockBackend,
+{
+ #[inline(always)]
+ fn proc_block(&mut self, mut block: InOut<'_, '_, Block>) {
+ let mut t = block.clone_in();
+ block.xor_in2out(self.iv);
+ self.backend.proc_block((&mut t).into());
+ *self.iv = t;
+ }
+
+ #[inline(always)]
+ fn proc_par_blocks(&mut self, mut blocks: InOut<'_, '_, ParBlocks>) {
+ let mut t = ParBlocks::::default();
+ let b = (blocks.get_in(), &mut t).into();
+ self.backend.proc_par_blocks(b);
+
+ let n = t.len();
+ blocks.get(0).xor_in2out(self.iv);
+ for i in 1..n {
+ blocks.get(i).xor_in2out(&t[i - 1])
+ }
+ *self.iv = t[n - 1].clone();
+ }
+}
diff --git a/cfb-mode/src/encrypt.rs b/cfb-mode/src/encrypt.rs
new file mode 100644
index 0000000..42a7fd6
--- /dev/null
+++ b/cfb-mode/src/encrypt.rs
@@ -0,0 +1,181 @@
+use cipher::{
+ consts::U1,
+ crypto_common::{InnerUser, IvSizeUser},
+ generic_array::{ArrayLength, GenericArray},
+ inout::InOut,
+ AlgorithmName, AsyncStreamCipher, Block, BlockBackend, BlockCipher, BlockClosure, BlockDecrypt,
+ BlockEncryptMut, BlockSizeUser, InnerIvInit, Iv, IvState, ParBlocksSizeUser,
+};
+use core::fmt;
+
+#[cfg(feature = "zeroize")]
+use cipher::zeroize::{Zeroize, ZeroizeOnDrop};
+
+/// CFB mode encryptor.
+#[derive(Clone)]
+pub struct Encryptor
+where
+ C: BlockEncryptMut + BlockCipher,
+{
+ cipher: C,
+ iv: Block,
+}
+
+impl BlockSizeUser for Encryptor
+where
+ C: BlockEncryptMut + BlockCipher,
+{
+ type BlockSize = C::BlockSize;
+}
+
+impl BlockEncryptMut for Encryptor
+where
+ C: BlockEncryptMut + BlockCipher,
+{
+ fn encrypt_with_backend_mut(&mut self, f: impl BlockClosure) {
+ let Self { cipher, iv } = self;
+ cipher.encrypt_with_backend_mut(Closure { iv, f })
+ }
+}
+
+impl AsyncStreamCipher for Encryptor where C: BlockEncryptMut + BlockCipher {}
+
+impl InnerUser for Encryptor
+where
+ C: BlockEncryptMut + BlockCipher,
+{
+ type Inner = C;
+}
+
+impl IvSizeUser for Encryptor
+where
+ C: BlockEncryptMut + BlockCipher,
+{
+ type IvSize = C::BlockSize;
+}
+
+impl InnerIvInit for Encryptor
+where
+ C: BlockEncryptMut + BlockCipher,
+{
+ #[inline]
+ fn inner_iv_init(mut cipher: C, iv: &Iv) -> Self {
+ let mut iv = iv.clone();
+ cipher.encrypt_block_mut(&mut iv);
+ Self { cipher, iv }
+ }
+}
+
+impl IvState for Encryptor
+where
+ C: BlockEncryptMut + BlockDecrypt + BlockCipher,
+{
+ #[inline]
+ fn iv_state(&self) -> Iv {
+ let mut res = self.iv.clone();
+ self.cipher.decrypt_block(&mut res);
+ res
+ }
+}
+
+impl AlgorithmName for Encryptor
+where
+ C: BlockEncryptMut + BlockCipher + AlgorithmName,
+{
+ fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("cfb::Encryptor<")?;
+ ::write_alg_name(f)?;
+ f.write_str(">")
+ }
+}
+
+impl fmt::Debug for Encryptor
+where
+ C: BlockEncryptMut + BlockCipher + AlgorithmName,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("cfb::Encryptor<")?;
+ ::write_alg_name(f)?;
+ f.write_str("> { ... }")
+ }
+}
+
+#[cfg(feature = "zeroize")]
+#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))]
+impl Drop for Encryptor {
+ fn drop(&mut self) {
+ self.iv.zeroize();
+ }
+}
+
+#[cfg(feature = "zeroize")]
+#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))]
+impl ZeroizeOnDrop for Encryptor {}
+
+struct Closure<'a, BS, BC>
+where
+ BS: ArrayLength,
+ BC: BlockClosure,
+{
+ iv: &'a mut GenericArray,
+ f: BC,
+}
+
+impl<'a, BS, BC> BlockSizeUser for Closure<'a, BS, BC>
+where
+ BS: ArrayLength,
+ BC: BlockClosure,
+{
+ type BlockSize = BS;
+}
+
+impl<'a, BS, BC> BlockClosure for Closure<'a, BS, BC>
+where
+ BS: ArrayLength,
+ BC: BlockClosure,
+{
+ #[inline(always)]
+ fn call>(self, backend: &mut B) {
+ let Self { iv, f } = self;
+ f.call(&mut Backend { iv, backend });
+ }
+}
+
+struct Backend<'a, BS, BK>
+where
+ BS: ArrayLength,
+ BK: BlockBackend,
+{
+ iv: &'a mut GenericArray,
+ backend: &'a mut BK,
+}
+
+impl<'a, BS, BK> BlockSizeUser for Backend<'a, BS, BK>
+where
+ BS: ArrayLength,
+ BK: BlockBackend,
+{
+ type BlockSize = BS;
+}
+
+impl<'a, BS, BK> ParBlocksSizeUser for Backend<'a, BS, BK>
+where
+ BS: ArrayLength,
+ BK: BlockBackend,
+{
+ type ParBlocksSize = U1;
+}
+
+impl<'a, BS, BK> BlockBackend for Backend<'a, BS, BK>
+where
+ BS: ArrayLength,
+ BK: BlockBackend,
+{
+ #[inline(always)]
+ fn proc_block(&mut self, mut block: InOut<'_, '_, Block>) {
+ block.xor_in2out(self.iv);
+ let mut t = block.get_out().clone();
+ self.backend.proc_block((&mut t).into());
+ *self.iv = t;
+ }
+}
diff --git a/cfb-mode/src/lib.rs b/cfb-mode/src/lib.rs
new file mode 100644
index 0000000..de7cabc
--- /dev/null
+++ b/cfb-mode/src/lib.rs
@@ -0,0 +1,68 @@
+//! [Cipher feedback][1] (CFB) mode with full block feedback.
+//!
+//!
+//!
+//!
+//! Mode functionality is accessed using traits from re-exported [`cipher`] crate.
+//!
+//! # ⚠️ Security Warning: Hazmat!
+//!
+//! This crate does not ensure ciphertexts are authentic! Thus ciphertext integrity
+//! is not verified, which can lead to serious vulnerabilities!
+//!
+//! # Example
+//! ```
+//! use aes::cipher::{AsyncStreamCipher, KeyIvInit};
+//! use hex_literal::hex;
+//!
+//! type Aes128CfbEnc = cfb_mode::Encryptor;
+//! type Aes128CfbDec = cfb_mode::Decryptor;
+//!
+//! let key = [0x42; 16];
+//! let iv = [0x24; 16];
+//! let plaintext = b"hello world! this is my plaintext.";
+//! let ciphertext = hex!(
+//! "3357121ebb5a29468bd861467596ce3d6f99e251cc2d9f0a598032ae386d0ab995b3"
+//! );
+//!
+//! // encrypt/decrypt in-place
+//! let mut buf = plaintext.to_vec();
+//! Aes128CfbEnc::new(&key.into(), &iv.into()).encrypt(&mut buf);
+//! assert_eq!(buf, &ciphertext[..]);
+//!
+//! Aes128CfbDec::new(&key.into(), &iv.into()).decrypt(&mut buf);
+//! assert_eq!(buf, &plaintext[..]);
+//!
+//! // encrypt/decrypt from buffer to buffer
+//! // buffer length must be equal to input length
+//! let mut buf1 = vec![0u8; 34];
+//! Aes128CfbEnc::new(&key.into(), &iv.into())
+//! .encrypt_b2b(&plaintext[..], &mut buf1)
+//! .unwrap();
+//! assert_eq!(buf1, &ciphertext[..]);
+//!
+//! let mut buf2 = vec![0u8; 34];
+//! Aes128CfbDec::new(&key.into(), &iv.into())
+//! .decrypt_b2b(&buf1, &mut buf2)
+//! .unwrap();
+//! assert_eq!(buf2, &plaintext[..]);
+//! ```
+//!
+//! [1]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_feedback_(CFB)
+
+#![no_std]
+#![doc(
+ html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg",
+ html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg",
+ html_root_url = "https://docs.rs/cfb-mode/0.8.0"
+)]
+#![forbid(unsafe_code)]
+#![cfg_attr(docsrs, feature(doc_cfg))]
+#![warn(missing_docs, rust_2018_idioms)]
+
+mod decrypt;
+mod encrypt;
+
+pub use cipher;
+pub use decrypt::Decryptor;
+pub use encrypt::Encryptor;
diff --git a/cfb-mode/tests/aes.rs b/cfb-mode/tests/aes.rs
new file mode 100644
index 0000000..2f8bf98
--- /dev/null
+++ b/cfb-mode/tests/aes.rs
@@ -0,0 +1,55 @@
+use aes::*;
+use cfb_mode::{Decryptor, Encryptor};
+use cipher::{block_mode_dec_test, block_mode_enc_test, iv_state_test};
+
+iv_state_test!(aes128_cfb_enc_iv_state, Encryptor, encrypt);
+iv_state_test!(aes128_cfb_dec_iv_state, Decryptor, decrypt);
+iv_state_test!(aes192_cfb_enc_iv_state, Encryptor, encrypt);
+iv_state_test!(aes192_cfb_dec_iv_state, Decryptor, decrypt);
+iv_state_test!(aes256_cfb_enc_iv_state, Encryptor, encrypt);
+iv_state_test!(aes256_cfb_dec_iv_state, Decryptor, decrypt);
+
+// Test vectors from CVAP "AES Multiblock Message Test (MMT) Sample Vectors":
+//
+block_mode_enc_test!(aes128_cfb_enc_test, "aes128", Encryptor);
+block_mode_dec_test!(aes128_cfb_dec_test, "aes128", Decryptor);
+block_mode_enc_test!(aes128enc_cfb_enc_test, "aes128", Encryptor);
+block_mode_dec_test!(aes128enc_cfb_dec_test, "aes128", Decryptor);
+block_mode_enc_test!(aes192_cfb_enc_test, "aes192", Encryptor);
+block_mode_dec_test!(aes192_cfb_dec_test, "aes192", Decryptor);
+block_mode_enc_test!(aes192enc_cfb_enc_test, "aes192", Encryptor);
+block_mode_dec_test!(aes192dec_cfb_dec_test, "aes192", Decryptor);
+block_mode_enc_test!(aes256_cfb_enc_test, "aes256", Encryptor);
+block_mode_dec_test!(aes256_cfb_dec_test, "aes256", Decryptor);
+block_mode_enc_test!(aes256enc_cfb_enc_test, "aes256", Encryptor);
+block_mode_dec_test!(aes256dec_cfb_dec_test, "aes256", Decryptor);
+
+/// Test methods from the `AsyncStreamCipher` trait.
+#[test]
+fn aes128_cfb_async_test() {
+ use cipher::{AsyncStreamCipher, KeyIvInit};
+
+ type Enc = Encryptor;
+ type Dec = Decryptor;
+
+ let key = [42; 16];
+ let iv = [24; 16];
+ let mut pt = [0u8; 101];
+ for (i, b) in pt.iter_mut().enumerate() {
+ *b = (i % 11) as u8;
+ }
+ let enc = Enc::new_from_slices(&key, &iv).unwrap();
+ let mut ct = pt.clone();
+ enc.encrypt(&mut ct);
+ for i in 1..100 {
+ let enc = Enc::new_from_slices(&key, &iv).unwrap();
+ let mut t = pt.clone();
+ let t = &mut t[..i];
+ enc.encrypt(t);
+ assert_eq!(t, &ct[..i]);
+
+ let dec = Dec::new_from_slices(&key, &iv).unwrap();
+ dec.decrypt(t);
+ assert_eq!(t, &pt[..i]);
+ }
+}
diff --git a/cfb-mode/tests/data/aes128.blb b/cfb-mode/tests/data/aes128.blb
new file mode 100644
index 0000000..6e2c0c1
Binary files /dev/null and b/cfb-mode/tests/data/aes128.blb differ
diff --git a/cfb-mode/tests/data/aes192.blb b/cfb-mode/tests/data/aes192.blb
new file mode 100644
index 0000000..d3267a1
Binary files /dev/null and b/cfb-mode/tests/data/aes192.blb differ
diff --git a/cfb-mode/tests/data/aes256.blb b/cfb-mode/tests/data/aes256.blb
new file mode 100644
index 0000000..8479e7f
Binary files /dev/null and b/cfb-mode/tests/data/aes256.blb differ
diff --git a/cfb8/CHANGELOG.md b/cfb8/CHANGELOG.md
new file mode 100644
index 0000000..6b2e363
--- /dev/null
+++ b/cfb8/CHANGELOG.md
@@ -0,0 +1,56 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## 0.8.0 (2022-02-10)
+### Changed
+- Update `cipher` dependency to v0.4 and move crate
+to the [RustCrypto/block-modes] repository ([#2])
+
+[#2]: https://github.com/RustCrypto/block-modes/pull/2
+[RustCrypto/block-modes]: https://github.com/RustCrypto/block-modes
+
+## 0.7.1 (2021-04-30)
+### Changed
+- Removed redundant `NewBlockCipher` boundfrom `FromBlockCipher` implementation ([#236])
+
+[#236]: https://github.com/RustCrypto/stream-ciphers/pull/236
+
+## 0.7.0 (2021-04-29)
+### Changed
+- Bump `cipher` dependency to v0.3 release ([#226])
+- Bump `aes` dev dependency to v0.7 release ([#232])
+
+[#226]: https://github.com/RustCrypto/stream-ciphers/pull/226
+[#232]: https://github.com/RustCrypto/stream-ciphers/pull/232
+
+## 0.6.0 (2020-10-16)
+### Changed
+- Replace `block-cipher`/`stream-cipher` with `cipher` crate ([#177])
+
+[#177]: https://github.com/RustCrypto/stream-ciphers/pull/177
+
+## 0.5.0 (2020-08-25)
+### Changed
+- Bump `stream-cipher` dependency to v0.7, implement the `FromBlockCipher` trait ([#161], [#164])
+
+[#161]: https://github.com/RustCrypto/stream-ciphers/pull/161
+[#164]: https://github.com/RustCrypto/stream-ciphers/pull/164
+
+## 0.4.0 (2020-06-08)
+### Changed
+- Bump `stream-cipher` dependency to v0.4 ([#120])
+- Upgrade to Rust 2018 edition ([#120])
+
+[#120]: https://github.com/RustCrypto/stream-ciphers/pull/120
+
+## 0.3.2 (2019-03-11)
+
+## 0.3.1 (2018-11-01)
+
+## 0.3.0 (2018-11-01)
+
+## 0.1.0 (2018-11-01)
diff --git a/cfb8/Cargo.toml b/cfb8/Cargo.toml
new file mode 100644
index 0000000..ea16b02
--- /dev/null
+++ b/cfb8/Cargo.toml
@@ -0,0 +1,29 @@
+[package]
+name = "cfb8"
+version = "0.8.0" # Also update html_root_url in lib.rs when bumping this
+description = "Cipher Feedback with eight bit feedback (CFB-8) block cipher mode of operation"
+authors = ["RustCrypto Developers"]
+license = "MIT OR Apache-2.0"
+edition = "2021"
+rust-version = "1.56"
+readme = "README.md"
+documentation = "https://docs.rs/cfb8"
+repository = "https://github.com/RustCrypto/block-modes"
+keywords = ["crypto", "block-mode", "stream-cipher", "ciphers"]
+categories = ["cryptography", "no-std"]
+
+[dependencies]
+cipher = "0.4"
+
+[dev-dependencies]
+aes = "0.8"
+cipher = { version = "0.4", features = ["dev"] }
+hex-literal = "0.3"
+
+[features]
+block-padding = ["cipher/block-padding"]
+zeroize = ["cipher/zeroize"]
+
+[package.metadata.docs.rs]
+all-features = true
+rustdoc-args = ["--cfg", "docsrs"]
diff --git a/cfb8/LICENSE-APACHE b/cfb8/LICENSE-APACHE
new file mode 100644
index 0000000..78173fa
--- /dev/null
+++ b/cfb8/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/cfb8/LICENSE-MIT b/cfb8/LICENSE-MIT
new file mode 100644
index 0000000..d19d409
--- /dev/null
+++ b/cfb8/LICENSE-MIT
@@ -0,0 +1,26 @@
+Copyright (c) 2018-2022 RustCrypto Developers
+Copyright (c) 2018 Artyom Pavlov
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/cfb8/README.md b/cfb8/README.md
new file mode 100644
index 0000000..612de72
--- /dev/null
+++ b/cfb8/README.md
@@ -0,0 +1,60 @@
+# RustCrypto: CFB-8
+
+[![crate][crate-image]][crate-link]
+[![Docs][docs-image]][docs-link]
+![Apache2/MIT licensed][license-image]
+![Rust Version][rustc-image]
+[![Project Chat][chat-image]][chat-link]
+[![Build Status][build-image]][build-link]
+
+Generic implementation of the [Cipher Feedback][CFB-8] with eight bit
+feedback (CFB-8) block cipher mode of operation.
+
+
+
+See [documentation][cipher-doc] of the `cipher` crate for additional information.
+
+## Minimum Supported Rust Version
+
+Rust **1.56** or higher.
+
+Minimum supported Rust version can be changed in the future, but it will be
+done with a minor version bump.
+
+## SemVer Policy
+
+- All on-by-default features of this library are covered by SemVer
+- MSRV is considered exempt from SemVer as noted above
+
+## License
+
+Licensed under either of:
+
+ * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
+ * [MIT license](http://opensource.org/licenses/MIT)
+
+at your option.
+
+### Contribution
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
+dual licensed as above, without any additional terms or conditions.
+
+[//]: # (badges)
+
+[crate-image]: https://img.shields.io/crates/v/cfb.svg
+[crate-link]: https://crates.io/crates/cfb
+[docs-image]: https://docs.rs/cfb/badge.svg
+[docs-link]: https://docs.rs/cfb/
+[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg
+[rustc-image]: https://img.shields.io/badge/rustc-1.56+-blue.svg
+[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg
+[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/308460-block-modes
+[build-image]: https://github.com/RustCrypto/block-modes/workflows/cfb/badge.svg?branch=master&event=push
+[build-link]: https://github.com/RustCrypto/block-modes/actions?query=workflow%3Acfb+branch%3Amaster
+
+[//]: # (general links)
+
+[CFB]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#CFB-1,_CFB-8,_CFB-64,_CFB-128,_etc.
+[cipher-doc]: https://docs.rs/cipher/
diff --git a/cfb8/benches/aes128.rs b/cfb8/benches/aes128.rs
new file mode 100644
index 0000000..aa6dd6b
--- /dev/null
+++ b/cfb8/benches/aes128.rs
@@ -0,0 +1,16 @@
+#![feature(test)]
+extern crate test;
+
+use aes::Aes128;
+
+cipher::block_encryptor_bench!(
+ KeyIv: cfb8::Encryptor,
+ cfb8_aes128_encrypt_block,
+ cfb8_aes128_encrypt_blocks,
+);
+
+cipher::block_decryptor_bench!(
+ KeyIv: cfb8::Decryptor,
+ cfb8_aes128_decrypt_block,
+ cfb8_aes128_decrypt_blocks,
+);
diff --git a/cfb8/src/decrypt.rs b/cfb8/src/decrypt.rs
new file mode 100644
index 0000000..31362fc
--- /dev/null
+++ b/cfb8/src/decrypt.rs
@@ -0,0 +1,183 @@
+use cipher::{
+ consts::U1,
+ crypto_common::{InnerUser, IvSizeUser},
+ generic_array::{ArrayLength, GenericArray},
+ inout::InOut,
+ AlgorithmName, AsyncStreamCipher, Block, BlockBackend, BlockCipher, BlockClosure,
+ BlockDecryptMut, BlockEncryptMut, BlockSizeUser, InnerIvInit, Iv, IvState, ParBlocksSizeUser,
+};
+use core::fmt;
+
+#[cfg(feature = "zeroize")]
+use cipher::zeroize::{Zeroize, ZeroizeOnDrop};
+
+/// CFB-8 mode decryptor.
+#[derive(Clone)]
+pub struct Decryptor
+where
+ C: BlockEncryptMut + BlockCipher,
+{
+ cipher: C,
+ iv: Block,
+}
+
+impl BlockSizeUser for Decryptor
+where
+ C: BlockEncryptMut + BlockCipher,
+{
+ type BlockSize = U1;
+}
+
+impl BlockDecryptMut for Decryptor
+where
+ C: BlockEncryptMut + BlockCipher,
+{
+ fn decrypt_with_backend_mut(&mut self, f: impl BlockClosure) {
+ let Self { cipher, iv } = self;
+ cipher.encrypt_with_backend_mut(Closure { iv, f })
+ }
+}
+
+impl AsyncStreamCipher for Decryptor {}
+
+impl InnerUser for Decryptor