├── .github ├── dependabot.yml └── workflows │ ├── belt-ctr.yaml │ ├── cbc.yaml │ ├── cfb-mode.yaml │ ├── cfb8.yaml │ ├── ctr.yaml │ ├── cts.yaml │ ├── ige.yaml │ ├── ofb.yaml │ ├── pcbc.yaml │ ├── security-audit.yml │ └── workspace.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── README.md ├── belt-ctr ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── benches │ └── belt-ctr.rs ├── src │ └── lib.rs └── tests │ ├── data │ └── belt-ctr.blb │ └── mod.rs ├── cbc ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── benches │ └── aes128.rs ├── src │ ├── decrypt.rs │ ├── encrypt.rs │ └── lib.rs └── tests │ ├── aes.rs │ └── data │ ├── aes128.blb │ ├── aes192.blb │ └── aes256.blb ├── cfb-mode ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── benches │ └── aes128.rs ├── src │ ├── decrypt.rs │ ├── encrypt.rs │ ├── encrypt │ │ └── buf.rs │ └── lib.rs └── tests │ ├── aes.rs │ ├── belt.rs │ └── data │ ├── aes128.blb │ ├── aes192.blb │ ├── aes256.blb │ └── belt.blb ├── cfb8 ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── benches │ └── aes128.rs ├── src │ ├── decrypt.rs │ ├── encrypt.rs │ └── lib.rs └── tests │ ├── aes.rs │ └── data │ ├── aes128.blb │ ├── aes192.blb │ └── aes256.blb ├── ctr ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── benches │ └── aes128.rs ├── src │ ├── ctr_core.rs │ ├── flavors.rs │ ├── flavors │ │ ├── ctr128.rs │ │ ├── ctr32.rs │ │ └── ctr64.rs │ └── lib.rs └── tests │ ├── ctr128 │ ├── data │ │ ├── aes128-ctr.blb │ │ └── aes256-ctr.blb │ └── mod.rs │ ├── ctr32 │ ├── be.rs │ ├── le.rs │ └── mod.rs │ ├── gost │ └── mod.rs │ └── mod.rs ├── cts ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── src │ ├── cbc_cs1.rs │ ├── cbc_cs2.rs │ ├── cbc_cs3.rs │ ├── ecb_cs1.rs │ ├── ecb_cs2.rs │ ├── ecb_cs3.rs │ └── lib.rs └── tests │ ├── aes128_roundtrip.rs │ ├── belt_ecb.rs │ └── rfc3962.rs ├── ige ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── benches │ └── aes128.rs ├── src │ ├── decrypt.rs │ ├── encrypt.rs │ └── lib.rs └── tests │ ├── aes.rs │ └── data │ └── aes128.blb ├── ofb ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── benches │ └── aes128.rs ├── src │ └── lib.rs └── tests │ ├── aes.rs │ └── data │ ├── aes128.blb │ ├── aes192.blb │ └── aes256.blb └── pcbc ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── benches └── aes128.rs ├── src ├── decrypt.rs ├── encrypt.rs └── lib.rs └── tests ├── aes.rs └── data └── aes128.blb /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: cargo 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 8 | - package-ecosystem: github-actions 9 | directory: "/" 10 | schedule: 11 | interval: weekly 12 | open-pull-requests-limit: 10 13 | -------------------------------------------------------------------------------- /.github/workflows/belt-ctr.yaml: -------------------------------------------------------------------------------- 1 | name: belt-ctr 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - "belt-ctr/**" 7 | - "Cargo.*" 8 | push: 9 | branches: master 10 | 11 | defaults: 12 | run: 13 | working-directory: belt-ctr 14 | 15 | env: 16 | CARGO_INCREMENTAL: 0 17 | RUSTFLAGS: "-Dwarnings" 18 | 19 | jobs: 20 | build: 21 | runs-on: ubuntu-latest 22 | strategy: 23 | matrix: 24 | rust: 25 | - 1.85.0 # MSRV 26 | - stable 27 | target: 28 | - thumbv7em-none-eabi 29 | - wasm32-unknown-unknown 30 | steps: 31 | - uses: actions/checkout@v4 32 | - uses: RustCrypto/actions/cargo-cache@master 33 | - uses: actions-rs/toolchain@v1 34 | with: 35 | toolchain: ${{ matrix.rust }} 36 | target: ${{ matrix.target }} 37 | override: true 38 | profile: minimal 39 | - run: cargo build --no-default-features --release --target ${{ matrix.target }} 40 | 41 | minimal-versions: 42 | # disabled until belt-block gets published 43 | if: false 44 | uses: RustCrypto/actions/.github/workflows/minimal-versions.yml@master 45 | with: 46 | working-directory: ${{ github.workflow }} 47 | 48 | test: 49 | runs-on: ubuntu-latest 50 | strategy: 51 | matrix: 52 | rust: 53 | - 1.85.0 # MSRV 54 | - stable 55 | steps: 56 | - uses: actions/checkout@v4 57 | - uses: RustCrypto/actions/cargo-cache@master 58 | - uses: actions-rs/toolchain@v1 59 | with: 60 | toolchain: ${{ matrix.rust }} 61 | override: true 62 | profile: minimal 63 | - run: cargo test 64 | - run: cargo test --all-features 65 | -------------------------------------------------------------------------------- /.github/workflows/cbc.yaml: -------------------------------------------------------------------------------- 1 | name: cbc 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - "cbc/**" 7 | - "Cargo.*" 8 | push: 9 | branches: master 10 | 11 | defaults: 12 | run: 13 | working-directory: cbc 14 | 15 | env: 16 | CARGO_INCREMENTAL: 0 17 | RUSTFLAGS: "-Dwarnings" 18 | 19 | jobs: 20 | build: 21 | runs-on: ubuntu-latest 22 | strategy: 23 | matrix: 24 | rust: 25 | - 1.85.0 # MSRV 26 | - stable 27 | target: 28 | - thumbv7em-none-eabi 29 | - wasm32-unknown-unknown 30 | steps: 31 | - uses: actions/checkout@v4 32 | - uses: RustCrypto/actions/cargo-cache@master 33 | - uses: dtolnay/rust-toolchain@master 34 | with: 35 | toolchain: ${{ matrix.rust }} 36 | targets: ${{ matrix.target }} 37 | - run: cargo build --no-default-features --release --target ${{ matrix.target }} 38 | 39 | minimal-versions: 40 | # disabled until belt-block gets published 41 | if: false 42 | uses: RustCrypto/actions/.github/workflows/minimal-versions.yml@master 43 | with: 44 | working-directory: ${{ github.workflow }} 45 | 46 | test: 47 | runs-on: ubuntu-latest 48 | strategy: 49 | matrix: 50 | rust: 51 | - 1.85.0 # MSRV 52 | - stable 53 | steps: 54 | - uses: actions/checkout@v4 55 | - uses: RustCrypto/actions/cargo-cache@master 56 | - uses: dtolnay/rust-toolchain@master 57 | with: 58 | toolchain: ${{ matrix.rust }} 59 | - run: cargo test 60 | - run: cargo test --all-features 61 | -------------------------------------------------------------------------------- /.github/workflows/cfb-mode.yaml: -------------------------------------------------------------------------------- 1 | name: cfb-mode 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - "cfb-mode/**" 7 | - "Cargo.*" 8 | push: 9 | branches: master 10 | 11 | defaults: 12 | run: 13 | working-directory: cfb-mode 14 | 15 | env: 16 | CARGO_INCREMENTAL: 0 17 | RUSTFLAGS: "-Dwarnings" 18 | 19 | jobs: 20 | build: 21 | runs-on: ubuntu-latest 22 | strategy: 23 | matrix: 24 | rust: 25 | - 1.85.0 # MSRV 26 | - stable 27 | target: 28 | - thumbv7em-none-eabi 29 | - wasm32-unknown-unknown 30 | steps: 31 | - uses: actions/checkout@v4 32 | - uses: RustCrypto/actions/cargo-cache@master 33 | - uses: dtolnay/rust-toolchain@master 34 | with: 35 | toolchain: ${{ matrix.rust }} 36 | targets: ${{ matrix.target }} 37 | - run: cargo build --no-default-features --release --target ${{ matrix.target }} 38 | 39 | minimal-versions: 40 | # disabled until aes gets published 41 | if: false 42 | uses: RustCrypto/actions/.github/workflows/minimal-versions.yml@master 43 | with: 44 | working-directory: ${{ github.workflow }} 45 | 46 | test: 47 | runs-on: ubuntu-latest 48 | strategy: 49 | matrix: 50 | rust: 51 | - 1.85.0 # MSRV 52 | - stable 53 | steps: 54 | - uses: actions/checkout@v4 55 | - uses: RustCrypto/actions/cargo-cache@master 56 | - uses: dtolnay/rust-toolchain@master 57 | with: 58 | toolchain: ${{ matrix.rust }} 59 | - run: cargo test 60 | - run: cargo test --all-features 61 | -------------------------------------------------------------------------------- /.github/workflows/cfb8.yaml: -------------------------------------------------------------------------------- 1 | name: cfb8 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - "cfb8/**" 7 | - "Cargo.*" 8 | push: 9 | branches: master 10 | 11 | defaults: 12 | run: 13 | working-directory: cfb8 14 | 15 | env: 16 | CARGO_INCREMENTAL: 0 17 | RUSTFLAGS: "-Dwarnings" 18 | 19 | jobs: 20 | build: 21 | runs-on: ubuntu-latest 22 | strategy: 23 | matrix: 24 | rust: 25 | - 1.85.0 # MSRV 26 | - stable 27 | target: 28 | - thumbv7em-none-eabi 29 | - wasm32-unknown-unknown 30 | steps: 31 | - uses: actions/checkout@v4 32 | - uses: RustCrypto/actions/cargo-cache@master 33 | - uses: dtolnay/rust-toolchain@master 34 | with: 35 | toolchain: ${{ matrix.rust }} 36 | targets: ${{ matrix.target }} 37 | - run: cargo build --no-default-features --release --target ${{ matrix.target }} 38 | 39 | minimal-versions: 40 | # disabled until aes gets published 41 | if: false 42 | uses: RustCrypto/actions/.github/workflows/minimal-versions.yml@master 43 | with: 44 | working-directory: ${{ github.workflow }} 45 | 46 | test: 47 | runs-on: ubuntu-latest 48 | strategy: 49 | matrix: 50 | rust: 51 | - 1.85.0 # MSRV 52 | - stable 53 | steps: 54 | - uses: actions/checkout@v4 55 | - uses: RustCrypto/actions/cargo-cache@master 56 | - uses: dtolnay/rust-toolchain@master 57 | with: 58 | toolchain: ${{ matrix.rust }} 59 | - run: cargo test 60 | - run: cargo test --all-features 61 | -------------------------------------------------------------------------------- /.github/workflows/ctr.yaml: -------------------------------------------------------------------------------- 1 | name: ctr 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - "ctr/**" 7 | - "Cargo.*" 8 | push: 9 | branches: master 10 | 11 | defaults: 12 | run: 13 | working-directory: ctr 14 | 15 | env: 16 | CARGO_INCREMENTAL: 0 17 | RUSTFLAGS: "-Dwarnings" 18 | 19 | jobs: 20 | build: 21 | runs-on: ubuntu-latest 22 | strategy: 23 | matrix: 24 | rust: 25 | - 1.85.0 # MSRV 26 | - stable 27 | target: 28 | - thumbv7em-none-eabi 29 | - wasm32-unknown-unknown 30 | steps: 31 | - uses: actions/checkout@v4 32 | - uses: RustCrypto/actions/cargo-cache@master 33 | - uses: dtolnay/rust-toolchain@master 34 | with: 35 | toolchain: ${{ matrix.rust }} 36 | targets: ${{ matrix.target }} 37 | - run: cargo build --no-default-features --release --target ${{ matrix.target }} 38 | 39 | minimal-versions: 40 | # disabled until aes gets published 41 | if: false 42 | uses: RustCrypto/actions/.github/workflows/minimal-versions.yml@master 43 | with: 44 | working-directory: ${{ github.workflow }} 45 | 46 | test: 47 | runs-on: ubuntu-latest 48 | strategy: 49 | matrix: 50 | rust: 51 | - 1.85.0 # MSRV 52 | - stable 53 | steps: 54 | - uses: actions/checkout@v4 55 | - uses: RustCrypto/actions/cargo-cache@master 56 | - uses: dtolnay/rust-toolchain@master 57 | with: 58 | toolchain: ${{ matrix.rust }} 59 | - run: cargo test 60 | - run: cargo test --all-features 61 | -------------------------------------------------------------------------------- /.github/workflows/cts.yaml: -------------------------------------------------------------------------------- 1 | name: cts 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - "cts/**" 7 | - "Cargo.*" 8 | push: 9 | branches: master 10 | 11 | defaults: 12 | run: 13 | working-directory: cts 14 | 15 | env: 16 | CARGO_INCREMENTAL: 0 17 | RUSTFLAGS: "-Dwarnings" 18 | 19 | jobs: 20 | build: 21 | runs-on: ubuntu-latest 22 | strategy: 23 | matrix: 24 | rust: 25 | - 1.85.0 # MSRV 26 | - stable 27 | target: 28 | - thumbv7em-none-eabi 29 | - wasm32-unknown-unknown 30 | steps: 31 | - uses: actions/checkout@v4 32 | - uses: RustCrypto/actions/cargo-cache@master 33 | - uses: dtolnay/rust-toolchain@master 34 | with: 35 | toolchain: ${{ matrix.rust }} 36 | targets: ${{ matrix.target }} 37 | - run: cargo build --no-default-features --release --target ${{ matrix.target }} 38 | 39 | minimal-versions: 40 | # disabled until belt-block gets published 41 | if: false 42 | uses: RustCrypto/actions/.github/workflows/minimal-versions.yml@master 43 | with: 44 | working-directory: ${{ github.workflow }} 45 | 46 | test: 47 | runs-on: ubuntu-latest 48 | strategy: 49 | matrix: 50 | rust: 51 | - 1.85.0 # MSRV 52 | - stable 53 | steps: 54 | - uses: actions/checkout@v4 55 | - uses: RustCrypto/actions/cargo-cache@master 56 | - uses: dtolnay/rust-toolchain@master 57 | with: 58 | toolchain: ${{ matrix.rust }} 59 | - run: cargo test 60 | - run: cargo test --all-features 61 | -------------------------------------------------------------------------------- /.github/workflows/ige.yaml: -------------------------------------------------------------------------------- 1 | name: ige 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - "ige/**" 7 | - "Cargo.*" 8 | push: 9 | branches: master 10 | 11 | defaults: 12 | run: 13 | working-directory: ige 14 | 15 | env: 16 | CARGO_INCREMENTAL: 0 17 | RUSTFLAGS: "-Dwarnings" 18 | 19 | jobs: 20 | build: 21 | runs-on: ubuntu-latest 22 | strategy: 23 | matrix: 24 | rust: 25 | - 1.85.0 # MSRV 26 | - stable 27 | target: 28 | - thumbv7em-none-eabi 29 | - wasm32-unknown-unknown 30 | steps: 31 | - uses: actions/checkout@v4 32 | - uses: RustCrypto/actions/cargo-cache@master 33 | - uses: dtolnay/rust-toolchain@master 34 | with: 35 | toolchain: ${{ matrix.rust }} 36 | targets: ${{ matrix.target }} 37 | - run: cargo build --no-default-features --release --target ${{ matrix.target }} 38 | 39 | minimal-versions: 40 | # disabled until aes gets published 41 | if: false 42 | uses: RustCrypto/actions/.github/workflows/minimal-versions.yml@master 43 | with: 44 | working-directory: ${{ github.workflow }} 45 | 46 | test: 47 | runs-on: ubuntu-latest 48 | strategy: 49 | matrix: 50 | rust: 51 | - 1.85.0 # MSRV 52 | - stable 53 | steps: 54 | - uses: actions/checkout@v4 55 | - uses: RustCrypto/actions/cargo-cache@master 56 | - uses: dtolnay/rust-toolchain@master 57 | with: 58 | toolchain: ${{ matrix.rust }} 59 | - run: cargo test 60 | - run: cargo test --all-features 61 | -------------------------------------------------------------------------------- /.github/workflows/ofb.yaml: -------------------------------------------------------------------------------- 1 | name: ofb 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - "ofb/**" 7 | - "Cargo.*" 8 | push: 9 | branches: master 10 | 11 | defaults: 12 | run: 13 | working-directory: ofb 14 | 15 | env: 16 | CARGO_INCREMENTAL: 0 17 | RUSTFLAGS: "-Dwarnings" 18 | 19 | jobs: 20 | build: 21 | runs-on: ubuntu-latest 22 | strategy: 23 | matrix: 24 | rust: 25 | - 1.85.0 # MSRV 26 | - stable 27 | target: 28 | - thumbv7em-none-eabi 29 | - wasm32-unknown-unknown 30 | steps: 31 | - uses: actions/checkout@v4 32 | - uses: RustCrypto/actions/cargo-cache@master 33 | - uses: dtolnay/rust-toolchain@master 34 | with: 35 | toolchain: ${{ matrix.rust }} 36 | targets: ${{ matrix.target }} 37 | - run: cargo build --no-default-features --release --target ${{ matrix.target }} 38 | 39 | minimal-versions: 40 | # disabled until aes gets published 41 | if: false 42 | uses: RustCrypto/actions/.github/workflows/minimal-versions.yml@master 43 | with: 44 | working-directory: ${{ github.workflow }} 45 | 46 | test: 47 | runs-on: ubuntu-latest 48 | strategy: 49 | matrix: 50 | rust: 51 | - 1.85.0 # MSRV 52 | - stable 53 | steps: 54 | - uses: actions/checkout@v4 55 | - uses: RustCrypto/actions/cargo-cache@master 56 | - uses: dtolnay/rust-toolchain@master 57 | with: 58 | toolchain: ${{ matrix.rust }} 59 | - run: cargo test 60 | - run: cargo test --all-features 61 | -------------------------------------------------------------------------------- /.github/workflows/pcbc.yaml: -------------------------------------------------------------------------------- 1 | name: pcbc 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - "pcbc/**" 7 | - "Cargo.*" 8 | push: 9 | branches: master 10 | 11 | defaults: 12 | run: 13 | working-directory: pcbc 14 | 15 | env: 16 | CARGO_INCREMENTAL: 0 17 | RUSTFLAGS: "-Dwarnings" 18 | 19 | jobs: 20 | build: 21 | runs-on: ubuntu-latest 22 | strategy: 23 | matrix: 24 | rust: 25 | - 1.85.0 # MSRV 26 | - stable 27 | target: 28 | - thumbv7em-none-eabi 29 | - wasm32-unknown-unknown 30 | steps: 31 | - uses: actions/checkout@v4 32 | - uses: RustCrypto/actions/cargo-cache@master 33 | - uses: dtolnay/rust-toolchain@master 34 | with: 35 | toolchain: ${{ matrix.rust }} 36 | targets: ${{ matrix.target }} 37 | - run: cargo build --no-default-features --release --target ${{ matrix.target }} 38 | 39 | minimal-versions: 40 | # disabled until aes gets published 41 | if: false 42 | uses: RustCrypto/actions/.github/workflows/minimal-versions.yml@master 43 | with: 44 | working-directory: ${{ github.workflow }} 45 | 46 | test: 47 | runs-on: ubuntu-latest 48 | strategy: 49 | matrix: 50 | rust: 51 | - 1.85.0 # MSRV 52 | - stable 53 | steps: 54 | - uses: actions/checkout@v4 55 | - uses: RustCrypto/actions/cargo-cache@master 56 | - uses: dtolnay/rust-toolchain@master 57 | with: 58 | toolchain: ${{ matrix.rust }} 59 | - run: cargo test 60 | - run: cargo test --all-features 61 | -------------------------------------------------------------------------------- /.github/workflows/security-audit.yml: -------------------------------------------------------------------------------- 1 | name: Security Audit 2 | on: 3 | pull_request: 4 | paths: Cargo.lock 5 | push: 6 | branches: master 7 | paths: Cargo.lock 8 | schedule: 9 | - cron: "0 0 * * *" 10 | 11 | jobs: 12 | security_audit: 13 | name: Security Audit 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v4 17 | - name: Cache cargo bin 18 | uses: actions/cache@v4 19 | with: 20 | path: ~/.cargo/bin 21 | key: ${{ runner.os }}-cargo-audit-v0.12.0 22 | - uses: actions-rs/audit-check@v1 23 | with: 24 | token: ${{ secrets.GITHUB_TOKEN }} 25 | -------------------------------------------------------------------------------- /.github/workflows/workspace.yml: -------------------------------------------------------------------------------- 1 | name: Workspace 2 | 3 | on: 4 | pull_request: 5 | paths-ignore: 6 | - README.md 7 | push: 8 | branches: master 9 | paths-ignore: 10 | - README.md 11 | 12 | jobs: 13 | clippy: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v4 17 | - uses: RustCrypto/actions/cargo-cache@master 18 | - uses: dtolnay/rust-toolchain@master 19 | with: 20 | toolchain: 1.85.0 21 | components: clippy 22 | - run: cargo clippy --all --all-features -- -D warnings 23 | 24 | rustfmt: 25 | runs-on: ubuntu-latest 26 | steps: 27 | - name: Checkout sources 28 | uses: actions/checkout@v4 29 | 30 | - name: Install stable toolchain 31 | uses: dtolnay/rust-toolchain@master 32 | with: 33 | toolchain: stable 34 | components: rustfmt 35 | - name: Run cargo fmt 36 | run: cargo fmt --all -- --check 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "3" 3 | members = [ 4 | "belt-ctr", 5 | "cbc", 6 | "cts", 7 | "cfb8", 8 | "cfb-mode", 9 | "ctr", 10 | "ige", 11 | "ofb", 12 | "pcbc" 13 | ] 14 | 15 | [profile.dev] 16 | opt-level = 2 17 | -------------------------------------------------------------------------------- /belt-ctr/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## 0.1.0 (2023-04-02) 9 | - Initial release 10 | -------------------------------------------------------------------------------- /belt-ctr/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "belt-ctr" 3 | version = "0.2.0-rc.0" 4 | description = "CTR block mode of operation specified by the BelT standard" 5 | authors = ["RustCrypto Developers"] 6 | license = "MIT OR Apache-2.0" 7 | edition = "2024" 8 | rust-version = "1.85" 9 | readme = "README.md" 10 | documentation = "https://docs.rs/belt-ctr" 11 | repository = "https://github.com/RustCrypto/block-modes" 12 | keywords = ["crypto", "block-mode", "stream-cipher", "ciphers", "belt"] 13 | categories = ["cryptography", "no-std"] 14 | 15 | [dependencies] 16 | cipher = "0.5.0-rc.0" 17 | belt-block = "0.2.0-rc.0" 18 | 19 | [dev-dependencies] 20 | hex-literal = "1" 21 | belt-block = "0.2.0-rc.0" 22 | cipher = { version = "0.5.0-rc.0", features = ["dev"] } 23 | 24 | [features] 25 | alloc = ["cipher/alloc"] 26 | zeroize = ["cipher/zeroize"] 27 | 28 | [package.metadata.docs.rs] 29 | all-features = true 30 | rustdoc-args = ["--cfg", "docsrs"] 31 | -------------------------------------------------------------------------------- /belt-ctr/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2023 The RustCrypto Project Developers 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /belt-ctr/README.md: -------------------------------------------------------------------------------- 1 | # RustCrypto: belt-ctr 2 | 3 | [![crate][crate-image]][crate-link] 4 | [![Docs][docs-image]][docs-link] 5 | [![Build Status][build-image]][build-link] 6 | ![Apache2/MIT licensed][license-image] 7 | ![Rust Version][rustc-image] 8 | [![Project Chat][chat-image]][chat-link] 9 | 10 | Generic implementation of the [`belt-ctr`] block mode of operation. 11 | 12 | Mode functionality is accessed using traits from the [`cipher`] crate. 13 | 14 | # ⚠️ Security Warning: Hazmat! 15 | 16 | This crate does not ensure ciphertexts are authentic! Thus ciphertext integrity 17 | is not verified, which can lead to serious vulnerabilities! 18 | [AEADs] provide simple authenticated encryption, 19 | which is much less error-prone than manual integrity verification. 20 | 21 | # Example 22 | ```rust 23 | use hex_literal::hex; 24 | use belt_ctr::{BeltCtr, cipher::{KeyIvInit, StreamCipher, StreamCipherSeek}}; 25 | 26 | let key = &[0x42; 32]; 27 | let iv = &[0x24; 16]; 28 | let plaintext: &[u8; 34] = b"hello world! this is my plaintext."; 29 | let ciphertext: &[u8; 34] = &hex!( 30 | "38DF06243BD85DA1CAE597CE680D3AFE" 31 | "0EBB372A4F6A858DB2DBE20A63567EED" 32 | "7D1B" 33 | ); 34 | 35 | let mut cipher: BeltCtr = BeltCtr::new_from_slices(key, iv).unwrap(); 36 | 37 | // encrypt in-place 38 | let mut buf = plaintext.clone(); 39 | cipher.apply_keystream(&mut buf); 40 | assert_eq!(buf[..], ciphertext[..]); 41 | 42 | cipher.seek(0); 43 | cipher.apply_keystream(&mut buf); 44 | assert_eq!(buf[..], plaintext[..]); 45 | ``` 46 | 47 | ## License 48 | 49 | Licensed under either of: 50 | 51 | * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) 52 | * [MIT license](http://opensource.org/licenses/MIT) 53 | 54 | at your option. 55 | 56 | ### Contribution 57 | 58 | Unless you explicitly state otherwise, any contribution intentionally submitted 59 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be 60 | dual licensed as above, without any additional terms or conditions. 61 | 62 | [//]: # (badges) 63 | 64 | [crate-image]: https://img.shields.io/crates/v/belt-ctr.svg?logo=rust 65 | [crate-link]: https://crates.io/crates/belt-ctr 66 | [docs-image]: https://docs.rs/belt-ctr/badge.svg 67 | [docs-link]: https://docs.rs/belt-ctr/ 68 | [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg 69 | [rustc-image]: https://img.shields.io/badge/rustc-1.85+-blue.svg 70 | [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg 71 | [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/308460-block-modes 72 | [build-image]: https://github.com/RustCrypto/block-modes/actions/workflows/belt-ctr.yaml/badge.svg 73 | [build-link]: https://github.com/RustCrypto/block-modes/actions/workflows/belt-ctr.yaml 74 | 75 | [//]: # (general links) 76 | 77 | [`cipher`]: https://docs.rs/cipher/ 78 | [`belt-ctr`]: https://apmi.bsu.by/assets/files/std/belt-spec371.pdf 79 | [AEADs]: https://github.com/RustCrypto/AEADs 80 | -------------------------------------------------------------------------------- /belt-ctr/benches/belt-ctr.rs: -------------------------------------------------------------------------------- 1 | #![feature(test)] 2 | extern crate test; 3 | 4 | cipher::stream_cipher_bench!( 5 | belt_ctr::BeltCtr; 6 | belt_ctr_bench1_16b 16; 7 | belt_ctr_bench2_256b 256; 8 | belt_ctr_bench3_1kib 1024; 9 | belt_ctr_bench4_16kib 16384; 10 | ); 11 | -------------------------------------------------------------------------------- /belt-ctr/tests/data/belt-ctr.blb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RustCrypto/block-modes/e52ed9c70aa22b8dd07285f4b15981f137960cd5/belt-ctr/tests/data/belt-ctr.blb -------------------------------------------------------------------------------- /belt-ctr/tests/mod.rs: -------------------------------------------------------------------------------- 1 | use belt_ctr::{BeltCtr, BeltCtrCore}; 2 | 3 | // Test vectors from the BelT standard (tables A.15 and A.16): 4 | // https://apmi.bsu.by/assets/files/std/belt-spec371.pdf 5 | cipher::stream_cipher_test!(belt_ctr_core, "belt-ctr", BeltCtr); 6 | cipher::stream_cipher_seek_test!(belt_ctr_seek, BeltCtr); 7 | cipher::iv_state_test!(belt_ctr_iv_state, BeltCtrCore, apply_ks); 8 | -------------------------------------------------------------------------------- /cbc/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## 0.2.0 (UNRELEASED) 9 | ### Removed 10 | - `std` feature ([#76]) 11 | 12 | ### Changed 13 | - Bump `cipher` from `0.4` to `0.5` ([#56]) 14 | - Edition changed to 2024 and MSRV bumped to 1.85 ([#76]) 15 | - Relax MSRV policy and allow MSRV bumps in patch releases 16 | 17 | [#56]: https://github.com/RustCrypto/block-modes/pull/56 18 | [#76]: https://github.com/RustCrypto/block-modes/pull/76 19 | 20 | ## 0.1.2 (2022-03-24) 21 | ### Changed 22 | - Minor code tweaks to help compiler with codegen ([#15]) 23 | 24 | [#15]: https://github.com/RustCrypto/block-modes/pull/15 25 | 26 | ## 0.1.1 (2022-02-17) 27 | ### Fixed 28 | - Minimal versions build ([#9]) 29 | 30 | [#9]: https://github.com/RustCrypto/block-modes/pull/9 31 | 32 | ## 0.1.0 (2022-02-10) 33 | - Initial release ([#2]) 34 | 35 | [#2]: https://github.com/RustCrypto/block-modes/pull/2 36 | -------------------------------------------------------------------------------- /cbc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cbc" 3 | version = "0.2.0-rc.0" 4 | description = "Cipher Block Chaining (CBC) block cipher mode of operation" 5 | authors = ["RustCrypto Developers"] 6 | license = "MIT OR Apache-2.0" 7 | edition = "2024" 8 | rust-version = "1.85" 9 | readme = "README.md" 10 | documentation = "https://docs.rs/cbc" 11 | repository = "https://github.com/RustCrypto/block-modes" 12 | keywords = ["crypto", "block-mode", "ciphers"] 13 | categories = ["cryptography", "no-std"] 14 | 15 | [dependencies] 16 | cipher = "0.5.0-rc.0" 17 | 18 | [dev-dependencies] 19 | aes = "0.9.0-rc.0" 20 | cipher = { version = "0.5.0-rc.0", features = ["dev"] } 21 | hex-literal = "1" 22 | 23 | [features] 24 | default = ["block-padding"] 25 | alloc = ["cipher/alloc"] 26 | block-padding = ["cipher/block-padding"] 27 | zeroize = ["cipher/zeroize"] 28 | 29 | [package.metadata.docs.rs] 30 | all-features = true 31 | rustdoc-args = ["--cfg", "docsrs"] 32 | -------------------------------------------------------------------------------- /cbc/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018-2022 RustCrypto Developers 2 | Copyright (c) 2018 Artyom Pavlov 3 | 4 | Permission is hereby granted, free of charge, to any 5 | person obtaining a copy of this software and associated 6 | documentation files (the "Software"), to deal in the 7 | Software without restriction, including without 8 | limitation the rights to use, copy, modify, merge, 9 | publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software 11 | is furnished to do so, subject to the following 12 | conditions: 13 | 14 | The above copyright notice and this permission notice 15 | shall be included in all copies or substantial portions 16 | of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 19 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 20 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 21 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 22 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 23 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 25 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 | DEALINGS IN THE SOFTWARE. 27 | -------------------------------------------------------------------------------- /cbc/README.md: -------------------------------------------------------------------------------- 1 | # RustCrypto: CBC 2 | 3 | [![crate][crate-image]][crate-link] 4 | [![Docs][docs-image]][docs-link] 5 | [![Build Status][build-image]][build-link] 6 | ![Apache2/MIT licensed][license-image] 7 | ![Rust Version][rustc-image] 8 | [![Project Chat][chat-image]][chat-link] 9 | 10 | Generic implementation of the [Cipher Block Chaining][CBC] (CBC) block cipher 11 | mode of operation. 12 | 13 | 14 | 15 | See [documentation][cipher-doc] of the `cipher` crate for additional information. 16 | 17 | ## License 18 | 19 | Licensed under either of: 20 | 21 | * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) 22 | * [MIT license](http://opensource.org/licenses/MIT) 23 | 24 | at your option. 25 | 26 | ### Contribution 27 | 28 | Unless you explicitly state otherwise, any contribution intentionally submitted 29 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be 30 | dual licensed as above, without any additional terms or conditions. 31 | 32 | [//]: # (badges) 33 | 34 | [crate-image]: https://img.shields.io/crates/v/cbc.svg?logo=rust 35 | [crate-link]: https://crates.io/crates/cbc 36 | [docs-image]: https://docs.rs/cbc/badge.svg 37 | [docs-link]: https://docs.rs/cbc/ 38 | [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg 39 | [rustc-image]: https://img.shields.io/badge/rustc-1.85+-blue.svg 40 | [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg 41 | [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/308460-block-modes 42 | [build-image]: https://github.com/RustCrypto/block-modes/actions/workflows/cbc.yaml/badge.svg 43 | [build-link]: https://github.com/RustCrypto/block-modes/actions/workflows/cbc.yaml 44 | 45 | [//]: # (general links) 46 | 47 | [CBC]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#CBC 48 | [cipher-doc]: https://docs.rs/cipher/ 49 | -------------------------------------------------------------------------------- /cbc/benches/aes128.rs: -------------------------------------------------------------------------------- 1 | #![feature(test)] 2 | extern crate test; 3 | 4 | use aes::Aes128; 5 | 6 | cipher::block_encryptor_bench!( 7 | KeyIv: cbc::Encryptor, 8 | cbc_aes128_encrypt_block, 9 | cbc_aes128_encrypt_blocks, 10 | ); 11 | 12 | cipher::block_decryptor_bench!( 13 | KeyIv: cbc::Decryptor, 14 | cbc_aes128_decrypt_block, 15 | cbc_aes128_decrypt_blocks, 16 | ); 17 | -------------------------------------------------------------------------------- /cbc/src/decrypt.rs: -------------------------------------------------------------------------------- 1 | use crate::xor; 2 | use cipher::{ 3 | AlgorithmName, Block, BlockCipherDecBackend, BlockCipherDecClosure, BlockCipherDecrypt, 4 | BlockModeDecBackend, BlockModeDecClosure, BlockModeDecrypt, BlockSizeUser, InnerIvInit, Iv, 5 | IvState, ParBlocks, ParBlocksSizeUser, 6 | array::Array, 7 | crypto_common::{BlockSizes, InnerUser, IvSizeUser}, 8 | inout::InOut, 9 | }; 10 | use core::fmt; 11 | 12 | #[cfg(feature = "zeroize")] 13 | use cipher::zeroize::{Zeroize, ZeroizeOnDrop}; 14 | 15 | /// CBC mode decryptor. 16 | #[derive(Clone)] 17 | pub struct Decryptor 18 | where 19 | C: BlockCipherDecrypt, 20 | { 21 | cipher: C, 22 | iv: Block, 23 | } 24 | 25 | impl BlockSizeUser for Decryptor 26 | where 27 | C: BlockCipherDecrypt, 28 | { 29 | type BlockSize = C::BlockSize; 30 | } 31 | 32 | impl BlockModeDecrypt for Decryptor 33 | where 34 | C: BlockCipherDecrypt, 35 | { 36 | fn decrypt_with_backend(&mut self, f: impl BlockModeDecClosure) { 37 | struct Closure<'a, BS, BC> 38 | where 39 | BS: BlockSizes, 40 | BC: BlockModeDecClosure, 41 | { 42 | iv: &'a mut Array, 43 | f: BC, 44 | } 45 | 46 | impl BlockSizeUser for Closure<'_, BS, BC> 47 | where 48 | BS: BlockSizes, 49 | BC: BlockModeDecClosure, 50 | { 51 | type BlockSize = BS; 52 | } 53 | 54 | impl BlockCipherDecClosure for Closure<'_, BS, BC> 55 | where 56 | BS: BlockSizes, 57 | BC: BlockModeDecClosure, 58 | { 59 | #[inline(always)] 60 | fn call>( 61 | self, 62 | cipher_backend: &B, 63 | ) { 64 | let Self { iv, f } = self; 65 | f.call(&mut Backend { iv, cipher_backend }); 66 | } 67 | } 68 | 69 | let Self { cipher, iv } = self; 70 | cipher.decrypt_with_backend(Closure { iv, f }) 71 | } 72 | } 73 | 74 | impl InnerUser for Decryptor 75 | where 76 | C: BlockCipherDecrypt, 77 | { 78 | type Inner = C; 79 | } 80 | 81 | impl IvSizeUser for Decryptor 82 | where 83 | C: BlockCipherDecrypt, 84 | { 85 | type IvSize = C::BlockSize; 86 | } 87 | 88 | impl InnerIvInit for Decryptor 89 | where 90 | C: BlockCipherDecrypt, 91 | { 92 | #[inline] 93 | fn inner_iv_init(cipher: C, iv: &Iv) -> Self { 94 | Self { 95 | cipher, 96 | iv: iv.clone(), 97 | } 98 | } 99 | } 100 | 101 | impl IvState for Decryptor 102 | where 103 | C: BlockCipherDecrypt, 104 | { 105 | #[inline] 106 | fn iv_state(&self) -> Iv { 107 | self.iv.clone() 108 | } 109 | } 110 | 111 | impl AlgorithmName for Decryptor 112 | where 113 | C: BlockCipherDecrypt + AlgorithmName, 114 | { 115 | fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { 116 | f.write_str("cbc::Decryptor<")?; 117 | ::write_alg_name(f)?; 118 | f.write_str(">") 119 | } 120 | } 121 | 122 | impl fmt::Debug for Decryptor 123 | where 124 | C: BlockCipherDecrypt + AlgorithmName, 125 | { 126 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 127 | f.write_str("cbc::Decryptor<")?; 128 | ::write_alg_name(f)?; 129 | f.write_str("> { ... }") 130 | } 131 | } 132 | 133 | impl Drop for Decryptor { 134 | fn drop(&mut self) { 135 | #[cfg(feature = "zeroize")] 136 | self.iv.zeroize(); 137 | } 138 | } 139 | 140 | #[cfg(feature = "zeroize")] 141 | impl ZeroizeOnDrop for Decryptor {} 142 | 143 | struct Backend<'a, BS, BK> 144 | where 145 | BS: BlockSizes, 146 | BK: BlockCipherDecBackend, 147 | { 148 | iv: &'a mut Array, 149 | cipher_backend: &'a BK, 150 | } 151 | 152 | impl BlockSizeUser for Backend<'_, BS, BK> 153 | where 154 | BS: BlockSizes, 155 | BK: BlockCipherDecBackend, 156 | { 157 | type BlockSize = BS; 158 | } 159 | 160 | impl ParBlocksSizeUser for Backend<'_, BS, BK> 161 | where 162 | BS: BlockSizes, 163 | BK: BlockCipherDecBackend, 164 | { 165 | type ParBlocksSize = BK::ParBlocksSize; 166 | } 167 | 168 | impl BlockModeDecBackend for Backend<'_, BS, BK> 169 | where 170 | BS: BlockSizes, 171 | BK: BlockCipherDecBackend, 172 | { 173 | #[inline(always)] 174 | fn decrypt_block(&mut self, mut block: InOut<'_, '_, Block>) { 175 | let in_block = block.clone_in(); 176 | let mut t = block.clone_in(); 177 | self.cipher_backend.decrypt_block((&mut t).into()); 178 | xor(&mut t, self.iv); 179 | *block.get_out() = t; 180 | *self.iv = in_block; 181 | } 182 | 183 | #[inline(always)] 184 | fn decrypt_par_blocks(&mut self, mut blocks: InOut<'_, '_, ParBlocks>) { 185 | let in_blocks = blocks.clone_in(); 186 | let mut t = blocks.clone_in(); 187 | 188 | self.cipher_backend.decrypt_par_blocks((&mut t).into()); 189 | let n = t.len(); 190 | xor(&mut t[0], self.iv); 191 | for i in 1..n { 192 | xor(&mut t[i], &in_blocks[i - 1]) 193 | } 194 | *blocks.get_out() = t; 195 | *self.iv = in_blocks[n - 1].clone(); 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /cbc/src/encrypt.rs: -------------------------------------------------------------------------------- 1 | use crate::xor; 2 | use cipher::{ 3 | AlgorithmName, Array, Block, BlockCipherEncBackend, BlockCipherEncClosure, BlockCipherEncrypt, 4 | BlockModeEncBackend, BlockModeEncClosure, BlockModeEncrypt, BlockSizeUser, InOut, InnerIvInit, 5 | Iv, IvSizeUser, IvState, ParBlocksSizeUser, 6 | consts::U1, 7 | crypto_common::{BlockSizes, InnerUser}, 8 | }; 9 | use core::fmt; 10 | 11 | #[cfg(feature = "zeroize")] 12 | use cipher::zeroize::{Zeroize, ZeroizeOnDrop}; 13 | 14 | /// CBC mode encryptor. 15 | #[derive(Clone)] 16 | pub struct Encryptor 17 | where 18 | C: BlockCipherEncrypt, 19 | { 20 | cipher: C, 21 | iv: Block, 22 | } 23 | 24 | impl BlockSizeUser for Encryptor 25 | where 26 | C: BlockCipherEncrypt, 27 | { 28 | type BlockSize = C::BlockSize; 29 | } 30 | 31 | impl InnerUser for Encryptor 32 | where 33 | C: BlockCipherEncrypt, 34 | { 35 | type Inner = C; 36 | } 37 | 38 | impl IvSizeUser for Encryptor 39 | where 40 | C: BlockCipherEncrypt, 41 | { 42 | type IvSize = C::BlockSize; 43 | } 44 | 45 | impl InnerIvInit for Encryptor 46 | where 47 | C: BlockCipherEncrypt, 48 | { 49 | #[inline] 50 | fn inner_iv_init(cipher: C, iv: &Iv) -> Self { 51 | Self { 52 | cipher, 53 | iv: iv.clone(), 54 | } 55 | } 56 | } 57 | 58 | impl IvState for Encryptor 59 | where 60 | C: BlockCipherEncrypt, 61 | { 62 | #[inline] 63 | fn iv_state(&self) -> Iv { 64 | self.iv.clone() 65 | } 66 | } 67 | 68 | impl BlockModeEncrypt for Encryptor 69 | where 70 | C: BlockCipherEncrypt, 71 | { 72 | fn encrypt_with_backend(&mut self, f: impl BlockModeEncClosure) { 73 | struct Closure<'a, BS, BC> 74 | where 75 | BS: BlockSizes, 76 | BC: BlockModeEncClosure, 77 | { 78 | iv: &'a mut Array, 79 | f: BC, 80 | } 81 | 82 | impl BlockSizeUser for Closure<'_, BS, BC> 83 | where 84 | BS: BlockSizes, 85 | BC: BlockModeEncClosure, 86 | { 87 | type BlockSize = BS; 88 | } 89 | 90 | impl BlockCipherEncClosure for Closure<'_, BS, BC> 91 | where 92 | BS: BlockSizes, 93 | BC: BlockModeEncClosure, 94 | { 95 | #[inline(always)] 96 | fn call>( 97 | self, 98 | cipher_backend: &B, 99 | ) { 100 | let Self { iv, f } = self; 101 | f.call(&mut Backend { iv, cipher_backend }); 102 | } 103 | } 104 | 105 | let Self { cipher, iv } = self; 106 | cipher.encrypt_with_backend(Closure { iv, f }) 107 | } 108 | } 109 | 110 | impl AlgorithmName for Encryptor 111 | where 112 | C: BlockCipherEncrypt + AlgorithmName, 113 | { 114 | fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { 115 | f.write_str("cbc::Encryptor<")?; 116 | ::write_alg_name(f)?; 117 | f.write_str(">") 118 | } 119 | } 120 | 121 | impl fmt::Debug for Encryptor 122 | where 123 | C: BlockCipherEncrypt + AlgorithmName, 124 | { 125 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 126 | f.write_str("cbc::Encryptor<")?; 127 | ::write_alg_name(f)?; 128 | f.write_str("> { ... }") 129 | } 130 | } 131 | 132 | impl Drop for Encryptor { 133 | fn drop(&mut self) { 134 | #[cfg(feature = "zeroize")] 135 | self.iv.zeroize(); 136 | } 137 | } 138 | 139 | #[cfg(feature = "zeroize")] 140 | impl ZeroizeOnDrop for Encryptor {} 141 | 142 | struct Backend<'a, BS, BK> 143 | where 144 | BS: BlockSizes, 145 | BK: BlockCipherEncBackend, 146 | { 147 | iv: &'a mut Array, 148 | cipher_backend: &'a BK, 149 | } 150 | 151 | impl BlockSizeUser for Backend<'_, BS, BK> 152 | where 153 | BS: BlockSizes, 154 | BK: BlockCipherEncBackend, 155 | { 156 | type BlockSize = BS; 157 | } 158 | 159 | impl ParBlocksSizeUser for Backend<'_, BS, BK> 160 | where 161 | BS: BlockSizes, 162 | BK: BlockCipherEncBackend, 163 | { 164 | type ParBlocksSize = U1; 165 | } 166 | 167 | impl BlockModeEncBackend for Backend<'_, BS, BK> 168 | where 169 | BS: BlockSizes, 170 | BK: BlockCipherEncBackend, 171 | { 172 | #[inline(always)] 173 | fn encrypt_block(&mut self, mut block: InOut<'_, '_, Block>) { 174 | let mut t = block.clone_in(); 175 | xor(&mut t, self.iv); 176 | self.cipher_backend.encrypt_block((&mut t).into()); 177 | *self.iv = t.clone(); 178 | *block.get_out() = t; 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /cbc/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! [Cipher Block Chaining][1] (CBC) mode. 2 | //! 3 | //! 4 | //! 5 | //! 6 | //! Mode functionality is accessed using traits from re-exported [`cipher`] crate. 7 | //! 8 | //! # ⚠️ Security Warning: Hazmat! 9 | //! 10 | //! This crate does not ensure ciphertexts are authentic! Thus ciphertext integrity 11 | //! is not verified, which can lead to serious vulnerabilities! 12 | //! [AEADs][https://github.com/RustCrypto/AEADs] provide simple authenticated encryption, 13 | //! which is much less error-prone than manual integrity verification. 14 | //! 15 | //! # Example 16 | //! ``` 17 | //! # #[cfg(feature = "block-padding")] { 18 | //! use aes::cipher::{block_padding::Pkcs7, BlockModeEncrypt, BlockModeDecrypt, KeyIvInit}; 19 | //! use hex_literal::hex; 20 | //! 21 | //! type Aes128CbcEnc = cbc::Encryptor; 22 | //! type Aes128CbcDec = cbc::Decryptor; 23 | //! 24 | //! let key = [0x42; 16]; 25 | //! let iv = [0x24; 16]; 26 | //! let plaintext = *b"hello world! this is my plaintext."; 27 | //! let ciphertext = hex!( 28 | //! "c7fe247ef97b21f07cbdd26cb5d346bf" 29 | //! "d27867cb00d9486723e159978fb9a5f9" 30 | //! "14cfb228a710de4171e396e7b6cf859e" 31 | //! ); 32 | //! 33 | //! // encrypt/decrypt in-place 34 | //! // buffer must be big enough for padded plaintext 35 | //! let mut buf = [0u8; 48]; 36 | //! let pt_len = plaintext.len(); 37 | //! buf[..pt_len].copy_from_slice(&plaintext); 38 | //! let ct = Aes128CbcEnc::new(&key.into(), &iv.into()) 39 | //! .encrypt_padded::(&mut buf, pt_len) 40 | //! .unwrap(); 41 | //! assert_eq!(ct, &ciphertext[..]); 42 | //! 43 | //! let pt = Aes128CbcDec::new(&key.into(), &iv.into()) 44 | //! .decrypt_padded::(&mut buf) 45 | //! .unwrap(); 46 | //! assert_eq!(pt, &plaintext); 47 | //! 48 | //! // encrypt/decrypt from buffer to buffer 49 | //! let mut buf = [0u8; 48]; 50 | //! let ct = Aes128CbcEnc::new(&key.into(), &iv.into()) 51 | //! .encrypt_padded_b2b::(&plaintext, &mut buf) 52 | //! .unwrap(); 53 | //! assert_eq!(ct, &ciphertext[..]); 54 | //! 55 | //! let mut buf = [0u8; 48]; 56 | //! let pt = Aes128CbcDec::new(&key.into(), &iv.into()) 57 | //! .decrypt_padded_b2b::(&ct, &mut buf) 58 | //! .unwrap(); 59 | //! assert_eq!(pt, &plaintext); 60 | //! # } 61 | //! ``` 62 | //! 63 | //! With enabled `alloc` (or `std`) feature you also can use allocating 64 | //! convenience methods: 65 | //! ``` 66 | //! # #[cfg(all(feature = "alloc", feature = "block-padding"))] { 67 | //! # use aes::cipher::{block_padding::Pkcs7, BlockModeEncrypt, BlockModeDecrypt, KeyIvInit}; 68 | //! # use hex_literal::hex; 69 | //! # type Aes128CbcEnc = cbc::Encryptor; 70 | //! # type Aes128CbcDec = cbc::Decryptor; 71 | //! # let key = [0x42; 16]; 72 | //! # let iv = [0x24; 16]; 73 | //! # let plaintext = *b"hello world! this is my plaintext."; 74 | //! # let ciphertext = hex!( 75 | //! # "c7fe247ef97b21f07cbdd26cb5d346bf" 76 | //! # "d27867cb00d9486723e159978fb9a5f9" 77 | //! # "14cfb228a710de4171e396e7b6cf859e" 78 | //! # ); 79 | //! let res = Aes128CbcEnc::new(&key.into(), &iv.into()) 80 | //! .encrypt_padded_vec::(&plaintext); 81 | //! assert_eq!(res[..], ciphertext[..]); 82 | //! let res = Aes128CbcDec::new(&key.into(), &iv.into()) 83 | //! .decrypt_padded_vec::(&res) 84 | //! .unwrap(); 85 | //! assert_eq!(res[..], plaintext[..]); 86 | //! # } 87 | //! ``` 88 | //! 89 | //! [1]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#CBC 90 | 91 | #![no_std] 92 | #![doc( 93 | html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", 94 | html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg" 95 | )] 96 | #![forbid(unsafe_code)] 97 | #![cfg_attr(docsrs, feature(doc_auto_cfg))] 98 | #![warn(missing_debug_implementations, missing_docs, rust_2018_idioms)] 99 | 100 | mod decrypt; 101 | mod encrypt; 102 | 103 | pub use cipher; 104 | pub use decrypt::Decryptor; 105 | pub use encrypt::Encryptor; 106 | 107 | use cipher::array::{Array, ArraySize}; 108 | 109 | #[inline(always)] 110 | fn xor(out: &mut Array, buf: &Array) { 111 | for (a, b) in out.iter_mut().zip(buf) { 112 | *a ^= *b; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /cbc/tests/aes.rs: -------------------------------------------------------------------------------- 1 | use aes::*; 2 | use cbc::{Decryptor, Encryptor}; 3 | use cipher::{block_mode_dec_test, block_mode_enc_test, iv_state_test}; 4 | 5 | iv_state_test!(aes128_cbc_enc_iv_state, Encryptor, encrypt); 6 | iv_state_test!(aes128_cbc_dec_iv_state, Decryptor, decrypt); 7 | iv_state_test!(aes192_cbc_enc_iv_state, Encryptor, encrypt); 8 | iv_state_test!(aes192_cbc_dec_iv_state, Decryptor, decrypt); 9 | iv_state_test!(aes256_cbc_enc_iv_state, Encryptor, encrypt); 10 | iv_state_test!(aes256_cbc_dec_iv_state, Decryptor, decrypt); 11 | 12 | // Test vectors from CVAP "AES Multiblock Message Test (MMT) Sample Vectors": 13 | // 14 | block_mode_enc_test!(aes128_cbc_enc_test, "aes128", Encryptor); 15 | block_mode_dec_test!(aes128_cbc_dec_test, "aes128", Decryptor); 16 | block_mode_enc_test!(aes128enc_cbc_enc_test, "aes128", Encryptor); 17 | block_mode_dec_test!(aes128dec_cbc_dec_test, "aes128", Decryptor); 18 | block_mode_enc_test!(aes192_cbc_enc_test, "aes192", Encryptor); 19 | block_mode_dec_test!(aes192_cbc_dec_test, "aes192", Decryptor); 20 | block_mode_enc_test!(aes192enc_cbc_enc_test, "aes192", Encryptor); 21 | block_mode_dec_test!(aes192dec_cbc_dec_test, "aes192", Decryptor); 22 | block_mode_enc_test!(aes256_cbc_enc_test, "aes256", Encryptor); 23 | block_mode_dec_test!(aes256_cbc_dec_test, "aes256", Decryptor); 24 | block_mode_enc_test!(aes256enc_cbc_enc_test, "aes256", Encryptor); 25 | block_mode_dec_test!(aes256dec_cbc_dec_test, "aes256", Decryptor); 26 | -------------------------------------------------------------------------------- /cbc/tests/data/aes128.blb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RustCrypto/block-modes/e52ed9c70aa22b8dd07285f4b15981f137960cd5/cbc/tests/data/aes128.blb -------------------------------------------------------------------------------- /cbc/tests/data/aes192.blb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RustCrypto/block-modes/e52ed9c70aa22b8dd07285f4b15981f137960cd5/cbc/tests/data/aes192.blb -------------------------------------------------------------------------------- /cbc/tests/data/aes256.blb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RustCrypto/block-modes/e52ed9c70aa22b8dd07285f4b15981f137960cd5/cbc/tests/data/aes256.blb -------------------------------------------------------------------------------- /cfb-mode/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## 0.9.0 (UNRELEASED) 9 | ### Removed 10 | - `std` feature ([#76]) 11 | 12 | ### Changed 13 | - Bump `cipher` from `0.4` to `0.5` ([#56]) 14 | - Edition changed to 2024 and MSRV bumped to 1.85 ([#76]) 15 | - Relax MSRV policy and allow MSRV bumps in patch releases 16 | 17 | [#56]: https://github.com/RustCrypto/block-modes/pull/56 18 | [#76]: https://github.com/RustCrypto/block-modes/pull/76 19 | 20 | ## 0.8.2 (2022-09-13) 21 | ### Added 22 | - `BufferEncryptor` and `BufferDecryptor` types ([#19]) 23 | 24 | [#19]: https://github.com/RustCrypto/block-modes/pull/19 25 | 26 | ## 0.8.1 (2022-02-17) 27 | ### Fixed 28 | - Minimal versions build ([#9]) 29 | 30 | [#9]: https://github.com/RustCrypto/block-modes/pull/9 31 | 32 | ## 0.8.0 (2022-02-10) 33 | ### Changed 34 | - Update `cipher` dependency to v0.4 and move crate 35 | to the [RustCrypto/block-modes] repository ([#2]) 36 | 37 | [#2]: https://github.com/RustCrypto/block-modes/pull/2 38 | [RustCrypto/block-modes]: https://github.com/RustCrypto/block-modes 39 | 40 | ## 0.7.1 (2021-04-30) 41 | ### Changed 42 | - Removed redundant `NewBlockCipher` bound from `FromBlockCipher` implementation ([#236]) 43 | 44 | [#236]: https://github.com/RustCrypto/stream-ciphers/pull/236 45 | 46 | ## 0.7.0 (2021-04-29) 47 | ### Changed 48 | - Bump `cipher` dependency to v0.3 release ([#226]) 49 | - Bump `aes` dev dependency to v0.7 release ([#232]) 50 | 51 | [#226]: https://github.com/RustCrypto/stream-ciphers/pull/226 52 | [#232]: https://github.com/RustCrypto/stream-ciphers/pull/232 53 | 54 | ## 0.6.0 (2020-10-16) 55 | ### Changed 56 | - Replace `block-cipher`/`stream-cipher` with `cipher` crate ([#177]) 57 | 58 | [#177]: https://github.com/RustCrypto/stream-ciphers/pull/177 59 | 60 | ## 0.5.0 (2020-08-25) 61 | ### Changed 62 | - Bump `stream-cipher` dependency to v0.7, implement the `FromBlockCipher` trait ([#161], [#164]) 63 | 64 | [#161]: https://github.com/RustCrypto/stream-ciphers/pull/161 65 | [#164]: https://github.com/RustCrypto/stream-ciphers/pull/164 66 | 67 | ## 0.4.0 (2020-06-08) 68 | ### Changed 69 | - Bump `stream-cipher` dependency to v0.4 ([#119]) 70 | - Upgrade to Rust 2018 edition ([#119]) 71 | 72 | [#119]: https://github.com/RustCrypto/stream-ciphers/pull/119 73 | 74 | ## 0.3.2 (2019-03-11) 75 | 76 | ## 0.3.1 (2018-11-01) 77 | 78 | ## 0.3.0 (2018-11-01) 79 | 80 | ## 0.2.0 (2018-10-13) 81 | 82 | ## 0.1.0 (2018-10-01) 83 | -------------------------------------------------------------------------------- /cfb-mode/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cfb-mode" 3 | version = "0.9.0-rc.0" 4 | description = "Cipher Feedback (CFB) block cipher mode of operation" 5 | authors = ["RustCrypto Developers"] 6 | license = "MIT OR Apache-2.0" 7 | edition = "2024" 8 | rust-version = "1.85" 9 | readme = "README.md" 10 | documentation = "https://docs.rs/cfb-mode" 11 | repository = "https://github.com/RustCrypto/block-modes" 12 | keywords = ["crypto", "block-mode", "stream-cipher", "ciphers"] 13 | categories = ["cryptography", "no-std"] 14 | 15 | [dependencies] 16 | cipher = "0.5.0-rc.0" 17 | 18 | [dev-dependencies] 19 | aes = "0.9.0-rc.0" 20 | belt-block = "0.2.0-rc.0" 21 | cipher = { version = "0.5.0-rc.0", features = ["dev"] } 22 | hex-literal = "1" 23 | 24 | [features] 25 | alloc = ["cipher/alloc"] 26 | block-padding = ["cipher/block-padding"] 27 | zeroize = ["cipher/zeroize"] 28 | 29 | [package.metadata.docs.rs] 30 | all-features = true 31 | rustdoc-args = ["--cfg", "docsrs"] 32 | -------------------------------------------------------------------------------- /cfb-mode/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018-2022 RustCrypto Developers 2 | Copyright (c) 2018 Artyom Pavlov 3 | 4 | Permission is hereby granted, free of charge, to any 5 | person obtaining a copy of this software and associated 6 | documentation files (the "Software"), to deal in the 7 | Software without restriction, including without 8 | limitation the rights to use, copy, modify, merge, 9 | publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software 11 | is furnished to do so, subject to the following 12 | conditions: 13 | 14 | The above copyright notice and this permission notice 15 | shall be included in all copies or substantial portions 16 | of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 19 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 20 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 21 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 22 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 23 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 25 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 | DEALINGS IN THE SOFTWARE. 27 | -------------------------------------------------------------------------------- /cfb-mode/README.md: -------------------------------------------------------------------------------- 1 | # RustCrypto: CFB 2 | 3 | [![crate][crate-image]][crate-link] 4 | [![Docs][docs-image]][docs-link] 5 | [![Build Status][build-image]][build-link] 6 | ![Apache2/MIT licensed][license-image] 7 | ![Rust Version][rustc-image] 8 | [![Project Chat][chat-image]][chat-link] 9 | 10 | Generic implementation of the [Cipher Feedback][CFB] (CFB) block cipher mode 11 | of operation. 12 | 13 | 14 | 15 | See [documentation][cipher-doc] of the `cipher` crate for additional information. 16 | 17 | ## License 18 | 19 | Licensed under either of: 20 | 21 | * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) 22 | * [MIT license](http://opensource.org/licenses/MIT) 23 | 24 | at your option. 25 | 26 | ### Contribution 27 | 28 | Unless you explicitly state otherwise, any contribution intentionally submitted 29 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be 30 | dual licensed as above, without any additional terms or conditions. 31 | 32 | [//]: # (badges) 33 | 34 | [crate-image]: https://img.shields.io/crates/v/cfb-mode.svg?logo=rust 35 | [crate-link]: https://crates.io/crates/cfb-mode 36 | [docs-image]: https://docs.rs/cfb-mode/badge.svg 37 | [docs-link]: https://docs.rs/cfb-mode/ 38 | [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg 39 | [rustc-image]: https://img.shields.io/badge/rustc-1.85+-blue.svg 40 | [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg 41 | [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/308460-block-modes 42 | [build-image]: https://github.com/RustCrypto/block-modes/actions/workflows/cfb-mode.yaml/badge.svg 43 | [build-link]: https://github.com/RustCrypto/block-modes/actions/workflows/cfb-mode.yaml 44 | 45 | [//]: # (general links) 46 | 47 | [CFB]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_feedback_(CFB) 48 | [cipher-doc]: https://docs.rs/cipher/ 49 | -------------------------------------------------------------------------------- /cfb-mode/benches/aes128.rs: -------------------------------------------------------------------------------- 1 | #![feature(test)] 2 | extern crate test; 3 | 4 | use aes::Aes128; 5 | 6 | cipher::block_encryptor_bench!( 7 | KeyIv: cfb_mode::Encryptor, 8 | cfb_aes128_encrypt_block, 9 | cfb_aes128_encrypt_blocks, 10 | ); 11 | 12 | cipher::block_decryptor_bench!( 13 | KeyIv: cfb_mode::Decryptor, 14 | cfb_aes128_decrypt_block, 15 | cfb_aes128_decrypt_blocks, 16 | ); 17 | -------------------------------------------------------------------------------- /cfb-mode/src/encrypt/buf.rs: -------------------------------------------------------------------------------- 1 | use super::xor_set1; 2 | use cipher::{ 3 | AlgorithmName, Block, BlockCipherEncrypt, InnerIvInit, Iv, IvSizeUser, 4 | crypto_common::InnerUser, typenum::Unsigned, 5 | }; 6 | use core::fmt; 7 | 8 | #[cfg(feature = "zeroize")] 9 | use cipher::zeroize::{Zeroize, ZeroizeOnDrop}; 10 | 11 | /// CFB mode buffered encryptor. 12 | #[derive(Clone)] 13 | pub struct BufEncryptor 14 | where 15 | C: BlockCipherEncrypt, 16 | { 17 | cipher: C, 18 | iv: Block, 19 | pos: usize, 20 | } 21 | 22 | impl BufEncryptor 23 | where 24 | C: BlockCipherEncrypt, 25 | { 26 | /// Encrypt a buffer in multiple parts. 27 | pub fn encrypt(&mut self, mut data: &mut [u8]) { 28 | let bs = C::BlockSize::USIZE; 29 | let n = data.len(); 30 | 31 | if n < bs - self.pos { 32 | xor_set1(data, &mut self.iv[self.pos..self.pos + n]); 33 | self.pos += n; 34 | return; 35 | } 36 | 37 | let (left, right) = { data }.split_at_mut(bs - self.pos); 38 | data = right; 39 | let mut iv = self.iv.clone(); 40 | xor_set1(left, &mut iv[self.pos..]); 41 | self.cipher.encrypt_block(&mut iv); 42 | 43 | let mut chunks = data.chunks_exact_mut(bs); 44 | for chunk in &mut chunks { 45 | xor_set1(chunk, iv.as_mut_slice()); 46 | self.cipher.encrypt_block(&mut iv); 47 | } 48 | 49 | let rem = chunks.into_remainder(); 50 | xor_set1(rem, iv.as_mut_slice()); 51 | self.pos = rem.len(); 52 | self.iv = iv; 53 | } 54 | 55 | /// Returns the current state (block and position) of the decryptor. 56 | pub fn get_state(&self) -> (&Block, usize) { 57 | (&self.iv, self.pos) 58 | } 59 | 60 | /// Restore from the given state for resumption. 61 | pub fn from_state(cipher: C, iv: &Block, pos: usize) -> Self { 62 | Self { 63 | cipher, 64 | iv: iv.clone(), 65 | pos, 66 | } 67 | } 68 | } 69 | 70 | impl InnerUser for BufEncryptor 71 | where 72 | C: BlockCipherEncrypt, 73 | { 74 | type Inner = C; 75 | } 76 | 77 | impl IvSizeUser for BufEncryptor 78 | where 79 | C: BlockCipherEncrypt, 80 | { 81 | type IvSize = C::BlockSize; 82 | } 83 | 84 | impl InnerIvInit for BufEncryptor 85 | where 86 | C: BlockCipherEncrypt, 87 | { 88 | #[inline] 89 | fn inner_iv_init(cipher: C, iv: &Iv) -> Self { 90 | let mut iv = iv.clone(); 91 | cipher.encrypt_block(&mut iv); 92 | Self { cipher, iv, pos: 0 } 93 | } 94 | } 95 | 96 | impl AlgorithmName for BufEncryptor 97 | where 98 | C: BlockCipherEncrypt + AlgorithmName, 99 | { 100 | fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { 101 | f.write_str("cfb::BufEncryptor<")?; 102 | ::write_alg_name(f)?; 103 | f.write_str(">") 104 | } 105 | } 106 | 107 | impl fmt::Debug for BufEncryptor 108 | where 109 | C: BlockCipherEncrypt + AlgorithmName, 110 | { 111 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 112 | f.write_str("cfb::BufEncryptor<")?; 113 | ::write_alg_name(f)?; 114 | f.write_str("> { ... }") 115 | } 116 | } 117 | 118 | impl Drop for BufEncryptor { 119 | fn drop(&mut self) { 120 | #[cfg(feature = "zeroize")] 121 | self.iv.zeroize(); 122 | } 123 | } 124 | 125 | #[cfg(feature = "zeroize")] 126 | impl ZeroizeOnDrop for BufEncryptor {} 127 | -------------------------------------------------------------------------------- /cfb-mode/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! [Cipher feedback][1] (CFB) mode with full block feedback. 2 | //! 3 | //! 4 | //! 5 | //! 6 | //! Mode functionality is accessed using traits from re-exported [`cipher`] crate. 7 | //! 8 | //! # ⚠️ Security Warning: Hazmat! 9 | //! 10 | //! This crate does not ensure ciphertexts are authentic! Thus ciphertext integrity 11 | //! is not verified, which can lead to serious vulnerabilities! 12 | //! [AEADs][https://github.com/RustCrypto/AEADs] provide simple authenticated encryption, 13 | //! which is much less error-prone than manual integrity verification. 14 | //! 15 | //! # Example 16 | //! ``` 17 | //! use aes::cipher::{AsyncStreamCipher, KeyIvInit}; 18 | //! use hex_literal::hex; 19 | //! 20 | //! type Aes128CfbEnc = cfb_mode::Encryptor; 21 | //! type Aes128CfbDec = cfb_mode::Decryptor; 22 | //! 23 | //! let key = [0x42; 16]; 24 | //! let iv = [0x24; 16]; 25 | //! let plaintext = *b"hello world! this is my plaintext."; 26 | //! let ciphertext = hex!( 27 | //! "3357121ebb5a29468bd861467596ce3d6f99e251cc2d9f0a598032ae386d0ab995b3" 28 | //! ); 29 | //! 30 | //! // encrypt/decrypt in-place 31 | //! let mut buf = plaintext.to_vec(); 32 | //! Aes128CfbEnc::new(&key.into(), &iv.into()).encrypt(&mut buf); 33 | //! assert_eq!(buf[..], ciphertext[..]); 34 | //! 35 | //! Aes128CfbDec::new(&key.into(), &iv.into()).decrypt(&mut buf); 36 | //! assert_eq!(buf[..], plaintext[..]); 37 | //! 38 | //! // encrypt/decrypt from buffer to buffer 39 | //! // buffer length must be equal to input length 40 | //! let mut buf1 = [0u8; 34]; 41 | //! Aes128CfbEnc::new(&key.into(), &iv.into()) 42 | //! .encrypt_b2b(&plaintext, &mut buf1) 43 | //! .unwrap(); 44 | //! assert_eq!(buf1[..], ciphertext[..]); 45 | //! 46 | //! let mut buf2 = [0u8; 34]; 47 | //! Aes128CfbDec::new(&key.into(), &iv.into()) 48 | //! .decrypt_b2b(&buf1, &mut buf2) 49 | //! .unwrap(); 50 | //! assert_eq!(buf2[..], plaintext[..]); 51 | //! ``` 52 | //! 53 | //! [1]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_feedback_(CFB) 54 | 55 | #![no_std] 56 | #![doc( 57 | html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", 58 | html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg" 59 | )] 60 | #![forbid(unsafe_code)] 61 | #![cfg_attr(docsrs, feature(doc_auto_cfg))] 62 | #![warn(missing_debug_implementations, missing_docs, rust_2018_idioms)] 63 | 64 | mod decrypt; 65 | mod encrypt; 66 | 67 | pub use cipher; 68 | pub use decrypt::{BufDecryptor, Decryptor}; 69 | pub use encrypt::{BufEncryptor, Encryptor}; 70 | -------------------------------------------------------------------------------- /cfb-mode/tests/aes.rs: -------------------------------------------------------------------------------- 1 | use aes::*; 2 | use cfb_mode::{BufDecryptor, BufEncryptor, Decryptor, Encryptor}; 3 | use cipher::{KeyInit, block_mode_dec_test, block_mode_enc_test, iv_state_test}; 4 | 5 | iv_state_test!(aes128_cfb_enc_iv_state, Encryptor, encrypt); 6 | iv_state_test!(aes128_cfb_dec_iv_state, Decryptor, decrypt); 7 | iv_state_test!(aes192_cfb_enc_iv_state, Encryptor, encrypt); 8 | iv_state_test!(aes192_cfb_dec_iv_state, Decryptor, decrypt); 9 | iv_state_test!(aes256_cfb_enc_iv_state, Encryptor, encrypt); 10 | iv_state_test!(aes256_cfb_dec_iv_state, Decryptor, decrypt); 11 | 12 | // Test vectors from CVAP "AES Multiblock Message Test (MMT) Sample Vectors": 13 | // 14 | block_mode_enc_test!(aes128_cfb_enc_test, "aes128", Encryptor); 15 | block_mode_dec_test!(aes128_cfb_dec_test, "aes128", Decryptor); 16 | block_mode_enc_test!(aes128enc_cfb_enc_test, "aes128", Encryptor); 17 | block_mode_dec_test!(aes128enc_cfb_dec_test, "aes128", Decryptor); 18 | block_mode_enc_test!(aes192_cfb_enc_test, "aes192", Encryptor); 19 | block_mode_dec_test!(aes192_cfb_dec_test, "aes192", Decryptor); 20 | block_mode_enc_test!(aes192enc_cfb_enc_test, "aes192", Encryptor); 21 | block_mode_dec_test!(aes192dec_cfb_dec_test, "aes192", Decryptor); 22 | block_mode_enc_test!(aes256_cfb_enc_test, "aes256", Encryptor); 23 | block_mode_dec_test!(aes256_cfb_dec_test, "aes256", Decryptor); 24 | block_mode_enc_test!(aes256enc_cfb_enc_test, "aes256", Encryptor); 25 | block_mode_dec_test!(aes256dec_cfb_dec_test, "aes256", Decryptor); 26 | 27 | /// Test methods from the `AsyncStreamCipher` trait. 28 | #[test] 29 | fn aes128_cfb_async_test() { 30 | use cipher::{AsyncStreamCipher, KeyIvInit}; 31 | 32 | type Enc = Encryptor; 33 | type Dec = Decryptor; 34 | 35 | let key = [42; 16]; 36 | let iv = [24; 16]; 37 | let mut pt = [0u8; 101]; 38 | for (i, b) in pt.iter_mut().enumerate() { 39 | *b = (i % 11) as u8; 40 | } 41 | let enc = Enc::new_from_slices(&key, &iv).unwrap(); 42 | let mut ct = pt; 43 | enc.encrypt(&mut ct); 44 | for i in 1..100 { 45 | let enc = Enc::new_from_slices(&key, &iv).unwrap(); 46 | let mut t = pt; 47 | let t = &mut t[..i]; 48 | enc.encrypt(t); 49 | assert_eq!(t, &ct[..i]); 50 | 51 | let dec = Dec::new_from_slices(&key, &iv).unwrap(); 52 | dec.decrypt(t); 53 | assert_eq!(t, &pt[..i]); 54 | } 55 | } 56 | 57 | #[test] 58 | fn aes128_cfb_buffered_test() { 59 | use cipher::{AsyncStreamCipher, KeyIvInit}; 60 | 61 | type Enc = Encryptor; 62 | 63 | type BufEnc = BufEncryptor; 64 | type BufDec = BufDecryptor; 65 | 66 | let key = [42; 16]; 67 | let iv = [24; 16]; 68 | let mut pt = [0u8; 101]; 69 | for (i, b) in pt.iter_mut().enumerate() { 70 | *b = (i % 11) as u8; 71 | } 72 | 73 | // unbuffered 74 | let enc = Enc::new_from_slices(&key, &iv).unwrap(); 75 | let mut ct = pt; 76 | enc.encrypt(&mut ct); 77 | 78 | // buffered 79 | for i in 1..100 { 80 | let mut buf_enc = BufEnc::new_from_slices(&key, &iv).unwrap(); 81 | let mut ct2 = pt; 82 | for chunk in ct2.chunks_mut(i) { 83 | buf_enc.encrypt(chunk); 84 | } 85 | assert_eq!(ct2, ct); 86 | 87 | let mut buf_dec = BufDec::new_from_slices(&key, &iv).unwrap(); 88 | for chunk in ct2.chunks_mut(i) { 89 | buf_dec.decrypt(chunk); 90 | } 91 | assert_eq!(ct2, pt); 92 | } 93 | 94 | // buffered with restore 95 | for i in 1..100 { 96 | let mut buf_enc = BufEnc::new_from_slices(&key, &iv).unwrap(); 97 | let mut ct2 = pt; 98 | for chunk in ct2.chunks_mut(i) { 99 | let (iv, pos) = buf_enc.get_state(); 100 | let cipher = Aes128::new_from_slice(&key).unwrap(); 101 | buf_enc = BufEnc::from_state(cipher, iv, pos); 102 | 103 | buf_enc.encrypt(chunk); 104 | } 105 | assert_eq!(ct2, ct); 106 | 107 | let mut buf_dec = BufDec::new_from_slices(&key, &iv).unwrap(); 108 | for chunk in ct2.chunks_mut(i) { 109 | let (iv, pos) = buf_dec.get_state(); 110 | let cipher = Aes128::new_from_slice(&key).unwrap(); 111 | buf_dec = BufDec::from_state(cipher, iv, pos); 112 | 113 | buf_dec.decrypt(chunk); 114 | } 115 | assert_eq!(ct2, pt); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /cfb-mode/tests/belt.rs: -------------------------------------------------------------------------------- 1 | use belt_block::BeltBlock; 2 | use cfb_mode::{Decryptor, Encryptor}; 3 | use cipher::{block_mode_dec_test, block_mode_enc_test, iv_state_test}; 4 | 5 | iv_state_test!(belt_cfb_enc_iv_state, Encryptor, encrypt); 6 | iv_state_test!(belt_cfb_dec_iv_state, Decryptor, decrypt); 7 | 8 | // Test vectors from STB 34.101.31-2020 (tables А.13 and А.14): 9 | // 10 | block_mode_enc_test!(belt_cfb_enc_test, "belt", Encryptor); 11 | block_mode_dec_test!(belt_cfb_dec_test, "belt", Decryptor); 12 | -------------------------------------------------------------------------------- /cfb-mode/tests/data/aes128.blb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RustCrypto/block-modes/e52ed9c70aa22b8dd07285f4b15981f137960cd5/cfb-mode/tests/data/aes128.blb -------------------------------------------------------------------------------- /cfb-mode/tests/data/aes192.blb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RustCrypto/block-modes/e52ed9c70aa22b8dd07285f4b15981f137960cd5/cfb-mode/tests/data/aes192.blb -------------------------------------------------------------------------------- /cfb-mode/tests/data/aes256.blb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RustCrypto/block-modes/e52ed9c70aa22b8dd07285f4b15981f137960cd5/cfb-mode/tests/data/aes256.blb -------------------------------------------------------------------------------- /cfb-mode/tests/data/belt.blb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RustCrypto/block-modes/e52ed9c70aa22b8dd07285f4b15981f137960cd5/cfb-mode/tests/data/belt.blb -------------------------------------------------------------------------------- /cfb8/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## 0.9.0 (UNRELEASED) 9 | ### Removed 10 | - `std` feature ([#76]) 11 | 12 | ### Changed 13 | - Bump `cipher` from `0.4` to `0.5` ([#56]) 14 | - Edition changed to 2024 and MSRV bumped to 1.85 ([#76]) 15 | - Relax MSRV policy and allow MSRV bumps in patch releases 16 | 17 | [#56]: https://github.com/RustCrypto/block-modes/pull/56 18 | [#75]: https://github.com/RustCrypto/block-modes/pull/76 19 | 20 | ## 0.8.1 (2022-02-17) 21 | ### Fixed 22 | - Minimal versions build ([#9]) 23 | 24 | [#9]: https://github.com/RustCrypto/block-modes/pull/9 25 | 26 | ## 0.8.0 (2022-02-10) 27 | ### Changed 28 | - Update `cipher` dependency to v0.4 and move crate 29 | to the [RustCrypto/block-modes] repository ([#2]) 30 | 31 | [#2]: https://github.com/RustCrypto/block-modes/pull/2 32 | [RustCrypto/block-modes]: https://github.com/RustCrypto/block-modes 33 | 34 | ## 0.7.1 (2021-04-30) 35 | ### Changed 36 | - Removed redundant `NewBlockCipher` boundfrom `FromBlockCipher` implementation ([#236]) 37 | 38 | [#236]: https://github.com/RustCrypto/stream-ciphers/pull/236 39 | 40 | ## 0.7.0 (2021-04-29) 41 | ### Changed 42 | - Bump `cipher` dependency to v0.3 release ([#226]) 43 | - Bump `aes` dev dependency to v0.7 release ([#232]) 44 | 45 | [#226]: https://github.com/RustCrypto/stream-ciphers/pull/226 46 | [#232]: https://github.com/RustCrypto/stream-ciphers/pull/232 47 | 48 | ## 0.6.0 (2020-10-16) 49 | ### Changed 50 | - Replace `block-cipher`/`stream-cipher` with `cipher` crate ([#177]) 51 | 52 | [#177]: https://github.com/RustCrypto/stream-ciphers/pull/177 53 | 54 | ## 0.5.0 (2020-08-25) 55 | ### Changed 56 | - Bump `stream-cipher` dependency to v0.7, implement the `FromBlockCipher` trait ([#161], [#164]) 57 | 58 | [#161]: https://github.com/RustCrypto/stream-ciphers/pull/161 59 | [#164]: https://github.com/RustCrypto/stream-ciphers/pull/164 60 | 61 | ## 0.4.0 (2020-06-08) 62 | ### Changed 63 | - Bump `stream-cipher` dependency to v0.4 ([#120]) 64 | - Upgrade to Rust 2018 edition ([#120]) 65 | 66 | [#120]: https://github.com/RustCrypto/stream-ciphers/pull/120 67 | 68 | ## 0.3.2 (2019-03-11) 69 | 70 | ## 0.3.1 (2018-11-01) 71 | 72 | ## 0.3.0 (2018-11-01) 73 | 74 | ## 0.1.0 (2018-11-01) 75 | -------------------------------------------------------------------------------- /cfb8/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cfb8" 3 | version = "0.9.0-rc.0" 4 | description = "Cipher Feedback with eight bit feedback (CFB-8) block cipher mode of operation" 5 | authors = ["RustCrypto Developers"] 6 | license = "MIT OR Apache-2.0" 7 | edition = "2024" 8 | rust-version = "1.85" 9 | readme = "README.md" 10 | documentation = "https://docs.rs/cfb8" 11 | repository = "https://github.com/RustCrypto/block-modes" 12 | keywords = ["crypto", "block-mode", "stream-cipher", "ciphers"] 13 | categories = ["cryptography", "no-std"] 14 | 15 | [dependencies] 16 | cipher = "0.5.0-rc.0" 17 | 18 | [dev-dependencies] 19 | aes = "0.9.0-rc.0" 20 | cipher = { version = "0.5.0-rc.0", features = ["dev"] } 21 | hex-literal = "1" 22 | 23 | [features] 24 | alloc = ["cipher/alloc"] 25 | block-padding = ["cipher/block-padding"] 26 | zeroize = ["cipher/zeroize"] 27 | 28 | [package.metadata.docs.rs] 29 | all-features = true 30 | rustdoc-args = ["--cfg", "docsrs"] 31 | -------------------------------------------------------------------------------- /cfb8/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018-2022 RustCrypto Developers 2 | Copyright (c) 2018 Artyom Pavlov 3 | 4 | Permission is hereby granted, free of charge, to any 5 | person obtaining a copy of this software and associated 6 | documentation files (the "Software"), to deal in the 7 | Software without restriction, including without 8 | limitation the rights to use, copy, modify, merge, 9 | publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software 11 | is furnished to do so, subject to the following 12 | conditions: 13 | 14 | The above copyright notice and this permission notice 15 | shall be included in all copies or substantial portions 16 | of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 19 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 20 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 21 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 22 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 23 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 25 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 | DEALINGS IN THE SOFTWARE. 27 | -------------------------------------------------------------------------------- /cfb8/README.md: -------------------------------------------------------------------------------- 1 | # RustCrypto: CFB-8 2 | 3 | [![crate][crate-image]][crate-link] 4 | [![Docs][docs-image]][docs-link] 5 | [![Build Status][build-image]][build-link] 6 | ![Apache2/MIT licensed][license-image] 7 | ![Rust Version][rustc-image] 8 | [![Project Chat][chat-image]][chat-link] 9 | 10 | Generic implementation of the [Cipher Feedback][CFB-8] with eight bit 11 | feedback (CFB-8) block cipher mode of operation. 12 | 13 | 14 | 15 | See [documentation][cipher-doc] of the `cipher` crate for additional information. 16 | 17 | ## License 18 | 19 | Licensed under either of: 20 | 21 | * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) 22 | * [MIT license](http://opensource.org/licenses/MIT) 23 | 24 | at your option. 25 | 26 | ### Contribution 27 | 28 | Unless you explicitly state otherwise, any contribution intentionally submitted 29 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be 30 | dual licensed as above, without any additional terms or conditions. 31 | 32 | [//]: # (badges) 33 | 34 | [crate-image]: https://img.shields.io/crates/v/cfb8.svg?logo=rust 35 | [crate-link]: https://crates.io/crates/cfb8 36 | [docs-image]: https://docs.rs/cfb8/badge.svg 37 | [docs-link]: https://docs.rs/cfb8/ 38 | [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg 39 | [rustc-image]: https://img.shields.io/badge/rustc-1.85+-blue.svg 40 | [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg 41 | [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/308460-block-modes 42 | [build-image]: https://github.com/RustCrypto/block-modes/actions/workflows/cfb8.yaml/badge.svg 43 | [build-link]: https://github.com/RustCrypto/block-modes/actions/workflows/cfb8.yaml 44 | 45 | [//]: # (general links) 46 | 47 | [CFB]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#CFB-1,_CFB-8,_CFB-64,_CFB-128,_etc. 48 | [cipher-doc]: https://docs.rs/cipher/ 49 | -------------------------------------------------------------------------------- /cfb8/benches/aes128.rs: -------------------------------------------------------------------------------- 1 | #![feature(test)] 2 | extern crate test; 3 | 4 | use aes::Aes128; 5 | 6 | cipher::block_encryptor_bench!( 7 | KeyIv: cfb8::Encryptor, 8 | cfb8_aes128_encrypt_block, 9 | cfb8_aes128_encrypt_blocks, 10 | ); 11 | 12 | cipher::block_decryptor_bench!( 13 | KeyIv: cfb8::Decryptor, 14 | cfb8_aes128_decrypt_block, 15 | cfb8_aes128_decrypt_blocks, 16 | ); 17 | -------------------------------------------------------------------------------- /cfb8/src/decrypt.rs: -------------------------------------------------------------------------------- 1 | use cipher::{ 2 | AlgorithmName, AsyncStreamCipher, Block, BlockCipherEncBackend, BlockCipherEncClosure, 3 | BlockCipherEncrypt, BlockModeDecBackend, BlockModeDecClosure, BlockModeDecrypt, BlockSizeUser, 4 | InnerIvInit, Iv, IvState, ParBlocksSizeUser, 5 | array::Array, 6 | consts::U1, 7 | crypto_common::{BlockSizes, InnerUser, IvSizeUser}, 8 | inout::InOut, 9 | }; 10 | use core::fmt; 11 | 12 | #[cfg(feature = "zeroize")] 13 | use cipher::zeroize::{Zeroize, ZeroizeOnDrop}; 14 | 15 | /// CFB-8 mode decryptor. 16 | #[derive(Clone)] 17 | pub struct Decryptor 18 | where 19 | C: BlockCipherEncrypt, 20 | { 21 | cipher: C, 22 | iv: Block, 23 | } 24 | 25 | impl BlockSizeUser for Decryptor 26 | where 27 | C: BlockCipherEncrypt, 28 | { 29 | type BlockSize = U1; 30 | } 31 | 32 | impl BlockModeDecrypt for Decryptor 33 | where 34 | C: BlockCipherEncrypt, 35 | { 36 | fn decrypt_with_backend(&mut self, f: impl BlockModeDecClosure) { 37 | struct Closure<'a, BS, BC> 38 | where 39 | BS: BlockSizes, 40 | BC: BlockModeDecClosure, 41 | { 42 | iv: &'a mut Array, 43 | f: BC, 44 | } 45 | 46 | impl BlockSizeUser for Closure<'_, BS, BC> 47 | where 48 | BS: BlockSizes, 49 | BC: BlockModeDecClosure, 50 | { 51 | type BlockSize = BS; 52 | } 53 | 54 | impl BlockCipherEncClosure for Closure<'_, BS, BC> 55 | where 56 | BS: BlockSizes, 57 | BC: BlockModeDecClosure, 58 | { 59 | #[inline(always)] 60 | fn call>(self, backend: &B) { 61 | let Self { iv, f } = self; 62 | f.call(&mut Backend { iv, backend }); 63 | } 64 | } 65 | 66 | let Self { cipher, iv } = self; 67 | cipher.encrypt_with_backend(Closure { iv, f }) 68 | } 69 | } 70 | 71 | impl AsyncStreamCipher for Decryptor {} 72 | 73 | impl InnerUser for Decryptor 74 | where 75 | C: BlockCipherEncrypt, 76 | { 77 | type Inner = C; 78 | } 79 | 80 | impl IvSizeUser for Decryptor 81 | where 82 | C: BlockCipherEncrypt, 83 | { 84 | type IvSize = C::BlockSize; 85 | } 86 | 87 | impl InnerIvInit for Decryptor 88 | where 89 | C: BlockCipherEncrypt, 90 | { 91 | #[inline] 92 | fn inner_iv_init(cipher: C, iv: &Iv) -> Self { 93 | let iv = iv.clone(); 94 | Self { cipher, iv } 95 | } 96 | } 97 | 98 | impl IvState for Decryptor 99 | where 100 | C: BlockCipherEncrypt, 101 | { 102 | #[inline] 103 | fn iv_state(&self) -> Iv { 104 | self.iv.clone() 105 | } 106 | } 107 | 108 | impl AlgorithmName for Decryptor 109 | where 110 | C: BlockCipherEncrypt + AlgorithmName, 111 | { 112 | fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { 113 | f.write_str("cfb8::Decryptor<")?; 114 | ::write_alg_name(f)?; 115 | f.write_str(">") 116 | } 117 | } 118 | 119 | impl fmt::Debug for Decryptor 120 | where 121 | C: BlockCipherEncrypt + AlgorithmName, 122 | { 123 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 124 | f.write_str("cfb8::Decryptor<")?; 125 | ::write_alg_name(f)?; 126 | f.write_str("> { ... }") 127 | } 128 | } 129 | 130 | impl Drop for Decryptor { 131 | fn drop(&mut self) { 132 | #[cfg(feature = "zeroize")] 133 | self.iv.zeroize(); 134 | } 135 | } 136 | 137 | #[cfg(feature = "zeroize")] 138 | impl ZeroizeOnDrop for Decryptor {} 139 | 140 | struct Backend<'a, BS, BK> 141 | where 142 | BS: BlockSizes, 143 | BK: BlockCipherEncBackend, 144 | { 145 | iv: &'a mut Array, 146 | backend: &'a BK, 147 | } 148 | 149 | impl BlockSizeUser for Backend<'_, BS, BK> 150 | where 151 | BS: BlockSizes, 152 | BK: BlockCipherEncBackend, 153 | { 154 | type BlockSize = U1; 155 | } 156 | 157 | impl ParBlocksSizeUser for Backend<'_, BS, BK> 158 | where 159 | BS: BlockSizes, 160 | BK: BlockCipherEncBackend, 161 | { 162 | type ParBlocksSize = U1; 163 | } 164 | 165 | impl BlockModeDecBackend for Backend<'_, BS, BK> 166 | where 167 | BS: BlockSizes, 168 | BK: BlockCipherEncBackend, 169 | { 170 | #[inline(always)] 171 | fn decrypt_block(&mut self, mut block: InOut<'_, '_, Block>) { 172 | let mut t = self.iv.clone(); 173 | self.backend.encrypt_block((&mut t).into()); 174 | let r = block.get(0).clone_in(); 175 | let k: &Array = t[..1].try_into().unwrap(); 176 | block.xor_in2out(k); 177 | let n = self.iv.len(); 178 | for i in 0..n - 1 { 179 | self.iv[i] = self.iv[i + 1]; 180 | } 181 | self.iv[n - 1] = r; 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /cfb8/src/encrypt.rs: -------------------------------------------------------------------------------- 1 | use cipher::{ 2 | AlgorithmName, AsyncStreamCipher, Block, BlockCipherEncBackend, BlockCipherEncClosure, 3 | BlockCipherEncrypt, BlockModeEncBackend, BlockModeEncClosure, BlockModeEncrypt, BlockSizeUser, 4 | InnerIvInit, Iv, IvState, ParBlocksSizeUser, 5 | array::Array, 6 | consts::U1, 7 | crypto_common::{BlockSizes, InnerUser, IvSizeUser}, 8 | inout::InOut, 9 | }; 10 | use core::fmt; 11 | 12 | #[cfg(feature = "zeroize")] 13 | use cipher::zeroize::{Zeroize, ZeroizeOnDrop}; 14 | 15 | /// CFB-8 mode encryptor. 16 | #[derive(Clone)] 17 | pub struct Encryptor 18 | where 19 | C: BlockCipherEncrypt, 20 | { 21 | cipher: C, 22 | iv: Block, 23 | } 24 | 25 | impl BlockSizeUser for Encryptor 26 | where 27 | C: BlockCipherEncrypt, 28 | { 29 | type BlockSize = U1; 30 | } 31 | 32 | impl BlockModeEncrypt for Encryptor 33 | where 34 | C: BlockCipherEncrypt, 35 | { 36 | fn encrypt_with_backend(&mut self, f: impl BlockModeEncClosure) { 37 | struct Closure<'a, BS, BC> 38 | where 39 | BS: BlockSizes, 40 | BC: BlockModeEncClosure, 41 | { 42 | iv: &'a mut Array, 43 | f: BC, 44 | } 45 | 46 | impl BlockSizeUser for Closure<'_, BS, BC> 47 | where 48 | BS: BlockSizes, 49 | BC: BlockModeEncClosure, 50 | { 51 | type BlockSize = BS; 52 | } 53 | 54 | impl BlockCipherEncClosure for Closure<'_, BS, BC> 55 | where 56 | BS: BlockSizes, 57 | BC: BlockModeEncClosure, 58 | { 59 | #[inline(always)] 60 | fn call>(self, backend: &B) { 61 | let Self { iv, f } = self; 62 | f.call(&mut Backend { iv, backend }); 63 | } 64 | } 65 | 66 | let Self { cipher, iv } = self; 67 | cipher.encrypt_with_backend(Closure { iv, f }) 68 | } 69 | } 70 | 71 | impl AsyncStreamCipher for Encryptor {} 72 | 73 | impl InnerUser for Encryptor 74 | where 75 | C: BlockCipherEncrypt, 76 | { 77 | type Inner = C; 78 | } 79 | 80 | impl IvSizeUser for Encryptor 81 | where 82 | C: BlockCipherEncrypt, 83 | { 84 | type IvSize = C::BlockSize; 85 | } 86 | 87 | impl InnerIvInit for Encryptor 88 | where 89 | C: BlockCipherEncrypt, 90 | { 91 | #[inline] 92 | fn inner_iv_init(cipher: C, iv: &Iv) -> Self { 93 | let iv = iv.clone(); 94 | Self { cipher, iv } 95 | } 96 | } 97 | 98 | impl IvState for Encryptor 99 | where 100 | C: BlockCipherEncrypt, 101 | { 102 | #[inline] 103 | fn iv_state(&self) -> Iv { 104 | self.iv.clone() 105 | } 106 | } 107 | 108 | impl AlgorithmName for Encryptor 109 | where 110 | C: BlockCipherEncrypt + AlgorithmName, 111 | { 112 | fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { 113 | f.write_str("cfb8::Encryptor<")?; 114 | ::write_alg_name(f)?; 115 | f.write_str(">") 116 | } 117 | } 118 | 119 | impl fmt::Debug for Encryptor 120 | where 121 | C: BlockCipherEncrypt + AlgorithmName, 122 | { 123 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 124 | f.write_str("cfb8::Encryptor<")?; 125 | ::write_alg_name(f)?; 126 | f.write_str("> { ... }") 127 | } 128 | } 129 | 130 | impl Drop for Encryptor { 131 | fn drop(&mut self) { 132 | #[cfg(feature = "zeroize")] 133 | self.iv.zeroize(); 134 | } 135 | } 136 | 137 | #[cfg(feature = "zeroize")] 138 | impl ZeroizeOnDrop for Encryptor {} 139 | 140 | struct Backend<'a, BS, BK> 141 | where 142 | BS: BlockSizes, 143 | BK: BlockCipherEncBackend, 144 | { 145 | iv: &'a mut Array, 146 | backend: &'a BK, 147 | } 148 | 149 | impl BlockSizeUser for Backend<'_, BS, BK> 150 | where 151 | BS: BlockSizes, 152 | BK: BlockCipherEncBackend, 153 | { 154 | type BlockSize = U1; 155 | } 156 | 157 | impl ParBlocksSizeUser for Backend<'_, BS, BK> 158 | where 159 | BS: BlockSizes, 160 | BK: BlockCipherEncBackend, 161 | { 162 | type ParBlocksSize = U1; 163 | } 164 | 165 | impl BlockModeEncBackend for Backend<'_, BS, BK> 166 | where 167 | BS: BlockSizes, 168 | BK: BlockCipherEncBackend, 169 | { 170 | #[inline(always)] 171 | fn encrypt_block(&mut self, mut block: InOut<'_, '_, Block>) { 172 | let mut t = self.iv.clone(); 173 | self.backend.encrypt_block((&mut t).into()); 174 | let k: &Array = t[..1].try_into().unwrap(); 175 | block.xor_in2out(k); 176 | let r = block.get_out()[0]; 177 | let n = self.iv.len(); 178 | for i in 0..n - 1 { 179 | self.iv[i] = self.iv[i + 1]; 180 | } 181 | self.iv[n - 1] = r; 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /cfb8/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! [Cipher Feedback with eight bit feedback][1] (CFB-8) mode. 2 | //! 3 | //! 4 | //! 5 | //! 6 | //! Mode functionality is accessed using traits from re-exported [`cipher`] crate. 7 | //! 8 | //! # ⚠️ Security Warning: Hazmat! 9 | //! 10 | //! This crate does not ensure ciphertexts are authentic! Thus ciphertext integrity 11 | //! is not verified, which can lead to serious vulnerabilities! 12 | //! [AEADs][https://github.com/RustCrypto/AEADs] provide simple authenticated encryption, 13 | //! which is much less error-prone than manual integrity verification. 14 | //! 15 | //! # Example 16 | //! ``` 17 | //! use aes::cipher::{AsyncStreamCipher, KeyIvInit}; 18 | //! use hex_literal::hex; 19 | //! 20 | //! type Aes128Cfb8Enc = cfb8::Encryptor; 21 | //! type Aes128Cfb8Dec = cfb8::Decryptor; 22 | //! 23 | //! let key = [0x42; 16]; 24 | //! let iv = [0x24; 16]; 25 | //! let plaintext = *b"hello world! this is my plaintext."; 26 | //! let ciphertext = hex!( 27 | //! "33b356ce9184290c4c8facc1c0b1f918d5475aeb75b88c161ca65bdf05c7137ff4b0" 28 | //! ); 29 | //! 30 | //! // encrypt/decrypt in-place 31 | //! let mut buf = plaintext.to_vec(); 32 | //! Aes128Cfb8Enc::new(&key.into(), &iv.into()).encrypt(&mut buf); 33 | //! assert_eq!(buf[..], ciphertext[..]); 34 | //! 35 | //! Aes128Cfb8Dec::new(&key.into(), &iv.into()).decrypt(&mut buf); 36 | //! assert_eq!(buf[..], plaintext[..]); 37 | //! 38 | //! // encrypt/decrypt from buffer to buffer 39 | //! // buffer length must be equal to input length 40 | //! let mut buf1 = [0u8; 34]; 41 | //! Aes128Cfb8Enc::new(&key.into(), &iv.into()) 42 | //! .encrypt_b2b(&plaintext, &mut buf1) 43 | //! .unwrap(); 44 | //! assert_eq!(buf1[..], ciphertext[..]); 45 | //! 46 | //! let mut buf2 = [0u8; 34]; 47 | //! Aes128Cfb8Dec::new(&key.into(), &iv.into()) 48 | //! .decrypt_b2b(&buf1, &mut buf2) 49 | //! .unwrap(); 50 | //! assert_eq!(buf2[..], plaintext[..]); 51 | //! ``` 52 | //! 53 | //! [1]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#CFB-1,_CFB-8,_CFB-64,_CFB-128,_etc. 54 | 55 | #![no_std] 56 | #![doc( 57 | html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", 58 | html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg" 59 | )] 60 | #![forbid(unsafe_code)] 61 | #![cfg_attr(docsrs, feature(doc_auto_cfg))] 62 | #![warn(missing_debug_implementations, missing_docs, rust_2018_idioms)] 63 | 64 | mod decrypt; 65 | mod encrypt; 66 | 67 | pub use cipher; 68 | pub use decrypt::Decryptor; 69 | pub use encrypt::Encryptor; 70 | -------------------------------------------------------------------------------- /cfb8/tests/aes.rs: -------------------------------------------------------------------------------- 1 | use aes::*; 2 | use cfb8::{Decryptor, Encryptor}; 3 | use cipher::{block_mode_dec_test, block_mode_enc_test, iv_state_test}; 4 | 5 | iv_state_test!(aes128_cfb8_enc_iv_state, Encryptor, encrypt); 6 | iv_state_test!(aes128_cfb8_dec_iv_state, Decryptor, decrypt); 7 | iv_state_test!(aes192_cfb8_enc_iv_state, Encryptor, encrypt); 8 | iv_state_test!(aes192_cfb8_dec_iv_state, Decryptor, decrypt); 9 | iv_state_test!(aes256_cfb8_enc_iv_state, Encryptor, encrypt); 10 | iv_state_test!(aes256_cfb8_dec_iv_state, Decryptor, decrypt); 11 | 12 | // Test vectors from CVAP "AES Multiblock Message Test (MMT) Sample Vectors": 13 | // 14 | block_mode_enc_test!(aes128_cfb8_enc_test, "aes128", Encryptor); 15 | block_mode_dec_test!(aes128_cfb8_dec_test, "aes128", Decryptor); 16 | block_mode_enc_test!(aes128enc_cfb8_enc_test, "aes128", Encryptor); 17 | block_mode_dec_test!(aes128enc_cfb8_dec_test, "aes128", Decryptor); 18 | block_mode_enc_test!(aes192_cfb8_enc_test, "aes192", Encryptor); 19 | block_mode_dec_test!(aes192_cfb8_dec_test, "aes192", Decryptor); 20 | block_mode_enc_test!(aes192enc_cfb8_enc_test, "aes192", Encryptor); 21 | block_mode_dec_test!(aes192dec_cfb8_dec_test, "aes192", Decryptor); 22 | block_mode_enc_test!(aes256_cfb8_enc_test, "aes256", Encryptor); 23 | block_mode_dec_test!(aes256_cfb8_dec_test, "aes256", Decryptor); 24 | block_mode_enc_test!(aes256enc_cfb8_enc_test, "aes256", Encryptor); 25 | block_mode_dec_test!(aes256dec_cfb8_dec_test, "aes256", Decryptor); 26 | 27 | /// Test methods from the `AsyncStreamCipher` trait. 28 | #[test] 29 | fn aes128_cfb8_async_test() { 30 | use cipher::{AsyncStreamCipher, KeyIvInit}; 31 | 32 | type Enc = Encryptor; 33 | type Dec = Decryptor; 34 | 35 | let key = [42; 16]; 36 | let iv = [24; 16]; 37 | let mut pt = [0u8; 101]; 38 | for (i, b) in pt.iter_mut().enumerate() { 39 | *b = (i % 11) as u8; 40 | } 41 | let enc = Enc::new_from_slices(&key, &iv).unwrap(); 42 | let mut ct = pt; 43 | enc.encrypt(&mut ct); 44 | for i in 1..100 { 45 | let enc = Enc::new_from_slices(&key, &iv).unwrap(); 46 | let mut t = pt; 47 | let t = &mut t[..i]; 48 | enc.encrypt(t); 49 | assert_eq!(t, &ct[..i]); 50 | 51 | let dec = Dec::new_from_slices(&key, &iv).unwrap(); 52 | dec.decrypt(t); 53 | assert_eq!(t, &pt[..i]); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /cfb8/tests/data/aes128.blb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RustCrypto/block-modes/e52ed9c70aa22b8dd07285f4b15981f137960cd5/cfb8/tests/data/aes128.blb -------------------------------------------------------------------------------- /cfb8/tests/data/aes192.blb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RustCrypto/block-modes/e52ed9c70aa22b8dd07285f4b15981f137960cd5/cfb8/tests/data/aes192.blb -------------------------------------------------------------------------------- /cfb8/tests/data/aes256.blb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RustCrypto/block-modes/e52ed9c70aa22b8dd07285f4b15981f137960cd5/cfb8/tests/data/aes256.blb -------------------------------------------------------------------------------- /ctr/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## 0.10.0 (UNRELEASED) 9 | ### Removed 10 | - `std` feature ([#76]) 11 | 12 | ### Changed 13 | - Bump `cipher` from `0.4` to `0.5` ([#56]) 14 | - Edition changed to 2024 and MSRV bumped to 1.85 ([#76]) 15 | - Relax MSRV policy and allow MSRV bumps in patch releases 16 | 17 | [#56]: https://github.com/RustCrypto/block-modes/pull/56 18 | [#76]: https://github.com/RustCrypto/block-modes/pull/76 19 | 20 | 21 | ## 0.9.2 (2022-09-30) 22 | ### Changed 23 | - Implement `Clone` directly for `CtrCore`, so it would work with non-`Clone` flavors ([#24]) 24 | 25 | [#24]: https://github.com/RustCrypto/block-modes/pull/24 26 | 27 | ## 0.9.1 (2022-02-17) 28 | ### Fixed 29 | - Minimal versions build ([#9]) 30 | 31 | [#9]: https://github.com/RustCrypto/block-modes/pull/9 32 | 33 | ## 0.9.0 (2022-02-10) 34 | ### Changed 35 | - Update `cipher` dependency to v0.4 and move crate 36 | to the [RustCrypto/block-modes] repository ([#2]) 37 | 38 | [#2]: https://github.com/RustCrypto/block-modes/pull/2 39 | [RustCrypto/block-modes]: https://github.com/RustCrypto/block-modes 40 | 41 | ## 0.8.0 (2021-07-08) 42 | ### Changed 43 | - Make implementation generic over block size (previously it 44 | was generic only over 128-bit block ciphers). Breaking changes 45 | in the `CtrFlavor` API. ([#252]). 46 | 47 | [#252]: https://github.com/RustCrypto/stream-ciphers/pull/252 48 | 49 | ## 0.7.0 (2020-04-29) 50 | ### Changed 51 | - Generic implementation of CTR ([#195]) 52 | - Removed `Ctr32LE` mask bit ([#197]) 53 | - Bump `cipher` dependency to v0.3 ([#226]) 54 | 55 | [#195]: https://github.com/RustCrypto/stream-ciphers/pull/195 56 | [#197]: https://github.com/RustCrypto/stream-ciphers/pull/197 57 | [#226]: https://github.com/RustCrypto/stream-ciphers/pull/226 58 | 59 | ## 0.6.0 (2020-10-16) 60 | ### Added 61 | - `Ctr32BE` and `Ctr32LE` ([#170]) 62 | 63 | ### Changed 64 | - Replace `block-cipher`/`stream-cipher` with `cipher` crate ([#177]) 65 | 66 | [#177]: https://github.com/RustCrypto/stream-ciphers/pull/177 67 | [#170]: https://github.com/RustCrypto/stream-ciphers/pull/170 68 | 69 | ## 0.5.0 (2020-08-26) 70 | ### Changed 71 | - Bump `stream-cipher` dependency to v0.7, implement the `FromBlockCipher` trait ([#161], [#164]) 72 | 73 | [#161]: https://github.com/RustCrypto/stream-ciphers/pull/161 74 | [#164]: https://github.com/RustCrypto/stream-ciphers/pull/164 75 | 76 | ## 0.4.0 (2020-06-06) 77 | ### Changed 78 | - Upgrade to the `stream-cipher` v0.4 crate ([#116], [#138]) 79 | - Upgrade to Rust 2018 edition ([#116]) 80 | 81 | [#138]: https://github.com/RustCrypto/stream-ciphers/pull/138 82 | [#116]: https://github.com/RustCrypto/stream-ciphers/pull/121 83 | 84 | ## 0.3.2 (2019-03-11) 85 | 86 | ## 0.3.0 (2018-11-01) 87 | 88 | ## 0.2.0 (2018-10-13) 89 | 90 | ## 0.1.1 (2018-10-13) 91 | 92 | ## 0.1.0 (2018-07-30) 93 | -------------------------------------------------------------------------------- /ctr/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ctr" 3 | version = "0.10.0-rc.0" 4 | description = "CTR block modes of operation" 5 | authors = ["RustCrypto Developers"] 6 | license = "MIT OR Apache-2.0" 7 | edition = "2024" 8 | rust-version = "1.85" 9 | readme = "README.md" 10 | documentation = "https://docs.rs/ctr" 11 | repository = "https://github.com/RustCrypto/block-modes" 12 | keywords = ["crypto", "block-mode", "stream-cipher", "ciphers"] 13 | categories = ["cryptography", "no-std"] 14 | 15 | [dependencies] 16 | cipher = "0.5.0-rc.0" 17 | 18 | [dev-dependencies] 19 | aes = "0.9.0-rc.0" 20 | magma = "0.10.0-rc.0" 21 | kuznyechik = "0.9.0-rc.0" 22 | cipher = { version = "0.5.0-rc.0", features = ["dev"] } 23 | hex-literal = "1" 24 | 25 | [features] 26 | alloc = ["cipher/alloc"] 27 | block-padding = ["cipher/block-padding"] 28 | zeroize = ["cipher/zeroize"] 29 | 30 | [package.metadata.docs.rs] 31 | all-features = true 32 | rustdoc-args = ["--cfg", "docsrs"] 33 | -------------------------------------------------------------------------------- /ctr/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018-2022 RustCrypto Developers 2 | Copyright (c) 2018 Artyom Pavlov 3 | 4 | Permission is hereby granted, free of charge, to any 5 | person obtaining a copy of this software and associated 6 | documentation files (the "Software"), to deal in the 7 | Software without restriction, including without 8 | limitation the rights to use, copy, modify, merge, 9 | publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software 11 | is furnished to do so, subject to the following 12 | conditions: 13 | 14 | The above copyright notice and this permission notice 15 | shall be included in all copies or substantial portions 16 | of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 19 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 20 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 21 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 22 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 23 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 25 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 | DEALINGS IN THE SOFTWARE. 27 | -------------------------------------------------------------------------------- /ctr/README.md: -------------------------------------------------------------------------------- 1 | # RustCrypto: CTR 2 | 3 | [![crate][crate-image]][crate-link] 4 | [![Docs][docs-image]][docs-link] 5 | ![Apache2/MIT licensed][license-image] 6 | [![Build Status][build-image]][build-link] 7 | ![Rust Version][rustc-image] 8 | [![Project Chat][chat-image]][chat-link] 9 | 10 | Generic implementation of the [Counter][CTR] (CTR) block cipher mode of operation. 11 | 12 | 13 | 14 | See [documentation][cipher-doc] of the `cipher` crate for additional information. 15 | 16 | ## License 17 | 18 | Licensed under either of: 19 | 20 | * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) 21 | * [MIT license](http://opensource.org/licenses/MIT) 22 | 23 | at your option. 24 | 25 | ### Contribution 26 | 27 | Unless you explicitly state otherwise, any contribution intentionally submitted 28 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be 29 | dual licensed as above, without any additional terms or conditions. 30 | 31 | [//]: # (badges) 32 | 33 | [crate-image]: https://img.shields.io/crates/v/ctr.svg?logo=rust 34 | [crate-link]: https://crates.io/crates/ctr 35 | [docs-image]: https://docs.rs/ctr/badge.svg 36 | [docs-link]: https://docs.rs/ctr/ 37 | [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg 38 | [rustc-image]: https://img.shields.io/badge/rustc-1.85+-blue.svg 39 | [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg 40 | [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/308460-block-modes 41 | [build-image]: https://github.com/RustCrypto/block-modes/actions/workflows/ctr.yaml/badge.svg 42 | [build-link]: https://github.com/RustCrypto/block-modes/actions/workflows/ctr.yaml 43 | 44 | [//]: # (general links) 45 | 46 | [CTR]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_(CTR) 47 | [cipher-doc]: https://docs.rs/cipher/ 48 | -------------------------------------------------------------------------------- /ctr/benches/aes128.rs: -------------------------------------------------------------------------------- 1 | #![feature(test)] 2 | extern crate test; 3 | 4 | cipher::stream_cipher_bench!( 5 | ctr::Ctr32LE; 6 | ctr_32le_aes128_stream_bench1_16b 16; 7 | ctr_32le_aes128_stream_bench2_256b 256; 8 | ctr_32le_aes128_stream_bench3_1kib 1024; 9 | ctr_32le_aes128_stream_bench4_16kib 16384; 10 | ); 11 | 12 | cipher::stream_cipher_bench!( 13 | ctr::Ctr64LE; 14 | ctr_64le_aes128_stream_bench1_16b 16; 15 | ctr_64le_aes128_stream_bench2_256b 256; 16 | ctr_64le_aes128_stream_bench3_1kib 1024; 17 | ctr_64le_aes128_stream_bench4_16kib 16384; 18 | ); 19 | 20 | cipher::stream_cipher_bench!( 21 | ctr::Ctr128BE; 22 | ctr_128be_aes128_stream_bench1_16b 16; 23 | ctr_128be_aes128_stream_bench2_256b 256; 24 | ctr_128be_aes128_stream_bench3_1kib 1024; 25 | ctr_128be_aes128_stream_bench4_16kib 16384; 26 | ); 27 | -------------------------------------------------------------------------------- /ctr/src/flavors.rs: -------------------------------------------------------------------------------- 1 | //! CTR mode flavors 2 | 3 | use cipher::{ 4 | StreamCipherCounter, 5 | array::{Array, ArraySize}, 6 | }; 7 | 8 | mod ctr128; 9 | mod ctr32; 10 | mod ctr64; 11 | 12 | pub use ctr32::{Ctr32BE, Ctr32LE}; 13 | pub use ctr64::{Ctr64BE, Ctr64LE}; 14 | pub use ctr128::{Ctr128BE, Ctr128LE}; 15 | 16 | /// Trait implemented by different CTR flavors. 17 | pub trait CtrFlavor { 18 | /// Inner representation of nonce. 19 | type CtrNonce: Clone; 20 | /// Backend numeric type 21 | type Backend: StreamCipherCounter; 22 | /// Flavor name 23 | const NAME: &'static str; 24 | 25 | /// Return number of remaining blocks. 26 | /// 27 | /// If result does not fit into `usize`, returns `None`. 28 | fn remaining(cn: &Self::CtrNonce) -> Option; 29 | 30 | /// Generate block for given `nonce` and current counter value. 31 | fn next_block(cn: &mut Self::CtrNonce) -> Array; 32 | 33 | /// Generate block for given `nonce` and current counter value. 34 | fn current_block(cn: &Self::CtrNonce) -> Array; 35 | 36 | /// Initialize from bytes. 37 | fn from_nonce(block: &Array) -> Self::CtrNonce; 38 | 39 | /// Convert from a backend value 40 | fn set_from_backend(cn: &mut Self::CtrNonce, v: Self::Backend); 41 | 42 | /// Convert to a backend value 43 | fn as_backend(cn: &Self::CtrNonce) -> Self::Backend; 44 | } 45 | -------------------------------------------------------------------------------- /ctr/src/flavors/ctr128.rs: -------------------------------------------------------------------------------- 1 | //! 128-bit counter falvors. 2 | use super::CtrFlavor; 3 | use cipher::{ 4 | array::{Array, ArraySize}, 5 | typenum::{PartialDiv, PartialQuot, U16, Unsigned}, 6 | }; 7 | use core::fmt; 8 | 9 | type ChunkSize = U16; 10 | type Chunks = PartialQuot; 11 | const CS: usize = ChunkSize::USIZE; 12 | 13 | #[derive(Clone)] 14 | pub struct CtrNonce128 { 15 | ctr: u128, 16 | nonce: Array, 17 | } 18 | 19 | impl fmt::Debug for CtrNonce128 { 20 | #[inline] 21 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 22 | f.write_str("CtrNonce128 { ... }") 23 | } 24 | } 25 | 26 | impl Drop for CtrNonce128 { 27 | fn drop(&mut self) { 28 | #[cfg(feature = "zeroize")] 29 | { 30 | use cipher::zeroize::Zeroize; 31 | self.ctr.zeroize(); 32 | self.nonce.zeroize(); 33 | } 34 | } 35 | } 36 | 37 | #[cfg(feature = "zeroize")] 38 | impl cipher::zeroize::ZeroizeOnDrop for CtrNonce128 {} 39 | 40 | /// 128-bit big endian counter flavor. 41 | #[derive(Debug)] 42 | pub enum Ctr128BE {} 43 | 44 | impl CtrFlavor for Ctr128BE 45 | where 46 | B: ArraySize + PartialDiv, 47 | Chunks: ArraySize, 48 | { 49 | type CtrNonce = CtrNonce128>; 50 | type Backend = u128; 51 | const NAME: &'static str = "128BE"; 52 | 53 | #[inline] 54 | fn remaining(cn: &Self::CtrNonce) -> Option { 55 | (u128::MAX - cn.ctr).try_into().ok() 56 | } 57 | 58 | #[inline(always)] 59 | fn current_block(cn: &Self::CtrNonce) -> Array { 60 | let mut block = Array::::default(); 61 | for i in 0..Chunks::::USIZE { 62 | let t = if i == Chunks::::USIZE - 1 { 63 | cn.ctr.wrapping_add(cn.nonce[i]).to_be_bytes() 64 | } else { 65 | cn.nonce[i].to_ne_bytes() 66 | }; 67 | block[CS * i..][..CS].copy_from_slice(&t); 68 | } 69 | block 70 | } 71 | 72 | #[inline] 73 | fn next_block(cn: &mut Self::CtrNonce) -> Array { 74 | let block = Self::current_block(cn); 75 | cn.ctr = cn.ctr.wrapping_add(1); 76 | block 77 | } 78 | 79 | #[inline] 80 | fn from_nonce(block: &Array) -> Self::CtrNonce { 81 | let mut nonce = Array::>::default(); 82 | for i in 0..Chunks::::USIZE { 83 | let chunk = block[CS * i..][..CS].try_into().unwrap(); 84 | nonce[i] = if i == Chunks::::USIZE - 1 { 85 | u128::from_be_bytes(chunk) 86 | } else { 87 | u128::from_ne_bytes(chunk) 88 | } 89 | } 90 | let ctr = 0; 91 | Self::CtrNonce { ctr, nonce } 92 | } 93 | 94 | #[inline] 95 | fn as_backend(cn: &Self::CtrNonce) -> Self::Backend { 96 | cn.ctr 97 | } 98 | 99 | #[inline] 100 | fn set_from_backend(cn: &mut Self::CtrNonce, v: Self::Backend) { 101 | cn.ctr = v; 102 | } 103 | } 104 | 105 | /// 128-bit little endian counter flavor. 106 | #[derive(Debug)] 107 | pub enum Ctr128LE {} 108 | 109 | impl CtrFlavor for Ctr128LE 110 | where 111 | B: ArraySize + PartialDiv, 112 | Chunks: ArraySize, 113 | { 114 | type CtrNonce = CtrNonce128>; 115 | type Backend = u128; 116 | const NAME: &'static str = "128LE"; 117 | 118 | #[inline] 119 | fn remaining(cn: &Self::CtrNonce) -> Option { 120 | (u128::MAX - cn.ctr).try_into().ok() 121 | } 122 | 123 | #[inline(always)] 124 | fn current_block(cn: &Self::CtrNonce) -> Array { 125 | let mut block = Array::::default(); 126 | for i in 0..Chunks::::USIZE { 127 | let t = if i == 0 { 128 | cn.ctr.wrapping_add(cn.nonce[i]).to_le_bytes() 129 | } else { 130 | cn.nonce[i].to_ne_bytes() 131 | }; 132 | block[CS * i..][..CS].copy_from_slice(&t); 133 | } 134 | block 135 | } 136 | 137 | #[inline] 138 | fn next_block(cn: &mut Self::CtrNonce) -> Array { 139 | let block = Self::current_block(cn); 140 | cn.ctr = cn.ctr.wrapping_add(1); 141 | block 142 | } 143 | 144 | #[inline] 145 | fn from_nonce(block: &Array) -> Self::CtrNonce { 146 | let mut nonce = Array::>::default(); 147 | for i in 0..Chunks::::USIZE { 148 | let chunk = block[CS * i..][..CS].try_into().unwrap(); 149 | nonce[i] = if i == 0 { 150 | u128::from_le_bytes(chunk) 151 | } else { 152 | u128::from_ne_bytes(chunk) 153 | } 154 | } 155 | let ctr = 0; 156 | Self::CtrNonce { ctr, nonce } 157 | } 158 | 159 | #[inline] 160 | fn as_backend(cn: &Self::CtrNonce) -> Self::Backend { 161 | cn.ctr 162 | } 163 | 164 | #[inline] 165 | fn set_from_backend(cn: &mut Self::CtrNonce, v: Self::Backend) { 166 | cn.ctr = v; 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /ctr/src/flavors/ctr32.rs: -------------------------------------------------------------------------------- 1 | //! 32-bit counter falvors. 2 | use super::CtrFlavor; 3 | use cipher::{ 4 | array::{Array, ArraySize}, 5 | typenum::{PartialDiv, PartialQuot, U4, Unsigned}, 6 | }; 7 | use core::fmt; 8 | 9 | type ChunkSize = U4; 10 | type Chunks = PartialQuot; 11 | const CS: usize = ChunkSize::USIZE; 12 | 13 | #[derive(Clone)] 14 | pub struct CtrNonce32 { 15 | ctr: u32, 16 | nonce: Array, 17 | } 18 | 19 | impl fmt::Debug for CtrNonce32 { 20 | #[inline] 21 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 22 | f.write_str("CtrNonce32 { ... }") 23 | } 24 | } 25 | 26 | impl Drop for CtrNonce32 { 27 | fn drop(&mut self) { 28 | #[cfg(feature = "zeroize")] 29 | { 30 | use cipher::zeroize::Zeroize; 31 | self.ctr.zeroize(); 32 | self.nonce.zeroize(); 33 | } 34 | } 35 | } 36 | 37 | #[cfg(feature = "zeroize")] 38 | impl cipher::zeroize::ZeroizeOnDrop for CtrNonce32 {} 39 | 40 | /// 32-bit big endian counter flavor. 41 | #[derive(Debug)] 42 | pub enum Ctr32BE {} 43 | 44 | impl CtrFlavor for Ctr32BE 45 | where 46 | B: ArraySize + PartialDiv, 47 | Chunks: ArraySize, 48 | { 49 | type CtrNonce = CtrNonce32>; 50 | type Backend = u32; 51 | const NAME: &'static str = "32BE"; 52 | 53 | #[inline] 54 | fn remaining(cn: &Self::CtrNonce) -> Option { 55 | (u32::MAX - cn.ctr).try_into().ok() 56 | } 57 | 58 | #[inline(always)] 59 | fn current_block(cn: &Self::CtrNonce) -> Array { 60 | let mut block = Array::::default(); 61 | for i in 0..Chunks::::USIZE { 62 | let t = if i == Chunks::::USIZE - 1 { 63 | cn.ctr.wrapping_add(cn.nonce[i]).to_be_bytes() 64 | } else { 65 | cn.nonce[i].to_ne_bytes() 66 | }; 67 | block[CS * i..][..CS].copy_from_slice(&t); 68 | } 69 | block 70 | } 71 | 72 | #[inline] 73 | fn next_block(cn: &mut Self::CtrNonce) -> Array { 74 | let block = Self::current_block(cn); 75 | cn.ctr = cn.ctr.wrapping_add(1); 76 | block 77 | } 78 | 79 | #[inline] 80 | fn from_nonce(block: &Array) -> Self::CtrNonce { 81 | let mut nonce = Array::>::default(); 82 | for i in 0..Chunks::::USIZE { 83 | let chunk = block[CS * i..][..CS].try_into().unwrap(); 84 | nonce[i] = if i == Chunks::::USIZE - 1 { 85 | u32::from_be_bytes(chunk) 86 | } else { 87 | u32::from_ne_bytes(chunk) 88 | } 89 | } 90 | let ctr = 0; 91 | Self::CtrNonce { ctr, nonce } 92 | } 93 | 94 | #[inline] 95 | fn as_backend(cn: &Self::CtrNonce) -> Self::Backend { 96 | cn.ctr 97 | } 98 | 99 | #[inline] 100 | fn set_from_backend(cn: &mut Self::CtrNonce, v: Self::Backend) { 101 | cn.ctr = v; 102 | } 103 | } 104 | 105 | /// 32-bit little endian counter flavor. 106 | #[derive(Debug)] 107 | pub enum Ctr32LE {} 108 | 109 | impl CtrFlavor for Ctr32LE 110 | where 111 | B: ArraySize + PartialDiv, 112 | Chunks: ArraySize, 113 | { 114 | type CtrNonce = CtrNonce32>; 115 | type Backend = u32; 116 | const NAME: &'static str = "32LE"; 117 | 118 | #[inline] 119 | fn remaining(cn: &Self::CtrNonce) -> Option { 120 | (u32::MAX - cn.ctr).try_into().ok() 121 | } 122 | 123 | #[inline(always)] 124 | fn current_block(cn: &Self::CtrNonce) -> Array { 125 | let mut block = Array::::default(); 126 | for i in 0..Chunks::::USIZE { 127 | let t = if i == 0 { 128 | cn.ctr.wrapping_add(cn.nonce[i]).to_le_bytes() 129 | } else { 130 | cn.nonce[i].to_ne_bytes() 131 | }; 132 | block[CS * i..][..CS].copy_from_slice(&t); 133 | } 134 | block 135 | } 136 | 137 | #[inline] 138 | fn next_block(cn: &mut Self::CtrNonce) -> Array { 139 | let block = Self::current_block(cn); 140 | cn.ctr = cn.ctr.wrapping_add(1); 141 | block 142 | } 143 | 144 | #[inline] 145 | fn from_nonce(block: &Array) -> Self::CtrNonce { 146 | let mut nonce = Array::>::default(); 147 | for i in 0..Chunks::::USIZE { 148 | let chunk = block[CS * i..][..CS].try_into().unwrap(); 149 | nonce[i] = if i == 0 { 150 | u32::from_le_bytes(chunk) 151 | } else { 152 | u32::from_ne_bytes(chunk) 153 | } 154 | } 155 | let ctr = 0; 156 | Self::CtrNonce { ctr, nonce } 157 | } 158 | 159 | #[inline] 160 | fn as_backend(cn: &Self::CtrNonce) -> Self::Backend { 161 | cn.ctr 162 | } 163 | 164 | #[inline] 165 | fn set_from_backend(cn: &mut Self::CtrNonce, v: Self::Backend) { 166 | cn.ctr = v; 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /ctr/src/flavors/ctr64.rs: -------------------------------------------------------------------------------- 1 | //! 64-bit counter falvors. 2 | use super::CtrFlavor; 3 | use cipher::{ 4 | array::{Array, ArraySize}, 5 | typenum::{PartialDiv, PartialQuot, U8, Unsigned}, 6 | }; 7 | use core::fmt; 8 | 9 | type ChunkSize = U8; 10 | type Chunks = PartialQuot; 11 | const CS: usize = ChunkSize::USIZE; 12 | 13 | #[derive(Clone)] 14 | pub struct CtrNonce64 { 15 | ctr: u64, 16 | nonce: Array, 17 | } 18 | 19 | impl fmt::Debug for CtrNonce64 { 20 | #[inline] 21 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 22 | f.write_str("CtrNonce64 { ... }") 23 | } 24 | } 25 | 26 | impl Drop for CtrNonce64 { 27 | fn drop(&mut self) { 28 | #[cfg(feature = "zeroize")] 29 | { 30 | use cipher::zeroize::Zeroize; 31 | self.ctr.zeroize(); 32 | self.nonce.zeroize(); 33 | } 34 | } 35 | } 36 | 37 | #[cfg(feature = "zeroize")] 38 | impl cipher::zeroize::ZeroizeOnDrop for CtrNonce64 {} 39 | 40 | /// 64-bit big endian counter flavor. 41 | #[derive(Debug)] 42 | pub enum Ctr64BE {} 43 | 44 | impl CtrFlavor for Ctr64BE 45 | where 46 | B: ArraySize + PartialDiv, 47 | Chunks: ArraySize, 48 | { 49 | type CtrNonce = CtrNonce64>; 50 | type Backend = u64; 51 | const NAME: &'static str = "64BE"; 52 | 53 | #[inline] 54 | fn remaining(cn: &Self::CtrNonce) -> Option { 55 | (u64::MAX - cn.ctr).try_into().ok() 56 | } 57 | 58 | #[inline(always)] 59 | fn current_block(cn: &Self::CtrNonce) -> Array { 60 | let mut block = Array::::default(); 61 | for i in 0..Chunks::::USIZE { 62 | let t = if i == Chunks::::USIZE - 1 { 63 | cn.ctr.wrapping_add(cn.nonce[i]).to_be_bytes() 64 | } else { 65 | cn.nonce[i].to_ne_bytes() 66 | }; 67 | block[CS * i..][..CS].copy_from_slice(&t); 68 | } 69 | block 70 | } 71 | 72 | #[inline] 73 | fn next_block(cn: &mut Self::CtrNonce) -> Array { 74 | let block = Self::current_block(cn); 75 | cn.ctr = cn.ctr.wrapping_add(1); 76 | block 77 | } 78 | 79 | #[inline] 80 | fn from_nonce(block: &Array) -> Self::CtrNonce { 81 | let mut nonce = Array::>::default(); 82 | for i in 0..Chunks::::USIZE { 83 | let chunk = block[CS * i..][..CS].try_into().unwrap(); 84 | nonce[i] = if i == Chunks::::USIZE - 1 { 85 | u64::from_be_bytes(chunk) 86 | } else { 87 | u64::from_ne_bytes(chunk) 88 | } 89 | } 90 | let ctr = 0; 91 | Self::CtrNonce { ctr, nonce } 92 | } 93 | 94 | #[inline] 95 | fn as_backend(cn: &Self::CtrNonce) -> Self::Backend { 96 | cn.ctr 97 | } 98 | 99 | #[inline] 100 | fn set_from_backend(cn: &mut Self::CtrNonce, v: Self::Backend) { 101 | cn.ctr = v; 102 | } 103 | } 104 | 105 | /// 64-bit little endian counter flavor. 106 | #[derive(Debug)] 107 | pub enum Ctr64LE {} 108 | 109 | impl CtrFlavor for Ctr64LE 110 | where 111 | B: ArraySize + PartialDiv, 112 | Chunks: ArraySize, 113 | { 114 | type CtrNonce = CtrNonce64>; 115 | type Backend = u64; 116 | const NAME: &'static str = "64LE"; 117 | 118 | #[inline] 119 | fn remaining(cn: &Self::CtrNonce) -> Option { 120 | (u64::MAX - cn.ctr).try_into().ok() 121 | } 122 | 123 | #[inline(always)] 124 | fn current_block(cn: &Self::CtrNonce) -> Array { 125 | let mut block = Array::::default(); 126 | for i in 0..Chunks::::USIZE { 127 | let t = if i == 0 { 128 | cn.ctr.wrapping_add(cn.nonce[i]).to_le_bytes() 129 | } else { 130 | cn.nonce[i].to_ne_bytes() 131 | }; 132 | block[CS * i..][..CS].copy_from_slice(&t); 133 | } 134 | block 135 | } 136 | 137 | #[inline] 138 | fn next_block(cn: &mut Self::CtrNonce) -> Array { 139 | let block = Self::current_block(cn); 140 | cn.ctr = cn.ctr.wrapping_add(1); 141 | block 142 | } 143 | 144 | #[inline] 145 | fn from_nonce(block: &Array) -> Self::CtrNonce { 146 | let mut nonce = Array::>::default(); 147 | for i in 0..Chunks::::USIZE { 148 | let chunk = block[CS * i..][..CS].try_into().unwrap(); 149 | nonce[i] = if i == 0 { 150 | u64::from_le_bytes(chunk) 151 | } else { 152 | u64::from_ne_bytes(chunk) 153 | } 154 | } 155 | let ctr = 0; 156 | Self::CtrNonce { ctr, nonce } 157 | } 158 | 159 | #[inline] 160 | fn as_backend(cn: &Self::CtrNonce) -> Self::Backend { 161 | cn.ctr 162 | } 163 | 164 | #[inline] 165 | fn set_from_backend(cn: &mut Self::CtrNonce, v: Self::Backend) { 166 | cn.ctr = v; 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /ctr/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Generic implementations of [CTR mode][1] for block ciphers. 2 | //! 3 | //! 4 | //! 5 | //! 6 | //! Mode functionality is accessed using traits from re-exported [`cipher`] crate. 7 | //! 8 | //! # ⚠️ Security Warning: Hazmat! 9 | //! 10 | //! This crate does not ensure ciphertexts are authentic! Thus ciphertext integrity 11 | //! is not verified, which can lead to serious vulnerabilities! 12 | //! [AEADs][https://github.com/RustCrypto/AEADs] provide simple authenticated encryption, 13 | //! which is much less error-prone than manual integrity verification. 14 | //! 15 | //! # Example 16 | //! ``` 17 | //! use aes::cipher::{KeyIvInit, StreamCipher, StreamCipherSeek}; 18 | //! use hex_literal::hex; 19 | //! 20 | //! type Aes128Ctr64LE = ctr::Ctr64LE; 21 | //! 22 | //! let key = [0x42; 16]; 23 | //! let iv = [0x24; 16]; 24 | //! let plaintext = *b"hello world! this is my plaintext."; 25 | //! let ciphertext = hex!( 26 | //! "3357121ebb5a29468bd861467596ce3da59bdee42dcc0614dea955368d8a5dc0cad4" 27 | //! ); 28 | //! 29 | //! // encrypt in-place 30 | //! let mut buf = plaintext.to_vec(); 31 | //! let mut cipher = Aes128Ctr64LE::new(&key.into(), &iv.into()); 32 | //! cipher.apply_keystream(&mut buf); 33 | //! assert_eq!(buf[..], ciphertext[..]); 34 | //! 35 | //! // CTR mode can be used with streaming messages 36 | //! let mut cipher = Aes128Ctr64LE::new(&key.into(), &iv.into()); 37 | //! for chunk in buf.chunks_mut(3) { 38 | //! cipher.apply_keystream(chunk); 39 | //! } 40 | //! assert_eq!(buf[..], plaintext[..]); 41 | //! 42 | //! // CTR mode supports seeking. The parameter is zero-based _bytes_ counter (not _blocks_). 43 | //! cipher.seek(0u32); 44 | //! 45 | //! // encrypt/decrypt from buffer to buffer 46 | //! // buffer length must be equal to input length 47 | //! let mut buf1 = [0u8; 34]; 48 | //! cipher 49 | //! .apply_keystream_b2b(&plaintext, &mut buf1) 50 | //! .unwrap(); 51 | //! assert_eq!(buf1[..], ciphertext[..]); 52 | //! 53 | //! let mut buf2 = [0u8; 34]; 54 | //! cipher.seek(0u32); 55 | //! cipher.apply_keystream_b2b(&buf1, &mut buf2).unwrap(); 56 | //! assert_eq!(buf2[..], plaintext[..]); 57 | //! ``` 58 | //! 59 | //! [1]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#CTR 60 | 61 | #![no_std] 62 | #![doc( 63 | html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", 64 | html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg" 65 | )] 66 | #![forbid(unsafe_code)] 67 | #![cfg_attr(docsrs, feature(doc_auto_cfg))] 68 | #![warn(missing_debug_implementations, missing_docs, rust_2018_idioms)] 69 | 70 | mod ctr_core; 71 | pub mod flavors; 72 | 73 | pub use cipher; 74 | pub use flavors::CtrFlavor; 75 | 76 | use cipher::StreamCipherCoreWrapper; 77 | pub use ctr_core::CtrCore; 78 | 79 | /// CTR mode with 128-bit big endian counter. 80 | pub type Ctr128BE = StreamCipherCoreWrapper>; 81 | /// CTR mode with 128-bit little endian counter. 82 | pub type Ctr128LE = StreamCipherCoreWrapper>; 83 | /// CTR mode with 64-bit big endian counter. 84 | pub type Ctr64BE = StreamCipherCoreWrapper>; 85 | /// CTR mode with 64-bit little endian counter. 86 | pub type Ctr64LE = StreamCipherCoreWrapper>; 87 | /// CTR mode with 32-bit big endian counter. 88 | pub type Ctr32BE = StreamCipherCoreWrapper>; 89 | /// CTR mode with 32-bit little endian counter. 90 | pub type Ctr32LE = StreamCipherCoreWrapper>; 91 | -------------------------------------------------------------------------------- /ctr/tests/ctr128/data/aes128-ctr.blb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RustCrypto/block-modes/e52ed9c70aa22b8dd07285f4b15981f137960cd5/ctr/tests/ctr128/data/aes128-ctr.blb -------------------------------------------------------------------------------- /ctr/tests/ctr128/data/aes256-ctr.blb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RustCrypto/block-modes/e52ed9c70aa22b8dd07285f4b15981f137960cd5/ctr/tests/ctr128/data/aes256-ctr.blb -------------------------------------------------------------------------------- /ctr/tests/ctr128/mod.rs: -------------------------------------------------------------------------------- 1 | use aes::{Aes128, Aes256}; 2 | use ctr::{Ctr128BE, CtrCore, flavors}; 3 | 4 | cipher::stream_cipher_test!(aes128_ctr_core, "aes128-ctr", Ctr128BE); 5 | cipher::stream_cipher_test!(aes256_ctr_core, "aes256-ctr", Ctr128BE); 6 | cipher::stream_cipher_seek_test!(aes128_ctr_seek, Ctr128BE); 7 | cipher::stream_cipher_seek_test!(aes256_ctr_seek, Ctr128BE); 8 | cipher::iv_state_test!( 9 | aes128_ctr_iv_state, 10 | CtrCore, 11 | apply_ks, 12 | ); 13 | -------------------------------------------------------------------------------- /ctr/tests/ctr32/be.rs: -------------------------------------------------------------------------------- 1 | //! Counter Mode with a 32-bit big endian counter 2 | 3 | use cipher::{KeyIvInit, StreamCipher, StreamCipherSeek, StreamCipherSeekCore}; 4 | use hex_literal::hex; 5 | 6 | type Aes128Ctr = ctr::Ctr32BE; 7 | 8 | const KEY: &[u8; 16] = &hex!("000102030405060708090A0B0C0D0E0F"); 9 | const NONCE1: &[u8; 16] = &hex!("11111111111111111111111111111111"); 10 | const NONCE2: &[u8; 16] = &hex!("222222222222222222222222FFFFFFFE"); 11 | 12 | #[test] 13 | fn counter_incr() { 14 | let mut ctr = Aes128Ctr::new(KEY.into(), NONCE1.into()); 15 | assert_eq!(ctr.get_core().get_block_pos(), 0); 16 | 17 | let mut buffer = [0u8; 64]; 18 | ctr.apply_keystream(&mut buffer); 19 | 20 | assert_eq!(ctr.get_core().get_block_pos(), 4); 21 | assert_eq!( 22 | &buffer[..], 23 | &hex!( 24 | "35D14E6D3E3A279CF01E343E34E7DED36EEADB04F42E2251AB4377F257856DBA" 25 | "0AB37657B9C2AA09762E518FC9395D5304E96C34CCD2F0A95CDE7321852D90C0" 26 | )[..] 27 | ); 28 | } 29 | 30 | #[test] 31 | fn counter_seek() { 32 | let mut ctr = Aes128Ctr::new(KEY.into(), NONCE1.into()); 33 | ctr.seek(16); 34 | assert_eq!(ctr.get_core().get_block_pos(), 1); 35 | 36 | let mut buffer = [0u8; 64]; 37 | ctr.apply_keystream(&mut buffer); 38 | 39 | assert_eq!(ctr.get_core().get_block_pos(), 5); 40 | assert_eq!( 41 | &buffer[..], 42 | &hex!( 43 | "6EEADB04F42E2251AB4377F257856DBA0AB37657B9C2AA09762E518FC9395D53" 44 | "04E96C34CCD2F0A95CDE7321852D90C0F7441EAB3811A03FDBD162AEC402F5AA" 45 | )[..] 46 | ); 47 | } 48 | 49 | #[test] 50 | fn keystream_xor() { 51 | let mut ctr = Aes128Ctr::new(KEY.into(), NONCE1.into()); 52 | let mut buffer = [1u8; 64]; 53 | 54 | ctr.apply_keystream(&mut buffer); 55 | assert_eq!( 56 | &buffer[..], 57 | &hex!( 58 | "34D04F6C3F3B269DF11F353F35E6DFD26FEBDA05F52F2350AA4276F356846CBB" 59 | "0BB27756B8C3AB08772F508EC8385C5205E86D35CDD3F1A85DDF7220842C91C1" 60 | )[..] 61 | ); 62 | } 63 | 64 | #[test] 65 | fn counter_wrap() { 66 | let mut ctr = Aes128Ctr::new(KEY.into(), NONCE2.into()); 67 | assert_eq!(ctr.get_core().get_block_pos(), 0); 68 | 69 | let mut buffer = [0u8; 64]; 70 | ctr.apply_keystream(&mut buffer); 71 | 72 | assert_eq!(ctr.get_core().get_block_pos(), 4); 73 | assert_eq!( 74 | &buffer[..], 75 | &hex!( 76 | "58FC849D1CF53C54C63E1B1D15CB3C8AAA335F72135585E9FF943F4DAC77CB63" 77 | "BD1AE8716BE69C3B4D886B222B9B4E1E67548EF896A96E2746D8CA6476D8B183" 78 | )[..] 79 | ); 80 | } 81 | 82 | cipher::iv_state_test!( 83 | iv_state, 84 | ctr::CtrCore, 85 | apply_ks, 86 | ); 87 | -------------------------------------------------------------------------------- /ctr/tests/ctr32/le.rs: -------------------------------------------------------------------------------- 1 | //! Counter Mode with a 32-bit little endian counter 2 | 3 | use cipher::{ 4 | KeyIvInit, StreamCipher, StreamCipherSeek, StreamCipherSeekCore, array::Array, consts::U16, 5 | }; 6 | use hex_literal::hex; 7 | 8 | type Aes128Ctr = ctr::Ctr32LE; 9 | 10 | const KEY: &[u8; 16] = &hex!("000102030405060708090A0B0C0D0E0F"); 11 | const NONCE1: &[u8; 16] = &hex!("11111111111111111111111111111111"); 12 | const NONCE2: &[u8; 16] = &hex!("FEFFFFFF222222222222222222222222"); 13 | 14 | /// Compute nonce as used by AES-GCM-SIV 15 | fn nonce(bytes: &[u8; 16]) -> Array { 16 | let mut n = *bytes; 17 | n[15] |= 0x80; 18 | n.into() 19 | } 20 | 21 | #[test] 22 | fn counter_incr() { 23 | let mut ctr = Aes128Ctr::new(KEY.into(), &nonce(NONCE1)); 24 | assert_eq!(ctr.get_core().get_block_pos(), 0); 25 | 26 | let mut buffer = [0u8; 64]; 27 | ctr.apply_keystream(&mut buffer); 28 | 29 | // assert_eq!(ctr.current_ctr(), 4); 30 | assert_eq!( 31 | &buffer[..], 32 | &hex!( 33 | "2A0680B210CAD45E886D7EF6DAB357C9F18B39AFF6930FDB2D9FCE34261FF699" 34 | "EB96774669D24B560C9AD028C5C39C4580775A82065256B4787DC91C6942B700" 35 | )[..] 36 | ); 37 | } 38 | 39 | #[test] 40 | fn counter_seek() { 41 | let mut ctr = Aes128Ctr::new(KEY.into(), &nonce(NONCE1)); 42 | ctr.seek(16); 43 | assert_eq!(ctr.get_core().get_block_pos(), 1); 44 | 45 | let mut buffer = [0u8; 64]; 46 | ctr.apply_keystream(&mut buffer); 47 | 48 | assert_eq!(ctr.get_core().get_block_pos(), 5); 49 | assert_eq!( 50 | &buffer[..], 51 | &hex!( 52 | "F18B39AFF6930FDB2D9FCE34261FF699EB96774669D24B560C9AD028C5C39C45" 53 | "80775A82065256B4787DC91C6942B7001564DDA1B07DCED9201AB71BAF06905B" 54 | )[..] 55 | ); 56 | } 57 | 58 | #[test] 59 | fn keystream_xor() { 60 | let mut ctr = Aes128Ctr::new(KEY.into(), &nonce(NONCE1)); 61 | let mut buffer = [1u8; 64]; 62 | 63 | ctr.apply_keystream(&mut buffer); 64 | assert_eq!( 65 | &buffer[..], 66 | &hex!( 67 | "2B0781B311CBD55F896C7FF7DBB256C8F08A38AEF7920EDA2C9ECF35271EF798" 68 | "EA97764768D34A570D9BD129C4C29D4481765B83075357B5797CC81D6843B601" 69 | )[..] 70 | ); 71 | } 72 | 73 | #[test] 74 | fn counter_wrap() { 75 | let mut ctr = Aes128Ctr::new(KEY.into(), &nonce(NONCE2)); 76 | assert_eq!(ctr.get_core().get_block_pos(), 0); 77 | 78 | let mut buffer = [0u8; 64]; 79 | ctr.apply_keystream(&mut buffer); 80 | 81 | assert_eq!(ctr.get_core().get_block_pos(), 4); 82 | assert_eq!( 83 | &buffer[..], 84 | &hex!( 85 | "A1E649D8B382293DC28375C42443BB6A226BAADC9E9CCA8214F56E07A4024E06" 86 | "6355A0DA2E08FB00112FFA38C26189EE55DD5B0B130ED87096FE01B59A665A60" 87 | )[..] 88 | ); 89 | } 90 | 91 | cipher::iv_state_test!( 92 | iv_state, 93 | ctr::CtrCore, 94 | apply_ks, 95 | ); 96 | -------------------------------------------------------------------------------- /ctr/tests/ctr32/mod.rs: -------------------------------------------------------------------------------- 1 | //! Counter Mode with a 32-bit counter. 2 | //! 3 | //! NOTE: AES-128-CTR test vectors used by these tests were generated by first 4 | //! integration testing the implementation in the contexts of AES-GCM and 5 | //! AES-GCM-SIV, with the former tested against the NIST CAVS vectors, and the 6 | //! latter against the RFC8452 test vectors. 7 | 8 | mod be; 9 | mod le; 10 | -------------------------------------------------------------------------------- /ctr/tests/gost/mod.rs: -------------------------------------------------------------------------------- 1 | use cipher::{KeyIvInit, StreamCipher}; 2 | use hex_literal::hex; 3 | 4 | type MagmaCtr = ctr::Ctr32BE; 5 | type KuznyechikCtr = ctr::Ctr64BE; 6 | 7 | /// Test vectors from GOST R 34.13-2015 (Section A.1.2) 8 | #[test] 9 | fn kuznyechik() { 10 | let key = hex!( 11 | "8899aabbccddeeff0011223344556677" 12 | "fedcba98765432100123456789abcdef" 13 | ); 14 | let nonce = hex!("1234567890abcef00000000000000000"); 15 | let mut pt = hex!( 16 | "1122334455667700ffeeddccbbaa9988" 17 | "00112233445566778899aabbcceeff0a" 18 | "112233445566778899aabbcceeff0a00" 19 | "2233445566778899aabbcceeff0a0011" 20 | ); 21 | let ct = hex!( 22 | "f195d8bec10ed1dbd57b5fa240bda1b8" 23 | "85eee733f6a13e5df33ce4b33c45dee4" 24 | "a5eae88be6356ed3d5e877f13564a3a5" 25 | "cb91fab1f20cbab6d1c6d15820bdba73" 26 | ); 27 | let mut cipher = KuznyechikCtr::new(&key.into(), &nonce.into()); 28 | cipher.apply_keystream(&mut pt); 29 | assert_eq!(pt[..], ct[..]); 30 | } 31 | 32 | /// Test vectors from GOST R 34.13-2015 (Section A.2.2) 33 | #[test] 34 | fn magma() { 35 | let key = hex!( 36 | "ffeeddccbbaa99887766554433221100" 37 | "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff" 38 | ); 39 | let nonce = hex!("1234567800000000"); 40 | let mut pt = hex!( 41 | "92def06b3c130a59" 42 | "db54c704f8189d20" 43 | "4a98fb2e67a8024c" 44 | "8912409b17b57e41" 45 | ); 46 | let ct = hex!( 47 | "4e98110c97b7b93c" 48 | "3e250d93d6e85d69" 49 | "136d868807b2dbef" 50 | "568eb680ab52a12d" 51 | ); 52 | let mut cipher = MagmaCtr::new(&key.into(), &nonce.into()); 53 | cipher.apply_keystream(&mut pt); 54 | assert_eq!(pt[..], ct[..]); 55 | } 56 | -------------------------------------------------------------------------------- /ctr/tests/mod.rs: -------------------------------------------------------------------------------- 1 | //! Counter Mode Tests 2 | 3 | mod ctr128; 4 | mod ctr32; 5 | mod gost; 6 | -------------------------------------------------------------------------------- /cts/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## 0.7.0 (UNRELEASED) 9 | ### Removed 10 | - `std` feature ([#76]) 11 | 12 | ### Changed 13 | - Update to cipher v0.5 ([#72]) 14 | - Merge Enc/Dec types, i.e. `CbcCs1Enc` and `CbcCs1Dec` are merged into `CbcCs1` ([#72]) 15 | - Edition changed to 2024 and MSRV bumped to 1.85 ([#76]) 16 | - Relax MSRV policy and allow MSRV bumps in patch releases 17 | 18 | [#72]: https://github.com/RustCrypto/block-modes/pull/72 19 | [#76]: https://github.com/RustCrypto/block-modes/pull/76 20 | 21 | ## 0.6.0 (2024-11-01) 22 | - Initial release ([#70]) 23 | 24 | [#70]: https://github.com/RustCrypto/block-modes/pull/70 25 | -------------------------------------------------------------------------------- /cts/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cts" 3 | version = "0.7.0-rc.0" 4 | description = "Generic implementation of the ciphertext stealing block modes of operation" 5 | authors = ["RustCrypto Developers"] 6 | license = "MIT OR Apache-2.0" 7 | edition = "2024" 8 | rust-version = "1.85" 9 | readme = "README.md" 10 | documentation = "https://docs.rs/cts" 11 | repository = "https://github.com/RustCrypto/block-modes" 12 | keywords = ["crypto", "block-mode", "ciphers"] 13 | categories = ["cryptography", "no-std"] 14 | 15 | [dependencies] 16 | cipher = "0.5.0-rc.0" 17 | 18 | [dev-dependencies] 19 | cipher = { version = "0.5.0-rc.0", features = ["dev"] } 20 | hex-literal = "1" 21 | aes = "0.9.0-rc.0" 22 | belt-block = "0.2.0-rc.0" 23 | 24 | [package.metadata.docs.rs] 25 | all-features = true 26 | rustdoc-args = ["--cfg", "docsrs"] 27 | -------------------------------------------------------------------------------- /cts/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2024 RustCrypto Developers 2 | Copyright (c) 2024 Artyom Pavlov 3 | 4 | Permission is hereby granted, free of charge, to any 5 | person obtaining a copy of this software and associated 6 | documentation files (the "Software"), to deal in the 7 | Software without restriction, including without 8 | limitation the rights to use, copy, modify, merge, 9 | publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software 11 | is furnished to do so, subject to the following 12 | conditions: 13 | 14 | The above copyright notice and this permission notice 15 | shall be included in all copies or substantial portions 16 | of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 19 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 20 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 21 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 22 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 23 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 25 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 | DEALINGS IN THE SOFTWARE. 27 | -------------------------------------------------------------------------------- /cts/README.md: -------------------------------------------------------------------------------- 1 | # RustCrypto: CTS 2 | 3 | [![crate][crate-image]][crate-link] 4 | [![Docs][docs-image]][docs-link] 5 | [![Build Status][build-image]][build-link] 6 | ![Apache2/MIT licensed][license-image] 7 | ![Rust Version][rustc-image] 8 | [![Project Chat][chat-image]][chat-link] 9 | 10 | Generic implementation of the [ciphertext stealing] block cipher modes of operation. 11 | 12 | ## Example 13 | ```rust 14 | use aes::Aes128; 15 | use cts::{Decrypt, Encrypt, KeyIvInit}; 16 | use hex_literal::hex; 17 | 18 | type Aes128CbcCs3 = cts::CbcCs3; 19 | 20 | let key = [0x42; 16]; 21 | let iv = [0x24; 16]; 22 | 23 | // Message must be bigger than block size (16 bytes for AES-128) 24 | let msg = b"Lorem ipsum dolor sit amet"; 25 | let mut buf = [0u8; 26]; 26 | 27 | Aes128CbcCs3::new(&key.into(), &iv.into()) 28 | .encrypt_b2b(msg, &mut buf).unwrap(); 29 | assert_eq!(buf, hex!("68ec97f172e322fdd38e74fca65cee52658ae2124beb5e4e5315")); 30 | 31 | Aes128CbcCs3::new(&key.into(), &iv.into()) 32 | .decrypt(&mut buf).unwrap(); 33 | assert_eq!(&buf, msg); 34 | ``` 35 | 36 | If you wan to encrypt many messages with one key, you can use a block cipher reference 37 | to create CTS modes: 38 | ```rust 39 | use aes::Aes128; 40 | use cts::{ 41 | cipher::{InnerIvInit, KeyInit}, 42 | Encrypt, 43 | }; 44 | use hex_literal::hex; 45 | 46 | let key = [0x42; 16]; 47 | let cipher = Aes128::new(&key.into()); 48 | 49 | let iv1 = [0x24; 16]; 50 | let msg1 = b"Lorem ipsum dolor sit amet"; 51 | let mut buf1 = [0u8; 26]; 52 | 53 | let iv2 = [0x25; 16]; 54 | let msg2 = b"Lorem ipsum dolor sit"; 55 | let mut buf2 = [0u8; 21]; 56 | 57 | cts::CbcCs3::inner_iv_init(&cipher, &iv1.into()) 58 | .encrypt_b2b(msg1, &mut buf1).unwrap(); 59 | assert_eq!(buf1, hex!("68ec97f172e322fdd38e74fca65cee52658ae2124beb5e4e5315")); 60 | 61 | cts::CbcCs3::inner_iv_init(&cipher, &iv2.into()) 62 | .encrypt_b2b(msg2, &mut buf2).unwrap(); 63 | assert_eq!(buf2, hex!("69ebd2059e69c6e416a67351982267a26bf5672934")); 64 | ``` 65 | 66 | ## License 67 | 68 | Licensed under either of: 69 | 70 | * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) 71 | * [MIT license](http://opensource.org/licenses/MIT) 72 | 73 | at your option. 74 | 75 | ### Contribution 76 | 77 | Unless you explicitly state otherwise, any contribution intentionally submitted 78 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be 79 | dual licensed as above, without any additional terms or conditions. 80 | 81 | [//]: # (badges) 82 | 83 | [crate-image]: https://img.shields.io/crates/v/cts.svg?logo=rust 84 | [crate-link]: https://crates.io/crates/cts 85 | [docs-image]: https://docs.rs/cts/badge.svg 86 | [docs-link]: https://docs.rs/cts/ 87 | [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg 88 | [rustc-image]: https://img.shields.io/badge/rustc-1.85+-blue.svg 89 | [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg 90 | [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/308460-block-modes 91 | [build-image]: https://github.com/RustCrypto/block-modes/actions/workflows/cts.yaml/badge.svg 92 | [build-link]: https://github.com/RustCrypto/block-modes/actions/workflows/cts.yaml 93 | 94 | [//]: # (general links) 95 | 96 | [ciphertext stealing]: https://en.wikipedia.org/wiki/Ciphertext_stealing 97 | -------------------------------------------------------------------------------- /cts/src/cbc_cs1.rs: -------------------------------------------------------------------------------- 1 | use crate::{Decrypt, Encrypt, Error, cbc_dec, cbc_enc, xor}; 2 | use cipher::{ 3 | Block, BlockCipherDecBackend, BlockCipherDecClosure, BlockCipherDecrypt, BlockCipherEncBackend, 4 | BlockCipherEncClosure, BlockCipherEncrypt, BlockSizeUser, InnerIvInit, IvSizeUser, 5 | array::Array, 6 | crypto_common::{BlockSizes, InnerUser}, 7 | inout::InOutBuf, 8 | typenum::Unsigned, 9 | }; 10 | 11 | /// The CBC-CS-1 ciphertext stealing mode. 12 | #[derive(Clone)] 13 | pub struct CbcCs1 { 14 | cipher: C, 15 | iv: Block, 16 | } 17 | 18 | impl InnerUser for CbcCs1 { 19 | type Inner = C; 20 | } 21 | 22 | impl IvSizeUser for CbcCs1 { 23 | type IvSize = C::BlockSize; 24 | } 25 | 26 | impl InnerIvInit for CbcCs1 { 27 | fn inner_iv_init(cipher: Self::Inner, iv: &cipher::Iv) -> Self { 28 | Self { 29 | cipher, 30 | iv: iv.clone(), 31 | } 32 | } 33 | } 34 | 35 | impl Encrypt for CbcCs1 { 36 | fn encrypt_inout(self, buf: InOutBuf<'_, '_, u8>) -> Result<(), Error> { 37 | if buf.len() < C::BlockSize::USIZE { 38 | return Err(Error); 39 | } 40 | let Self { cipher, iv } = self; 41 | cipher.encrypt_with_backend(Closure { iv, buf }); 42 | Ok(()) 43 | } 44 | } 45 | 46 | impl Decrypt for CbcCs1 { 47 | fn decrypt_inout(self, buf: InOutBuf<'_, '_, u8>) -> Result<(), Error> { 48 | if buf.len() < C::BlockSize::USIZE { 49 | return Err(Error); 50 | } 51 | let Self { cipher, iv } = self; 52 | cipher.decrypt_with_backend(Closure { iv, buf }); 53 | Ok(()) 54 | } 55 | } 56 | 57 | struct Closure<'a, BS: BlockSizes> { 58 | iv: Array, 59 | buf: InOutBuf<'a, 'a, u8>, 60 | } 61 | 62 | impl BlockSizeUser for Closure<'_, BS> { 63 | type BlockSize = BS; 64 | } 65 | 66 | impl BlockCipherEncClosure for Closure<'_, BS> { 67 | fn call>(self, cipher: &B) { 68 | let Self { mut iv, mut buf } = self; 69 | let (blocks, tail) = buf.reborrow().into_chunks(); 70 | 71 | cbc_enc(cipher, &mut iv, blocks); 72 | 73 | if tail.is_empty() { 74 | return; 75 | } 76 | 77 | let mut block = Block::::default(); 78 | block[..tail.len()].copy_from_slice(tail.get_in()); 79 | xor(&mut block, &iv); 80 | cipher.encrypt_block_inplace(&mut block); 81 | 82 | let pos = buf.len() - B::BlockSize::USIZE; 83 | buf.get_out()[pos..].copy_from_slice(&block); 84 | } 85 | } 86 | 87 | impl BlockCipherDecClosure for Closure<'_, BS> { 88 | fn call>(self, cipher: &B) { 89 | let Self { mut iv, mut buf } = self; 90 | 91 | let (mut blocks, tail) = buf.reborrow().into_chunks(); 92 | 93 | if !tail.is_empty() { 94 | let mid = blocks.len() - 1; 95 | blocks = blocks.split_at(mid).0; 96 | }; 97 | 98 | cbc_dec(cipher, &mut iv, blocks); 99 | 100 | if tail.is_empty() { 101 | return; 102 | } 103 | 104 | let tail_len = tail.len(); 105 | let bs = B::BlockSize::USIZE; 106 | let mid = buf.len() - (bs + tail_len); 107 | let mut rem = buf.split_at(mid).1; 108 | 109 | let n = rem.len() - bs; 110 | let mut block1: Block = rem.get_in()[..bs].try_into().unwrap(); 111 | let mut block2: Block = rem.get_in()[n..].try_into().unwrap(); 112 | 113 | cipher.decrypt_block_inplace(&mut block2); 114 | block1[n..].copy_from_slice(&block2[n..]); 115 | xor(&mut block2, &block1); 116 | 117 | cipher.decrypt_block_inplace(&mut block1); 118 | xor(&mut block1, &iv); 119 | 120 | rem.get_out()[..bs].copy_from_slice(&block1); 121 | rem.get_out()[bs..].copy_from_slice(&block2[..n]); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /cts/src/cbc_cs2.rs: -------------------------------------------------------------------------------- 1 | use crate::{Decrypt, Encrypt, Error, cbc_dec, cbc_enc, xor}; 2 | use cipher::{ 3 | Block, BlockCipherDecBackend, BlockCipherDecClosure, BlockCipherDecrypt, BlockCipherEncBackend, 4 | BlockCipherEncClosure, BlockCipherEncrypt, BlockSizeUser, InnerIvInit, IvSizeUser, 5 | array::Array, 6 | crypto_common::{BlockSizes, InnerUser}, 7 | inout::InOutBuf, 8 | typenum::Unsigned, 9 | }; 10 | 11 | /// The CBC-CS-2 ciphertext stealing mode. 12 | #[derive(Clone)] 13 | pub struct CbcCs2 { 14 | cipher: C, 15 | iv: Block, 16 | } 17 | 18 | impl InnerUser for CbcCs2 { 19 | type Inner = C; 20 | } 21 | 22 | impl IvSizeUser for CbcCs2 { 23 | type IvSize = C::BlockSize; 24 | } 25 | 26 | impl InnerIvInit for CbcCs2 { 27 | fn inner_iv_init(cipher: Self::Inner, iv: &cipher::Iv) -> Self { 28 | Self { 29 | cipher, 30 | iv: iv.clone(), 31 | } 32 | } 33 | } 34 | 35 | impl Encrypt for CbcCs2 { 36 | fn encrypt_inout(self, buf: InOutBuf<'_, '_, u8>) -> Result<(), Error> { 37 | if buf.len() < C::BlockSize::USIZE { 38 | return Err(Error); 39 | } 40 | let Self { cipher, iv } = self; 41 | cipher.encrypt_with_backend(Closure { iv, buf }); 42 | Ok(()) 43 | } 44 | } 45 | 46 | impl Decrypt for CbcCs2 { 47 | fn decrypt_inout(self, buf: InOutBuf<'_, '_, u8>) -> Result<(), Error> { 48 | if buf.len() < C::BlockSize::USIZE { 49 | return Err(Error); 50 | } 51 | let Self { cipher, iv } = self; 52 | cipher.decrypt_with_backend(Closure { iv, buf }); 53 | Ok(()) 54 | } 55 | } 56 | 57 | struct Closure<'a, BS: BlockSizes> { 58 | iv: Array, 59 | buf: InOutBuf<'a, 'a, u8>, 60 | } 61 | 62 | impl BlockSizeUser for Closure<'_, BS> { 63 | type BlockSize = BS; 64 | } 65 | 66 | impl BlockCipherEncClosure for Closure<'_, BS> { 67 | fn call>(self, cipher: &B) { 68 | let Self { mut iv, mut buf } = self; 69 | let (mut blocks, mut tail) = buf.reborrow().into_chunks(); 70 | 71 | cbc_enc(cipher, &mut iv, blocks.reborrow()); 72 | 73 | if tail.is_empty() { 74 | return; 75 | } 76 | 77 | let mut block = Block::::default(); 78 | block[..tail.len()].copy_from_slice(tail.get_in()); 79 | xor(&mut block, &iv); 80 | cipher.encrypt_block_inplace(&mut block); 81 | 82 | let penult_block = core::mem::replace(blocks.get_out().last_mut().unwrap(), block); 83 | let tail_val = &penult_block[..tail.len()]; 84 | tail.get_out().copy_from_slice(tail_val); 85 | } 86 | } 87 | 88 | impl BlockCipherDecClosure for Closure<'_, BS> { 89 | fn call>(self, cipher: &B) { 90 | let Self { mut iv, mut buf } = self; 91 | 92 | let (mut blocks, tail) = buf.reborrow().into_chunks(); 93 | 94 | if !tail.is_empty() { 95 | let mid = blocks.len() - 1; 96 | blocks = blocks.split_at(mid).0; 97 | }; 98 | 99 | cbc_dec(cipher, &mut iv, blocks); 100 | 101 | if tail.is_empty() { 102 | return; 103 | } 104 | 105 | let tail_len = tail.len(); 106 | let bs = B::BlockSize::USIZE; 107 | let mid = buf.len() - (bs + tail_len); 108 | let mut rem = buf.split_at(mid).1; 109 | 110 | let n = rem.len() - bs; 111 | let mut block1: Block = rem.get_in()[..bs].try_into().unwrap(); 112 | cipher.decrypt_block_inplace(&mut block1); 113 | 114 | let mut block2 = Block::::default(); 115 | block2[..n].copy_from_slice(&rem.get_in()[bs..]); 116 | block2[n..].copy_from_slice(&block1[n..]); 117 | 118 | xor(&mut block1, &block2); 119 | 120 | cipher.decrypt_block_inplace(&mut block2); 121 | xor(&mut block2, &iv); 122 | 123 | rem.get_out()[..bs].copy_from_slice(&block2); 124 | rem.get_out()[bs..].copy_from_slice(&block1[..n]); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /cts/src/cbc_cs3.rs: -------------------------------------------------------------------------------- 1 | use crate::{Decrypt, Encrypt, Error, cbc_dec, cbc_enc, xor}; 2 | use cipher::{ 3 | Block, BlockCipherDecBackend, BlockCipherDecClosure, BlockCipherDecrypt, BlockCipherEncBackend, 4 | BlockCipherEncClosure, BlockCipherEncrypt, BlockSizeUser, InnerIvInit, IvSizeUser, 5 | array::Array, 6 | crypto_common::{BlockSizes, InnerUser}, 7 | inout::InOutBuf, 8 | typenum::Unsigned, 9 | }; 10 | 11 | /// The CBC-CS-3 ciphertext stealing mode. 12 | #[derive(Clone)] 13 | pub struct CbcCs3 { 14 | cipher: C, 15 | iv: Block, 16 | } 17 | 18 | impl InnerUser for CbcCs3 { 19 | type Inner = C; 20 | } 21 | 22 | impl IvSizeUser for CbcCs3 { 23 | type IvSize = C::BlockSize; 24 | } 25 | 26 | impl InnerIvInit for CbcCs3 { 27 | fn inner_iv_init(cipher: Self::Inner, iv: &cipher::Iv) -> Self { 28 | Self { 29 | cipher, 30 | iv: iv.clone(), 31 | } 32 | } 33 | } 34 | 35 | impl Encrypt for CbcCs3 { 36 | fn encrypt_inout(self, buf: InOutBuf<'_, '_, u8>) -> Result<(), Error> { 37 | if buf.len() < C::BlockSize::USIZE { 38 | return Err(Error); 39 | } 40 | let Self { cipher, iv } = self; 41 | cipher.encrypt_with_backend(Closure { iv, buf }); 42 | Ok(()) 43 | } 44 | } 45 | 46 | impl Decrypt for CbcCs3 { 47 | fn decrypt_inout(self, buf: InOutBuf<'_, '_, u8>) -> Result<(), Error> { 48 | if buf.len() < C::BlockSize::USIZE { 49 | return Err(Error); 50 | } 51 | let Self { cipher, iv } = self; 52 | cipher.decrypt_with_backend(Closure { iv, buf }); 53 | Ok(()) 54 | } 55 | } 56 | 57 | struct Closure<'a, BS: BlockSizes> { 58 | iv: Array, 59 | buf: InOutBuf<'a, 'a, u8>, 60 | } 61 | 62 | impl BlockSizeUser for Closure<'_, BS> { 63 | type BlockSize = BS; 64 | } 65 | 66 | impl BlockCipherEncClosure for Closure<'_, BS> { 67 | fn call>(self, cipher: &B) { 68 | let Self { mut iv, mut buf } = self; 69 | let (mut blocks, mut tail) = buf.reborrow().into_chunks(); 70 | 71 | cbc_enc(cipher, &mut iv, blocks.reborrow()); 72 | 73 | if tail.is_empty() && blocks.len() > 1 { 74 | let blocks = blocks.get_out(); 75 | let (last, rest) = blocks.split_last_mut().unwrap(); 76 | let (penultimate, _) = rest.split_last_mut().unwrap(); 77 | core::mem::swap(penultimate, last); 78 | } else { 79 | let mut block = Block::::default(); 80 | block[..tail.len()].copy_from_slice(tail.get_in()); 81 | xor(&mut block, &iv); 82 | cipher.encrypt_block_inplace(&mut block); 83 | 84 | let penult_block = blocks.get_out().last_mut().unwrap(); 85 | let val = core::mem::replace(penult_block, block); 86 | 87 | let tail_val = &val[..tail.len()]; 88 | tail.get_out().copy_from_slice(tail_val); 89 | } 90 | } 91 | } 92 | 93 | impl BlockCipherDecClosure for Closure<'_, BS> { 94 | fn call>(self, cipher: &B) { 95 | let Self { mut iv, buf } = self; 96 | 97 | let bs = B::BlockSize::USIZE; 98 | let blocks_len = buf.len().div_ceil(bs); 99 | let main_blocks = blocks_len.saturating_sub(2); 100 | 101 | let (blocks, mut tail) = buf.split_at(bs * main_blocks); 102 | let (blocks, rem) = blocks.into_chunks(); 103 | debug_assert_eq!(rem.len(), 0); 104 | 105 | cbc_dec(cipher, &mut iv, blocks); 106 | 107 | let n = tail.len() - bs; 108 | let mut block1: Block = tail.get_in()[..bs].try_into().unwrap(); 109 | cipher.decrypt_block_inplace(&mut block1); 110 | 111 | let mut block2 = Block::::default(); 112 | block2[..n].copy_from_slice(&tail.get_in()[bs..]); 113 | block2[n..].copy_from_slice(&block1[n..]); 114 | xor(&mut block1, &block2); 115 | 116 | cipher.decrypt_block_inplace(&mut block2); 117 | xor(&mut block2, &iv); 118 | 119 | let (l, r) = tail.get_out().split_at_mut(bs); 120 | l.copy_from_slice(&block2); 121 | r.copy_from_slice(&block1[..n]); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /cts/src/ecb_cs1.rs: -------------------------------------------------------------------------------- 1 | use core::marker::PhantomData; 2 | 3 | use crate::{Decrypt, Encrypt, Error, ecb_dec, ecb_enc}; 4 | use cipher::{ 5 | Block, BlockCipherDecBackend, BlockCipherDecClosure, BlockCipherDecrypt, BlockCipherEncBackend, 6 | BlockCipherEncClosure, BlockCipherEncrypt, BlockSizeUser, IvSizeUser, 7 | crypto_common::{BlockSizes, InnerInit, InnerUser}, 8 | inout::InOutBuf, 9 | typenum::Unsigned, 10 | }; 11 | 12 | /// The ECB-CS-1 ciphertext stealing mode. 13 | #[derive(Clone)] 14 | pub struct EcbCs1 { 15 | cipher: C, 16 | } 17 | 18 | impl InnerUser for EcbCs1 { 19 | type Inner = C; 20 | } 21 | 22 | impl IvSizeUser for EcbCs1 { 23 | type IvSize = C::BlockSize; 24 | } 25 | 26 | impl InnerInit for EcbCs1 { 27 | fn inner_init(cipher: Self::Inner) -> Self { 28 | Self { cipher } 29 | } 30 | } 31 | 32 | impl Encrypt for EcbCs1 { 33 | fn encrypt_inout(self, buf: InOutBuf<'_, '_, u8>) -> Result<(), Error> { 34 | if buf.len() < C::BlockSize::USIZE { 35 | return Err(Error); 36 | } 37 | self.cipher.encrypt_with_backend(Closure { 38 | buf, 39 | _pd: PhantomData, 40 | }); 41 | Ok(()) 42 | } 43 | } 44 | 45 | impl Decrypt for EcbCs1 { 46 | fn decrypt_inout(self, buf: InOutBuf<'_, '_, u8>) -> Result<(), Error> { 47 | if buf.len() < C::BlockSize::USIZE { 48 | return Err(Error); 49 | } 50 | self.cipher.decrypt_with_backend(Closure { 51 | buf, 52 | _pd: PhantomData, 53 | }); 54 | Ok(()) 55 | } 56 | } 57 | 58 | struct Closure<'a, BS: BlockSizes> { 59 | buf: InOutBuf<'a, 'a, u8>, 60 | _pd: PhantomData, 61 | } 62 | 63 | impl BlockSizeUser for Closure<'_, BS> { 64 | type BlockSize = BS; 65 | } 66 | 67 | impl BlockCipherEncClosure for Closure<'_, BS> { 68 | fn call>(self, cipher: &B) { 69 | let mut buf = self.buf; 70 | let (mut blocks, tail) = buf.reborrow().into_chunks(); 71 | 72 | ecb_enc(cipher, blocks.reborrow()); 73 | 74 | if tail.is_empty() { 75 | return; 76 | } 77 | 78 | let last_block = blocks.get_out().last_mut().unwrap(); 79 | let mut block = Block::::default(); 80 | 81 | let n = tail.len(); 82 | 83 | block[..n].copy_from_slice(tail.get_in()); 84 | block[n..].copy_from_slice(&last_block[n..]); 85 | cipher.encrypt_block_inplace(&mut block); 86 | 87 | let pos = buf.len() - block.len(); 88 | buf.get_out()[pos..].copy_from_slice(&block); 89 | } 90 | } 91 | 92 | impl BlockCipherDecClosure for Closure<'_, BS> { 93 | fn call>(self, cipher: &B) { 94 | let mut buf = self.buf; 95 | let (mut blocks, tail) = buf.reborrow().into_chunks(); 96 | 97 | if !tail.is_empty() { 98 | let mid = blocks.len() - 1; 99 | blocks = blocks.split_at(mid).0; 100 | }; 101 | 102 | ecb_dec(cipher, blocks); 103 | 104 | if tail.is_empty() { 105 | return; 106 | } 107 | 108 | let tail_len = tail.len(); 109 | let bs = B::BlockSize::USIZE; 110 | let mid = buf.len() - (bs + tail_len); 111 | let mut rem = buf.split_at(mid).1; 112 | 113 | let n = rem.len() - bs; 114 | let mut block1: Block = rem.get_in()[..bs].try_into().unwrap(); 115 | let mut block2: Block = rem.get_in()[n..].try_into().unwrap(); 116 | 117 | cipher.decrypt_block_inplace(&mut block2); 118 | block1[n..].copy_from_slice(&block2[n..]); 119 | 120 | cipher.decrypt_block_inplace(&mut block1); 121 | 122 | rem.get_out()[..bs].copy_from_slice(&block1); 123 | rem.get_out()[bs..].copy_from_slice(&block2[..n]); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /cts/src/ecb_cs2.rs: -------------------------------------------------------------------------------- 1 | use core::marker::PhantomData; 2 | 3 | use crate::{Decrypt, Encrypt, Error, ecb_dec, ecb_enc}; 4 | use cipher::{ 5 | Block, BlockCipherDecBackend, BlockCipherDecClosure, BlockCipherDecrypt, BlockCipherEncBackend, 6 | BlockCipherEncClosure, BlockCipherEncrypt, BlockSizeUser, IvSizeUser, 7 | crypto_common::{BlockSizes, InnerInit, InnerUser}, 8 | inout::InOutBuf, 9 | typenum::Unsigned, 10 | }; 11 | 12 | /// The ECB-CS-2 ciphertext stealing mode. 13 | #[derive(Clone)] 14 | pub struct EcbCs2 { 15 | cipher: C, 16 | } 17 | 18 | impl InnerUser for EcbCs2 { 19 | type Inner = C; 20 | } 21 | 22 | impl IvSizeUser for EcbCs2 { 23 | type IvSize = C::BlockSize; 24 | } 25 | 26 | impl InnerInit for EcbCs2 { 27 | fn inner_init(cipher: Self::Inner) -> Self { 28 | Self { cipher } 29 | } 30 | } 31 | 32 | impl Encrypt for EcbCs2 { 33 | fn encrypt_inout(self, buf: InOutBuf<'_, '_, u8>) -> Result<(), Error> { 34 | if buf.len() < C::BlockSize::USIZE { 35 | return Err(Error); 36 | } 37 | self.cipher.encrypt_with_backend(Closure { 38 | buf, 39 | _pd: PhantomData, 40 | }); 41 | Ok(()) 42 | } 43 | } 44 | 45 | impl Decrypt for EcbCs2 { 46 | fn decrypt_inout(self, buf: InOutBuf<'_, '_, u8>) -> Result<(), Error> { 47 | if buf.len() < C::BlockSize::USIZE { 48 | return Err(Error); 49 | } 50 | self.cipher.decrypt_with_backend(Closure { 51 | buf, 52 | _pd: PhantomData, 53 | }); 54 | Ok(()) 55 | } 56 | } 57 | 58 | struct Closure<'a, BS: BlockSizes> { 59 | buf: InOutBuf<'a, 'a, u8>, 60 | _pd: PhantomData, 61 | } 62 | 63 | impl BlockSizeUser for Closure<'_, BS> { 64 | type BlockSize = BS; 65 | } 66 | 67 | impl BlockCipherEncClosure for Closure<'_, BS> { 68 | fn call>(self, cipher: &B) { 69 | let mut buf = self.buf; 70 | let (mut blocks, mut tail) = buf.reborrow().into_chunks(); 71 | 72 | ecb_enc(cipher, blocks.reborrow()); 73 | 74 | if tail.is_empty() { 75 | return; 76 | } 77 | 78 | let last_block = blocks.get_out().last_mut().unwrap(); 79 | 80 | let n = tail.len(); 81 | 82 | let mut block = Block::::default(); 83 | block[..n].copy_from_slice(tail.get_in()); 84 | block[n..].copy_from_slice(&last_block[n..]); 85 | cipher.encrypt_block_inplace(&mut block); 86 | 87 | tail.get_out().copy_from_slice(&last_block[..n]); 88 | *last_block = block; 89 | } 90 | } 91 | 92 | impl BlockCipherDecClosure for Closure<'_, BS> { 93 | fn call>(self, cipher: &B) { 94 | let mut buf = self.buf; 95 | let (mut blocks, mut tail) = buf.reborrow().into_chunks(); 96 | 97 | ecb_dec(cipher, blocks.reborrow()); 98 | 99 | if tail.is_empty() { 100 | return; 101 | } 102 | 103 | let last_block = blocks.get_out().last_mut().unwrap(); 104 | 105 | let tail_len = tail.len(); 106 | let mut block = Block::::default(); 107 | block[..tail_len].copy_from_slice(tail.get_in()); 108 | block[tail_len..].copy_from_slice(&last_block[tail_len..]); 109 | tail.get_out().copy_from_slice(&last_block[..tail_len]); 110 | 111 | cipher.decrypt_block_inplace(&mut block); 112 | 113 | *last_block = block; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /cts/src/ecb_cs3.rs: -------------------------------------------------------------------------------- 1 | use core::marker::PhantomData; 2 | 3 | use crate::{Decrypt, Encrypt, Error, ecb_dec, ecb_enc}; 4 | use cipher::{ 5 | Block, BlockCipherDecBackend, BlockCipherDecClosure, BlockCipherDecrypt, BlockCipherEncBackend, 6 | BlockCipherEncClosure, BlockCipherEncrypt, BlockSizeUser, IvSizeUser, 7 | crypto_common::{BlockSizes, InnerInit, InnerUser}, 8 | inout::InOutBuf, 9 | typenum::Unsigned, 10 | }; 11 | 12 | /// The ECB-CS-3 ciphertext stealing mode. 13 | #[derive(Clone)] 14 | pub struct EcbCs3 { 15 | cipher: C, 16 | } 17 | 18 | impl InnerUser for EcbCs3 { 19 | type Inner = C; 20 | } 21 | 22 | impl IvSizeUser for EcbCs3 { 23 | type IvSize = C::BlockSize; 24 | } 25 | 26 | impl InnerInit for EcbCs3 { 27 | fn inner_init(cipher: Self::Inner) -> Self { 28 | Self { cipher } 29 | } 30 | } 31 | 32 | impl Encrypt for EcbCs3 { 33 | fn encrypt_inout(self, buf: InOutBuf<'_, '_, u8>) -> Result<(), Error> { 34 | if buf.len() < C::BlockSize::USIZE { 35 | return Err(Error); 36 | } 37 | self.cipher.encrypt_with_backend(Closure { 38 | buf, 39 | _pd: PhantomData, 40 | }); 41 | Ok(()) 42 | } 43 | } 44 | 45 | impl Decrypt for EcbCs3 { 46 | fn decrypt_inout(self, buf: InOutBuf<'_, '_, u8>) -> Result<(), Error> { 47 | if buf.len() < C::BlockSize::USIZE { 48 | return Err(Error); 49 | } 50 | self.cipher.decrypt_with_backend(Closure { 51 | buf, 52 | _pd: PhantomData, 53 | }); 54 | Ok(()) 55 | } 56 | } 57 | 58 | struct Closure<'a, BS: BlockSizes> { 59 | buf: InOutBuf<'a, 'a, u8>, 60 | _pd: PhantomData, 61 | } 62 | 63 | impl BlockSizeUser for Closure<'_, BS> { 64 | type BlockSize = BS; 65 | } 66 | 67 | impl BlockCipherEncClosure for Closure<'_, BS> { 68 | fn call>(self, cipher: &B) { 69 | let mut buf = self.buf; 70 | let (mut blocks, mut tail) = buf.reborrow().into_chunks(); 71 | 72 | ecb_enc(cipher, blocks.reborrow()); 73 | 74 | if tail.is_empty() && blocks.len() > 1 { 75 | let blocks = blocks.get_out(); 76 | let (last, rest) = blocks.split_last_mut().unwrap(); 77 | let (penultimate, _) = rest.split_last_mut().unwrap(); 78 | core::mem::swap(penultimate, last); 79 | } else { 80 | let last_block = blocks.get_out().last_mut().unwrap(); 81 | 82 | let n = tail.len(); 83 | 84 | let mut block = Block::::default(); 85 | block[..n].copy_from_slice(tail.get_in()); 86 | block[n..].copy_from_slice(&last_block[n..]); 87 | cipher.encrypt_block_inplace(&mut block); 88 | 89 | tail.get_out().copy_from_slice(&last_block[..n]); 90 | *last_block = block; 91 | } 92 | } 93 | } 94 | 95 | impl BlockCipherDecClosure for Closure<'_, BS> { 96 | fn call>(self, cipher: &B) { 97 | let mut buf = self.buf; 98 | let (mut blocks, mut tail) = buf.reborrow().into_chunks(); 99 | 100 | ecb_dec(cipher, blocks.reborrow()); 101 | 102 | if tail.is_empty() && blocks.len() > 1 { 103 | let blocks = blocks.get_out(); 104 | let (last, rest) = blocks.split_last_mut().unwrap(); 105 | let (penultimate, _) = rest.split_last_mut().unwrap(); 106 | core::mem::swap(penultimate, last); 107 | } else { 108 | let last_block = blocks.get_out().last_mut().unwrap(); 109 | 110 | let n = tail.len(); 111 | let mut block = Block::::default(); 112 | block[..n].copy_from_slice(tail.get_in()); 113 | block[n..].copy_from_slice(&last_block[n..]); 114 | tail.get_out().copy_from_slice(&last_block[..n]); 115 | 116 | cipher.decrypt_block_inplace(&mut block); 117 | *last_block = block; 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /cts/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![doc = include_str!("../README.md")] 3 | #![doc( 4 | html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", 5 | html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg" 6 | )] 7 | #![deny(unsafe_code)] 8 | #![cfg_attr(docsrs, feature(doc_cfg))] 9 | #![warn(missing_docs, rust_2018_idioms)] 10 | 11 | pub use cipher; 12 | 13 | pub use cipher::{KeyInit, KeyIvInit}; 14 | 15 | mod cbc_cs1; 16 | mod cbc_cs2; 17 | mod cbc_cs3; 18 | mod ecb_cs1; 19 | mod ecb_cs2; 20 | mod ecb_cs3; 21 | 22 | pub use cbc_cs1::CbcCs1; 23 | pub use cbc_cs2::CbcCs2; 24 | pub use cbc_cs3::CbcCs3; 25 | pub use ecb_cs1::EcbCs1; 26 | pub use ecb_cs2::EcbCs2; 27 | pub use ecb_cs3::EcbCs3; 28 | 29 | use cipher::{ 30 | Block, BlockCipherDecBackend, BlockCipherEncBackend, 31 | array::{Array, ArraySize}, 32 | inout::{InOutBuf, NotEqualError}, 33 | typenum::Unsigned, 34 | }; 35 | 36 | /// Error which indicates that message is smaller than cipher's block size. 37 | #[derive(Copy, Clone, Debug)] 38 | pub struct Error; 39 | 40 | /// Encryption functionality of CTS modes. 41 | pub trait Encrypt: Sized { 42 | /// Encrypt `inout` buffer. 43 | fn encrypt_inout(self, buf: InOutBuf<'_, '_, u8>) -> Result<(), Error>; 44 | 45 | /// Encrypt data in-place. 46 | fn encrypt(self, buf: &mut [u8]) -> Result<(), Error> { 47 | self.encrypt_inout(buf.into()) 48 | } 49 | 50 | /// Encrypt data buffer-to-buffer. 51 | fn encrypt_b2b(self, in_buf: &[u8], out_buf: &mut [u8]) -> Result<(), Error> { 52 | InOutBuf::new(in_buf, out_buf) 53 | .map_err(|NotEqualError| Error) 54 | .and_then(|buf| self.encrypt_inout(buf)) 55 | } 56 | } 57 | 58 | /// Decryption functionality of CTS modes. 59 | pub trait Decrypt: Sized { 60 | /// Decrypt `inout` buffer. 61 | fn decrypt_inout(self, buf: InOutBuf<'_, '_, u8>) -> Result<(), Error>; 62 | 63 | /// Decrypt data in-place. 64 | fn decrypt(self, buf: &mut [u8]) -> Result<(), Error> { 65 | self.decrypt_inout(buf.into()) 66 | } 67 | 68 | /// Decrypt data buffer-to-buffer. 69 | fn decrypt_b2b(self, in_buf: &[u8], out_buf: &mut [u8]) -> Result<(), Error> { 70 | InOutBuf::new(in_buf, out_buf) 71 | .map_err(|NotEqualError| Error) 72 | .and_then(|buf| self.decrypt_inout(buf)) 73 | } 74 | } 75 | 76 | fn ecb_enc(cipher: &B, mut blocks: InOutBuf<'_, '_, Block>) { 77 | if B::ParBlocksSize::USIZE > 1 { 78 | let (par_blocks, rem_blocks) = blocks.into_chunks(); 79 | blocks = rem_blocks; 80 | for blocks in par_blocks { 81 | cipher.encrypt_par_blocks(blocks); 82 | } 83 | } 84 | for block in blocks { 85 | cipher.encrypt_block(block); 86 | } 87 | } 88 | 89 | fn ecb_dec(cipher: &B, mut blocks: InOutBuf<'_, '_, Block>) { 90 | if B::ParBlocksSize::USIZE > 1 { 91 | let (par_blocks, rem_blocks) = blocks.into_chunks(); 92 | blocks = rem_blocks; 93 | for blocks in par_blocks { 94 | cipher.decrypt_par_blocks(blocks); 95 | } 96 | } 97 | for block in blocks { 98 | cipher.decrypt_block(block); 99 | } 100 | } 101 | 102 | fn cbc_enc( 103 | cipher: &B, 104 | iv: &mut Block, 105 | mut blocks: InOutBuf<'_, '_, Block>, 106 | ) { 107 | for mut block in blocks.reborrow() { 108 | let mut t = block.clone_in(); 109 | xor(&mut t, iv); 110 | cipher.encrypt_block_inplace(&mut t); 111 | *iv = t.clone(); 112 | *block.get_out() = t; 113 | } 114 | } 115 | 116 | fn cbc_dec( 117 | cipher: &B, 118 | iv: &mut Block, 119 | mut blocks: InOutBuf<'_, '_, Block>, 120 | ) { 121 | if B::ParBlocksSize::USIZE > 1 { 122 | let (par_blocks, rem_blocks) = blocks.into_chunks(); 123 | blocks = rem_blocks; 124 | 125 | for mut blocks in par_blocks { 126 | let in_blocks = blocks.clone_in(); 127 | let mut t = blocks.clone_in(); 128 | 129 | cipher.decrypt_par_blocks_inplace(&mut t); 130 | let n = t.len(); 131 | xor(&mut t[0], iv); 132 | for i in 1..n { 133 | xor(&mut t[i], &in_blocks[i - 1]) 134 | } 135 | *blocks.get_out() = t; 136 | *iv = in_blocks[n - 1].clone(); 137 | } 138 | } 139 | 140 | for mut block in blocks { 141 | let in_block = block.clone_in(); 142 | let mut t = block.clone_in(); 143 | cipher.decrypt_block_inplace(&mut t); 144 | xor(&mut t, iv); 145 | *block.get_out() = t; 146 | *iv = in_block; 147 | } 148 | } 149 | 150 | #[inline(always)] 151 | fn xor(out: &mut Array, buf: &Array) { 152 | for (a, b) in out.iter_mut().zip(buf) { 153 | *a ^= *b; 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /cts/tests/aes128_roundtrip.rs: -------------------------------------------------------------------------------- 1 | use aes::Aes128; 2 | use cts::{ 3 | Decrypt, Encrypt, 4 | cipher::{InnerIvInit, KeyInit, crypto_common::InnerInit}, 5 | }; 6 | 7 | const KEY: [u8; 16] = [0x42; 16]; 8 | const IV: [u8; 16] = [0x24; 16]; 9 | 10 | const N: usize = 256; 11 | const MSG: [u8; N] = { 12 | let mut res = [0u8; N]; 13 | let mut i = 0; 14 | while i < N { 15 | res[i] = i as u8; 16 | i += 1; 17 | } 18 | res 19 | }; 20 | 21 | macro_rules! impl_cbc_roundtrip { 22 | ($name:ident, $mode:ident) => { 23 | #[test] 24 | fn $name() { 25 | let mut buf1 = [0u8; N]; 26 | let mut buf2 = [0u8; N]; 27 | 28 | let cipher = Aes128::new(&KEY.into()); 29 | for i in 16..MSG.len() { 30 | let orig_pt = &MSG[..i]; 31 | let ct = &mut buf1[..i]; 32 | cts::$mode::inner_iv_init(&cipher, &IV.into()) 33 | .encrypt_b2b(orig_pt, ct) 34 | .unwrap(); 35 | 36 | let pt = &mut buf2[..i]; 37 | cts::$mode::inner_iv_init(&cipher, &IV.into()) 38 | .decrypt_b2b(ct, pt) 39 | .unwrap(); 40 | assert_eq!(pt, orig_pt); 41 | 42 | cts::$mode::inner_iv_init(&cipher, &IV.into()) 43 | .encrypt(pt) 44 | .unwrap(); 45 | assert_eq!(pt, ct); 46 | 47 | cts::$mode::inner_iv_init(&cipher, &IV.into()) 48 | .decrypt(pt) 49 | .unwrap(); 50 | assert_eq!(pt, orig_pt); 51 | } 52 | } 53 | }; 54 | } 55 | 56 | impl_cbc_roundtrip!(aes128_cbc_cs1_roundtrip, CbcCs1); 57 | impl_cbc_roundtrip!(aes128_cbc_cs2_roundtrip, CbcCs2); 58 | impl_cbc_roundtrip!(aes128_cbc_cs3_roundtrip, CbcCs3); 59 | 60 | macro_rules! impl_ecb_roundtrip { 61 | ($name:ident, $mode:ident) => { 62 | #[test] 63 | fn $name() { 64 | let mut buf1 = [0u8; N]; 65 | let mut buf2 = [0u8; N]; 66 | 67 | let cipher = Aes128::new(&KEY.into()); 68 | for i in 16..MSG.len() { 69 | let orig_pt = &MSG[..i]; 70 | let ct = &mut buf1[..i]; 71 | cts::$mode::inner_init(&cipher) 72 | .encrypt_b2b(orig_pt, ct) 73 | .unwrap(); 74 | 75 | let pt = &mut buf2[..i]; 76 | cts::$mode::inner_init(&cipher).decrypt_b2b(ct, pt).unwrap(); 77 | assert_eq!(pt, orig_pt); 78 | 79 | cts::$mode::inner_init(&cipher).encrypt(pt).unwrap(); 80 | assert_eq!(pt, ct); 81 | 82 | cts::$mode::inner_init(&cipher).decrypt(pt).unwrap(); 83 | assert_eq!(pt, orig_pt); 84 | } 85 | } 86 | }; 87 | } 88 | 89 | impl_ecb_roundtrip!(aes128_ecb_cs1_roundtrip, EcbCs1); 90 | impl_ecb_roundtrip!(aes128_ecb_cs2_roundtrip, EcbCs2); 91 | impl_ecb_roundtrip!(aes128_ecb_cs3_roundtrip, EcbCs3); 92 | -------------------------------------------------------------------------------- /cts/tests/belt_ecb.rs: -------------------------------------------------------------------------------- 1 | //! Test vectors from STB 34.101.31-2020 (section А.4, tables A.9-10): 2 | //! https://apmi.bsu.by/assets/files/std/belt-spec371.pdf 3 | use belt_block::BeltBlock; 4 | use cts::{Decrypt, Encrypt, KeyInit}; 5 | use hex_literal::hex; 6 | 7 | type BeltEcb = cts::EcbCs2; 8 | 9 | struct TestVector { 10 | key: &'static [u8; 32], 11 | pt: &'static [u8], 12 | ct: &'static [u8], 13 | } 14 | 15 | static TEST_VECTORS: &[TestVector] = &[ 16 | TestVector { 17 | key: &hex!( 18 | "E9DEE72C 8F0C0FA6 2DDB49F4 6F739647" 19 | "06075316 ED247A37 39CBA383 03A98BF6" 20 | ), 21 | pt: &hex!( 22 | "B194BAC8 0A08F53B 366D008E 584A5DE4" 23 | "8504FA9D 1BB6C7AC 252E72C2 02FDCE0D" 24 | "5BE3D612 17B96181 FE6786AD 716B890B" 25 | ), 26 | ct: &hex!( 27 | "69CCA1C9 3557C9E3 D66BC3E0 FA88FA6E" 28 | "5F23102E F1097107 75017F73 806DA9DC" 29 | "46FB2ED2 CE771F26 DCB5E5D1 569F9AB0" 30 | ), 31 | }, 32 | TestVector { 33 | key: &hex!( 34 | "E9DEE72C 8F0C0FA6 2DDB49F4 6F739647" 35 | "06075316 ED247A37 39CBA383 03A98BF6" 36 | ), 37 | pt: &hex!( 38 | "B194BAC8 0A08F53B 366D008E 584A5DE4" 39 | "8504FA9D 1BB6C7AC 252E72C2 02FDCE0D" 40 | "5BE3D612 17B96181 FE6786AD 716B89" 41 | ), 42 | ct: &hex!( 43 | "69CCA1C9 3557C9E3 D66BC3E0 FA88FA6E" 44 | "36F00CFE D6D1CA14 98C12798 F4BEB207" 45 | "5F23102E F1097107 75017F73 806DA9" 46 | ), 47 | }, 48 | TestVector { 49 | key: &hex!( 50 | "92BD9B1C E5D14101 5445FBC9 5E4D0EF2" 51 | "682080AA 227D642F 2687F934 90405511" 52 | ), 53 | pt: &hex!( 54 | "0DC53006 00CAB840 B38448E5 E993F421" 55 | "E55A239F 2AB5C5D5 FDB6E81B 40938E2A" 56 | "54120CA3 E6E19C7A D750FC35 31DAEAB7" 57 | ), 58 | ct: &hex!( 59 | "E12BDC1A E28257EC 703FCCF0 95EE8DF1" 60 | "C1AB7638 9FE678CA F7C6F860 D5BB9C4F" 61 | "F33C657B 637C306A DD4EA779 9EB23D31" 62 | ), 63 | }, 64 | TestVector { 65 | key: &hex!( 66 | "92BD9B1C E5D14101 5445FBC9 5E4D0EF2" 67 | "682080AA 227D642F 2687F934 90405511" 68 | ), 69 | pt: &hex!( 70 | "0DC53006 00CAB840 B38448E5 E993F421" 71 | "5780A6E2 B69EAFBB 258726D7 B6718523" 72 | "E55A239F" 73 | ), 74 | ct: &hex!( 75 | "E12BDC1A E28257EC 703FCCF0 95EE8DF1" 76 | "C1AB7638 9FE678CA F7C6F860 D5BB9C4F" 77 | "F33C657B" 78 | ), 79 | }, 80 | ]; 81 | 82 | #[test] 83 | fn belt_ecb() { 84 | let mut buf = [0u8; 48]; 85 | for &TestVector { key, pt, ct } in TEST_VECTORS { 86 | let buf = &mut buf[..pt.len()]; 87 | BeltEcb::new(key.into()).encrypt_b2b(pt, buf).unwrap(); 88 | assert_eq!(buf, ct); 89 | 90 | BeltEcb::new(key.into()).decrypt(buf).unwrap(); 91 | assert_eq!(buf, pt); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /cts/tests/rfc3962.rs: -------------------------------------------------------------------------------- 1 | //! Test vectors from RFC 3962: https://www.rfc-editor.org/rfc/rfc3962 2 | use cipher::{InnerIvInit, KeyInit}; 3 | use cts::{Decrypt, Encrypt}; 4 | use hex_literal::hex; 5 | 6 | const KEY: [u8; 16] = hex!("636869636b656e207465726979616b69"); 7 | const IV: [u8; 16] = [0u8; 16]; 8 | 9 | static TEST_VECTORS: &[(&[u8], &[u8])] = &[ 10 | ( 11 | &hex!( 12 | "4920776f756c64206c696b6520746865" 13 | "20" 14 | ), 15 | &hex!( 16 | "c6353568f2bf8cb4d8a580362da7ff7f" 17 | "97" 18 | ), 19 | ), 20 | ( 21 | &hex!( 22 | "4920776f756c64206c696b6520746865" 23 | "2047656e6572616c20476175277320" 24 | ), 25 | &hex!( 26 | "fc00783e0efdb2c1d445d4c8eff7ed22" 27 | "97687268d6ecccc0c07b25e25ecfe5" 28 | ), 29 | ), 30 | ( 31 | &hex!( 32 | "4920776f756c64206c696b6520746865" 33 | "2047656e6572616c2047617527732043" 34 | ), 35 | &hex!( 36 | "39312523a78662d5be7fcbcc98ebf5a8" 37 | "97687268d6ecccc0c07b25e25ecfe584" 38 | ), 39 | ), 40 | ( 41 | &hex!( 42 | "4920776f756c64206c696b6520746865" 43 | "2047656e6572616c2047617527732043" 44 | "6869636b656e2c20706c656173652c" 45 | ), 46 | &hex!( 47 | "97687268d6ecccc0c07b25e25ecfe584" 48 | "b3fffd940c16a18c1b5549d2f838029e" 49 | "39312523a78662d5be7fcbcc98ebf5" 50 | ), 51 | ), 52 | ( 53 | &hex!( 54 | "4920776f756c64206c696b6520746865" 55 | "2047656e6572616c2047617527732043" 56 | "6869636b656e2c20706c656173652c20" 57 | ), 58 | &hex!( 59 | "97687268d6ecccc0c07b25e25ecfe584" 60 | "9dad8bbb96c4cdc03bc103e1a194bbd8" 61 | "39312523a78662d5be7fcbcc98ebf5a8" 62 | ), 63 | ), 64 | ( 65 | &hex!( 66 | "4920776f756c64206c696b6520746865" 67 | "2047656e6572616c2047617527732043" 68 | "6869636b656e2c20706c656173652c20" 69 | "616e6420776f6e746f6e20736f75702e" 70 | ), 71 | &hex!( 72 | "97687268d6ecccc0c07b25e25ecfe584" 73 | "39312523a78662d5be7fcbcc98ebf5a8" 74 | "4807efe836ee89a526730dbc2f7bc840" 75 | "9dad8bbb96c4cdc03bc103e1a194bbd8" 76 | ), 77 | ), 78 | ]; 79 | 80 | #[test] 81 | fn rfc3962() { 82 | let cipher = aes::Aes128::new(&KEY.into()); 83 | let iv = IV.into(); 84 | 85 | let mut buf = [0u8; 64]; 86 | for &(input, output) in TEST_VECTORS { 87 | let buf = &mut buf[..input.len()]; 88 | 89 | cts::CbcCs3::inner_iv_init(&cipher, &iv) 90 | .encrypt_b2b(input, buf) 91 | .unwrap(); 92 | assert_eq!(buf, output); 93 | 94 | cts::CbcCs3::inner_iv_init(&cipher, &iv) 95 | .decrypt_b2b(output, buf) 96 | .unwrap(); 97 | assert_eq!(buf, input); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /ige/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## 0.2.0 (UNRELEASED) 9 | ### Removed 10 | - `std` feature ([#76]) 11 | 12 | ### Changed 13 | - Bump `cipher` from `0.4` to `0.5` ([#56]) 14 | - Edition changed to 2024 and MSRV bumped to 1.85 ([#76]) 15 | - Relax MSRV policy and allow MSRV bumps in patch releases 16 | 17 | [#56]: https://github.com/RustCrypto/block-modes/pull/56 18 | [#76]: https://github.com/RustCrypto/block-modes/pull/76 19 | 20 | ## 0.1.1 (2022-02-17) 21 | ### Fixed 22 | - Minimal versions build ([#9]) 23 | 24 | [#9]: https://github.com/RustCrypto/block-modes/pull/9 25 | 26 | ## 0.1.0 (2022-02-10) 27 | - Initial release ([#2]) 28 | 29 | [#2]: https://github.com/RustCrypto/block-modes/pull/2 30 | -------------------------------------------------------------------------------- /ige/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ige" 3 | version = "0.2.0-rc.0" 4 | description = "Infinite Garble Extension (IGE) block cipher mode of operation" 5 | authors = ["RustCrypto Developers"] 6 | license = "MIT OR Apache-2.0" 7 | edition = "2024" 8 | rust-version = "1.85" 9 | readme = "README.md" 10 | documentation = "https://docs.rs/ige" 11 | repository = "https://github.com/RustCrypto/block-modes" 12 | keywords = ["crypto", "block-mode", "ciphers"] 13 | categories = ["cryptography", "no-std"] 14 | 15 | [dependencies] 16 | cipher = "0.5.0-rc.0" 17 | 18 | [dev-dependencies] 19 | aes = "0.9.0-rc.0" 20 | cipher = { version = "0.5.0-rc.0", features = ["dev"] } 21 | hex-literal = "1" 22 | 23 | [features] 24 | default = ["block-padding"] 25 | alloc = ["cipher/alloc"] 26 | block-padding = ["cipher/block-padding"] 27 | zeroize = ["cipher/zeroize"] 28 | 29 | [package.metadata.docs.rs] 30 | all-features = true 31 | rustdoc-args = ["--cfg", "docsrs"] 32 | -------------------------------------------------------------------------------- /ige/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018-2022 RustCrypto Developers 2 | Copyright (c) 2018 Artyom Pavlov 3 | 4 | Permission is hereby granted, free of charge, to any 5 | person obtaining a copy of this software and associated 6 | documentation files (the "Software"), to deal in the 7 | Software without restriction, including without 8 | limitation the rights to use, copy, modify, merge, 9 | publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software 11 | is furnished to do so, subject to the following 12 | conditions: 13 | 14 | The above copyright notice and this permission notice 15 | shall be included in all copies or substantial portions 16 | of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 19 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 20 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 21 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 22 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 23 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 25 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 | DEALINGS IN THE SOFTWARE. 27 | -------------------------------------------------------------------------------- /ige/README.md: -------------------------------------------------------------------------------- 1 | # RustCrypto: IGE 2 | 3 | [![crate][crate-image]][crate-link] 4 | [![Docs][docs-image]][docs-link] 5 | [![Build Status][build-image]][build-link] 6 | ![Apache2/MIT licensed][license-image] 7 | ![Rust Version][rustc-image] 8 | [![Project Chat][chat-image]][chat-link] 9 | 10 | Generic implementation of the [Infinite Garble Extension][IGE] (IGE) 11 | block cipher mode of operation. 12 | 13 | 14 | 15 | See [documentation][cipher-doc] of the `cipher` crate for additional information. 16 | 17 | ## License 18 | 19 | Licensed under either of: 20 | 21 | * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) 22 | * [MIT license](http://opensource.org/licenses/MIT) 23 | 24 | at your option. 25 | 26 | ### Contribution 27 | 28 | Unless you explicitly state otherwise, any contribution intentionally submitted 29 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be 30 | dual licensed as above, without any additional terms or conditions. 31 | 32 | [//]: # (badges) 33 | 34 | [crate-image]: https://img.shields.io/crates/v/ige.svg?logo=rust 35 | [crate-link]: https://crates.io/crates/ige 36 | [docs-image]: https://docs.rs/ige/badge.svg 37 | [docs-link]: https://docs.rs/ige/ 38 | [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg 39 | [rustc-image]: https://img.shields.io/badge/rustc-1.85+-blue.svg 40 | [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg 41 | [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/308460-block-modes 42 | [build-image]: https://github.com/RustCrypto/block-modes/actions/workflows/ige.yaml/badge.svg 43 | [build-link]: https://github.com/RustCrypto/block-modes/actions/workflows/ige.yaml 44 | 45 | [//]: # (general links) 46 | 47 | [CBC]: https://www.links.org/files/openssl-ige.pdf 48 | [cipher-doc]: https://docs.rs/cipher/ 49 | -------------------------------------------------------------------------------- /ige/benches/aes128.rs: -------------------------------------------------------------------------------- 1 | #![feature(test)] 2 | extern crate test; 3 | 4 | use aes::Aes128; 5 | 6 | cipher::block_encryptor_bench!( 7 | KeyIv: ige::Encryptor, 8 | ige_aes128_encrypt_block, 9 | ige_aes128_encrypt_blocks, 10 | ); 11 | 12 | cipher::block_decryptor_bench!( 13 | KeyIv: ige::Decryptor, 14 | ige_aes128_decrypt_block, 15 | ige_aes128_decrypt_blocks, 16 | ); 17 | -------------------------------------------------------------------------------- /ige/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! [Infinite Garble Extension][1] (IGE) block cipher mode of operation. 2 | //! 3 | //! 4 | //! 5 | //! 6 | //! Mode functionality is accessed using traits from re-exported [`cipher`] crate. 7 | //! 8 | //! # ⚠️ Security Warning: Hazmat! 9 | //! 10 | //! This crate does not ensure ciphertexts are authentic! Thus ciphertext integrity 11 | //! is not verified, which can lead to serious vulnerabilities! 12 | //! [AEADs][https://github.com/RustCrypto/AEADs] provide simple authenticated encryption, 13 | //! which is much less error-prone than manual integrity verification. 14 | //! 15 | //! # Example 16 | //! ``` 17 | //! # #[cfg(feature = "block-padding")] { 18 | //! use aes::cipher::{block_padding::Pkcs7, BlockModeEncrypt, BlockModeDecrypt, KeyIvInit}; 19 | //! use hex_literal::hex; 20 | //! 21 | //! type Aes128IgeEnc = ige::Encryptor; 22 | //! type Aes128IgeDec = ige::Decryptor; 23 | //! 24 | //! let key = [0x42; 16]; 25 | //! let iv = [0x24; 32]; 26 | //! let plaintext = *b"hello world! this is my plaintext."; 27 | //! let ciphertext = hex!( 28 | //! "e3da005add5f05d45899f64891f7629b" 29 | //! "6fcff7d21537fcd3569373d25701a5d1" 30 | //! "d9e586e4c5b8ac09f2190485a76873c2" 31 | //! ); 32 | //! 33 | //! // encrypt/decrypt in-place 34 | //! // buffer must be big enough for padded plaintext 35 | //! let mut buf = [0u8; 48]; 36 | //! let pt_len = plaintext.len(); 37 | //! buf[..pt_len].copy_from_slice(&plaintext); 38 | //! let ct = Aes128IgeEnc::new(&key.into(), &iv.into()) 39 | //! .encrypt_padded::(&mut buf, pt_len) 40 | //! .unwrap(); 41 | //! assert_eq!(ct, &ciphertext[..]); 42 | //! 43 | //! let pt = Aes128IgeDec::new(&key.into(), &iv.into()) 44 | //! .decrypt_padded::(&mut buf) 45 | //! .unwrap(); 46 | //! assert_eq!(pt, &plaintext); 47 | //! 48 | //! // encrypt/decrypt from buffer to buffer 49 | //! let mut buf = [0u8; 48]; 50 | //! let ct = Aes128IgeEnc::new(&key.into(), &iv.into()) 51 | //! .encrypt_padded_b2b::(&plaintext, &mut buf) 52 | //! .unwrap(); 53 | //! assert_eq!(ct, &ciphertext[..]); 54 | //! 55 | //! let mut buf = [0u8; 48]; 56 | //! let pt = Aes128IgeDec::new(&key.into(), &iv.into()) 57 | //! .decrypt_padded_b2b::(&ct, &mut buf) 58 | //! .unwrap(); 59 | //! assert_eq!(pt, &plaintext); 60 | //! # } 61 | //! ``` 62 | //! 63 | //! With enabled `alloc` (or `std`) feature you also can use allocating 64 | //! convenience methods: 65 | //! ``` 66 | //! # #[cfg(all(feature = "alloc", feature = "block-padding"))] { 67 | //! # use aes::cipher::{block_padding::Pkcs7, BlockModeEncrypt, BlockModeDecrypt, KeyIvInit}; 68 | //! # use hex_literal::hex; 69 | //! # type Aes128IgeEnc = ige::Encryptor; 70 | //! # type Aes128IgeDec = ige::Decryptor; 71 | //! # let key = [0x42; 16]; 72 | //! # let iv = [0x24; 32]; 73 | //! # let plaintext = *b"hello world! this is my plaintext."; 74 | //! # let ciphertext = hex!( 75 | //! # "e3da005add5f05d45899f64891f7629b" 76 | //! # "6fcff7d21537fcd3569373d25701a5d1" 77 | //! # "d9e586e4c5b8ac09f2190485a76873c2" 78 | //! # ); 79 | //! let res = Aes128IgeEnc::new(&key.into(), &iv.into()) 80 | //! .encrypt_padded_vec::(&plaintext); 81 | //! assert_eq!(res[..], ciphertext[..]); 82 | //! let res = Aes128IgeDec::new(&key.into(), &iv.into()) 83 | //! .decrypt_padded_vec::(&res) 84 | //! .unwrap(); 85 | //! assert_eq!(res[..], plaintext[..]); 86 | //! # } 87 | //! ``` 88 | //! [1]: https://www.links.org/files/openssl-ige.pdf 89 | 90 | #![no_std] 91 | #![doc( 92 | html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", 93 | html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg" 94 | )] 95 | #![forbid(unsafe_code)] 96 | #![cfg_attr(docsrs, feature(doc_auto_cfg))] 97 | #![warn(missing_debug_implementations, missing_docs, rust_2018_idioms)] 98 | 99 | mod decrypt; 100 | mod encrypt; 101 | 102 | pub use cipher; 103 | pub use decrypt::Decryptor; 104 | pub use encrypt::Encryptor; 105 | 106 | use cipher::{ 107 | BlockSizeUser, 108 | array::{Array, ArraySize}, 109 | typenum::Sum, 110 | }; 111 | 112 | type BlockSize = ::BlockSize; 113 | type IgeIvSize = Sum, BlockSize>; 114 | 115 | #[inline(always)] 116 | fn xor(out: &mut Array, buf: &Array) { 117 | for (a, b) in out.iter_mut().zip(buf) { 118 | *a ^= *b; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /ige/tests/aes.rs: -------------------------------------------------------------------------------- 1 | use aes::{Aes128, Aes128Dec, Aes128Enc}; 2 | use cipher::{block_mode_dec_test, block_mode_enc_test, iv_state_test}; 3 | use ige::{Decryptor, Encryptor}; 4 | 5 | iv_state_test!(aes128_ige_enc_iv_state, Encryptor, encrypt); 6 | iv_state_test!(aes128_ige_dec_iv_state, Decryptor, decrypt); 7 | 8 | // Test vectors from: 9 | block_mode_enc_test!(aes128_cbc_enc_test, "aes128", Encryptor); 10 | block_mode_dec_test!(aes128_cbc_dec_test, "aes128", Decryptor); 11 | block_mode_enc_test!(aes128enc_cbc_enc_test, "aes128", Encryptor); 12 | block_mode_dec_test!(aes128dec_cbc_dec_test, "aes128", Decryptor); 13 | -------------------------------------------------------------------------------- /ige/tests/data/aes128.blb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RustCrypto/block-modes/e52ed9c70aa22b8dd07285f4b15981f137960cd5/ige/tests/data/aes128.blb -------------------------------------------------------------------------------- /ofb/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## 0.7.0 (UNRELEASED) 9 | ### Removed 10 | - `std` feature ([#76]) 11 | 12 | ### Changed 13 | - Bump `cipher` from `0.4` to `0.5` ([#56]) 14 | - Edition changed to 2024 and MSRV bumped to 1.85 ([#76]) 15 | - Relax MSRV policy and allow MSRV bumps in patch releases 16 | 17 | [#56]: https://github.com/RustCrypto/block-modes/pull/56 18 | [#76]: https://github.com/RustCrypto/block-modes/pull/76 19 | 20 | ## 0.6.1 (2022-02-17) 21 | ### Fixed 22 | - Minimal versions build ([#9]) 23 | 24 | [#9]: https://github.com/RustCrypto/block-modes/pull/9 25 | 26 | ## 0.6.0 (2022-02-10) 27 | ### Changed 28 | - Update `cipher` dependency to v0.4 and move crate 29 | to the [RustCrypto/block-modes] repository ([#2]) 30 | 31 | [#2]: https://github.com/RustCrypto/block-modes/pull/2 32 | [RustCrypto/block-modes]: https://github.com/RustCrypto/block-modes 33 | 34 | ## 0.5.1 (2021-04-30) 35 | ### Changed 36 | - Removed redundant `NewBlockCipher` bound from `FromBlockCipher` implementation ([#236]) 37 | 38 | [#236]: https://github.com/RustCrypto/stream-ciphers/pull/236 39 | 40 | ## 0.5.0 (2021-04-29) 41 | ### Changed 42 | - Bump `cipher` dependency to v0.3 release ([#226]) 43 | - Bump `aes` dev dependency to v0.7 release ([#232]) 44 | 45 | [#226]: https://github.com/RustCrypto/stream-ciphers/pull/226 46 | [#232]: https://github.com/RustCrypto/stream-ciphers/pull/232 47 | 48 | ## 0.4.0 (2020-10-16) 49 | ### Changed 50 | - Replace `block-cipher`/`stream-cipher` with `cipher` crate ([#177]) 51 | 52 | [#177]: https://github.com/RustCrypto/stream-ciphers/pull/177 53 | 54 | ## 0.3.0 (2020-08-25) 55 | ### Changed 56 | - Bump `stream-cipher` dependency to v0.7, implement the `FromBlockCipher` trait ([#161], [#164]) 57 | 58 | [#161]: https://github.com/RustCrypto/stream-ciphers/pull/161 59 | [#164]: https://github.com/RustCrypto/stream-ciphers/pull/164 60 | 61 | ## 0.2.0 (2020-06-08) 62 | ### Changed 63 | - Bump `stream-cipher` dependency to v0.4 ([#123]) 64 | - Upgrade to Rust 2018 edition ([#123]) 65 | 66 | [#123]: https://github.com/RustCrypto/stream-ciphers/pull/123 67 | 68 | ## 0.1.1 (2019-03-11) 69 | 70 | ## 0.1.0 (2018-12-26) 71 | -------------------------------------------------------------------------------- /ofb/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ofb" 3 | version = "0.7.0-rc.0" 4 | description = "Output Feedback (OFB) block cipher mode of operation" 5 | authors = ["RustCrypto Developers"] 6 | license = "MIT OR Apache-2.0" 7 | edition = "2024" 8 | rust-version = "1.85" 9 | readme = "README.md" 10 | documentation = "https://docs.rs/ofb" 11 | repository = "https://github.com/RustCrypto/block-modes" 12 | keywords = ["crypto", "block-mode", "stream-cipher", "ciphers"] 13 | categories = ["cryptography", "no-std"] 14 | 15 | [dependencies] 16 | cipher = "0.5.0-rc.0" 17 | 18 | [dev-dependencies] 19 | aes = "0.9.0-rc.0" 20 | cipher = { version = "0.5.0-rc.0", features = ["dev"] } 21 | hex-literal = "1" 22 | 23 | [features] 24 | alloc = ["cipher/alloc"] 25 | block-padding = ["cipher/block-padding"] 26 | zeroize = ["cipher/zeroize"] 27 | 28 | [package.metadata.docs.rs] 29 | all-features = true 30 | rustdoc-args = ["--cfg", "docsrs"] 31 | -------------------------------------------------------------------------------- /ofb/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018-2022 RustCrypto Developers 2 | Copyright (c) 2018 Artyom Pavlov 3 | 4 | Permission is hereby granted, free of charge, to any 5 | person obtaining a copy of this software and associated 6 | documentation files (the "Software"), to deal in the 7 | Software without restriction, including without 8 | limitation the rights to use, copy, modify, merge, 9 | publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software 11 | is furnished to do so, subject to the following 12 | conditions: 13 | 14 | The above copyright notice and this permission notice 15 | shall be included in all copies or substantial portions 16 | of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 19 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 20 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 21 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 22 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 23 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 25 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 | DEALINGS IN THE SOFTWARE. 27 | -------------------------------------------------------------------------------- /ofb/README.md: -------------------------------------------------------------------------------- 1 | # RustCrypto: OFB 2 | 3 | [![crate][crate-image]][crate-link] 4 | [![Docs][docs-image]][docs-link] 5 | [![Build Status][build-image]][build-link] 6 | ![Apache2/MIT licensed][license-image] 7 | ![Rust Version][rustc-image] 8 | [![Project Chat][chat-image]][chat-link] 9 | 10 | Generic implementation of the [Output Feedback][OFB] (OFB) block cipher mode 11 | of operation. 12 | 13 | 14 | 15 | See [documentation][cipher-doc] of the `cipher` crate for additional information. 16 | 17 | ## License 18 | 19 | Licensed under either of: 20 | 21 | * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) 22 | * [MIT license](http://opensource.org/licenses/MIT) 23 | 24 | at your option. 25 | 26 | ### Contribution 27 | 28 | Unless you explicitly state otherwise, any contribution intentionally submitted 29 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be 30 | dual licensed as above, without any additional terms or conditions. 31 | 32 | [//]: # (badges) 33 | 34 | [crate-image]: https://img.shields.io/crates/v/ofb.svg?logo=rust 35 | [crate-link]: https://crates.io/crates/ofb 36 | [docs-image]: https://docs.rs/ofb/badge.svg 37 | [docs-link]: https://docs.rs/ofb/ 38 | [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg 39 | [rustc-image]: https://img.shields.io/badge/rustc-1.85+-blue.svg 40 | [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg 41 | [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/308460-block-modes 42 | [build-image]: https://github.com/RustCrypto/block-modes/actions/workflows/ofb.yaml/badge.svg 43 | [build-link]: https://github.com/RustCrypto/block-modes/actions/workflows/ofb.yaml 44 | 45 | [//]: # (general links) 46 | 47 | [OFB]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Output_feedback_(OFB) 48 | [cipher-doc]: https://docs.rs/cipher/ 49 | -------------------------------------------------------------------------------- /ofb/benches/aes128.rs: -------------------------------------------------------------------------------- 1 | #![feature(test)] 2 | extern crate test; 3 | 4 | use aes::Aes128; 5 | 6 | cipher::stream_cipher_bench!( 7 | ofb::Ofb; 8 | ofb_aes128_stream_bench1_16b 16; 9 | ofb_aes128_stream_bench2_256b 256; 10 | ofb_aes128_stream_bench3_1kib 1024; 11 | ofb_aes128_stream_bench4_16kib 16384; 12 | ); 13 | 14 | cipher::block_encryptor_bench!( 15 | KeyIv: ofb::OfbCore, 16 | ofb_aes128_encrypt_block, 17 | ofb_aes128_encrypt_blocks, 18 | ); 19 | 20 | cipher::block_decryptor_bench!( 21 | KeyIv: ofb::OfbCore, 22 | ofb_aes128_decrypt_block, 23 | ofb_aes128_decrypt_blocks, 24 | ); 25 | -------------------------------------------------------------------------------- /ofb/tests/aes.rs: -------------------------------------------------------------------------------- 1 | use aes::*; 2 | use cipher::{block_mode_dec_test, block_mode_enc_test, iv_state_test, stream_cipher_test}; 3 | use ofb::{Ofb, OfbCore}; 4 | 5 | iv_state_test!(aes128_ofb_enc_iv_state, OfbCore, encrypt); 6 | iv_state_test!(aes128_ofb_dec_iv_state, OfbCore, decrypt); 7 | iv_state_test!(aes128_ofb_apply_ks_iv_state, OfbCore, apply_ks); 8 | iv_state_test!(aes192_ofb_enc_iv_state, OfbCore, encrypt); 9 | iv_state_test!(aes192_ofb_dec_iv_state, OfbCore, decrypt); 10 | iv_state_test!(aes192_ofb_apply_ks_iv_state, OfbCore, apply_ks); 11 | iv_state_test!(aes256_ofb_enc_iv_state, OfbCore, encrypt); 12 | iv_state_test!(aes256_ofb_dec_iv_state, OfbCore, decrypt); 13 | iv_state_test!(aes256_ofb_apply_ks_iv_state, OfbCore, apply_ks); 14 | 15 | // Test vectors from CVAP "AES Multiblock Message Test (MMT) Sample Vectors": 16 | // 17 | block_mode_enc_test!(aes128_ofb_enc_test, "aes128", OfbCore); 18 | block_mode_dec_test!(aes128_ofb_dec_test, "aes128", OfbCore); 19 | block_mode_enc_test!(aes128enc_ofb_enc_test, "aes128", OfbCore); 20 | block_mode_dec_test!(aes128dec_ofb_dec_test, "aes128", OfbCore); 21 | stream_cipher_test!(aes128_ofb_stream_test, "aes128", Ofb); 22 | stream_cipher_test!(aes128enc_ofb_stream_test, "aes128", Ofb); 23 | block_mode_enc_test!(aes192_ofb_enc_test, "aes192", OfbCore); 24 | block_mode_dec_test!(aes192_ofb_dec_test, "aes192", OfbCore); 25 | block_mode_enc_test!(aes192enc_ofb_enc_test, "aes192", OfbCore); 26 | block_mode_dec_test!(aes192dec_ofb_dec_test, "aes192", OfbCore); 27 | stream_cipher_test!(aes192_ofb_stream_test, "aes192", Ofb); 28 | stream_cipher_test!(aes192enc_ofb_stream_test, "aes192", Ofb); 29 | block_mode_enc_test!(aes256_ofb_enc_test, "aes256", OfbCore); 30 | block_mode_dec_test!(aes256_ofb_dec_test, "aes256", OfbCore); 31 | block_mode_enc_test!(aes256enc_ofb_enc_test, "aes256", OfbCore); 32 | block_mode_dec_test!(aes256dec_ofb_dec_test, "aes256", OfbCore); 33 | stream_cipher_test!(aes256_ofb_stream_test, "aes256", Ofb); 34 | stream_cipher_test!(aes256enc_ofb_stream_test, "aes256", Ofb); 35 | -------------------------------------------------------------------------------- /ofb/tests/data/aes128.blb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RustCrypto/block-modes/e52ed9c70aa22b8dd07285f4b15981f137960cd5/ofb/tests/data/aes128.blb -------------------------------------------------------------------------------- /ofb/tests/data/aes192.blb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RustCrypto/block-modes/e52ed9c70aa22b8dd07285f4b15981f137960cd5/ofb/tests/data/aes192.blb -------------------------------------------------------------------------------- /ofb/tests/data/aes256.blb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RustCrypto/block-modes/e52ed9c70aa22b8dd07285f4b15981f137960cd5/ofb/tests/data/aes256.blb -------------------------------------------------------------------------------- /pcbc/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## 0.2.0 (UNRELEASED) 9 | ### Removed 10 | - `std` feature ([#76]) 11 | 12 | ### Changed 13 | - Bump `cipher` from `0.4` to `0.5` ([#56]) 14 | - Edition changed to 2024 and MSRV bumped to 1.85 ([#76]) 15 | - Relax MSRV policy and allow MSRV bumps in patch releases 16 | 17 | [#56]: https://github.com/RustCrypto/block-modes/pull/56 18 | [#76]: https://github.com/RustCrypto/block-modes/pull/76 19 | 20 | ## 0.1.2 (2022-03-24) 21 | ### Changed 22 | - Minor code tweaks to help compiler with codegen ([#16]) 23 | 24 | [#16]: https://github.com/RustCrypto/block-modes/pull/16 25 | 26 | ## 0.1.1 (2022-02-17) 27 | ### Fixed 28 | - Minimal versions build ([#9]) 29 | 30 | [#9]: https://github.com/RustCrypto/block-modes/pull/9 31 | 32 | ## 0.1.0 (2022-02-10) 33 | - Initial release ([#2]) 34 | 35 | [#2]: https://github.com/RustCrypto/block-modes/pull/2 36 | -------------------------------------------------------------------------------- /pcbc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pcbc" 3 | version = "0.2.0-rc.0" 4 | description = "Propagating Cipher Block Chaining (PCBC) block cipher mode of operation" 5 | authors = ["RustCrypto Developers"] 6 | license = "MIT OR Apache-2.0" 7 | edition = "2024" 8 | rust-version = "1.85" 9 | readme = "README.md" 10 | documentation = "https://docs.rs/pcbc" 11 | repository = "https://github.com/RustCrypto/block-modes" 12 | keywords = ["crypto", "block-mode", "ciphers"] 13 | categories = ["cryptography", "no-std"] 14 | 15 | [dependencies] 16 | cipher = "0.5.0-rc.0" 17 | 18 | [dev-dependencies] 19 | aes = "0.9.0-rc.0" 20 | cipher = { version = "0.5.0-rc.0", features = ["dev"] } 21 | hex-literal = "1" 22 | 23 | [features] 24 | default = ["block-padding"] 25 | alloc = ["cipher/alloc"] 26 | block-padding = ["cipher/block-padding"] 27 | zeroize = ["cipher/zeroize"] 28 | 29 | [package.metadata.docs.rs] 30 | all-features = true 31 | rustdoc-args = ["--cfg", "docsrs"] 32 | -------------------------------------------------------------------------------- /pcbc/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018-2022 RustCrypto Developers 2 | Copyright (c) 2018 Artyom Pavlov 3 | 4 | Permission is hereby granted, free of charge, to any 5 | person obtaining a copy of this software and associated 6 | documentation files (the "Software"), to deal in the 7 | Software without restriction, including without 8 | limitation the rights to use, copy, modify, merge, 9 | publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software 11 | is furnished to do so, subject to the following 12 | conditions: 13 | 14 | The above copyright notice and this permission notice 15 | shall be included in all copies or substantial portions 16 | of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 19 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 20 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 21 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 22 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 23 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 25 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 | DEALINGS IN THE SOFTWARE. 27 | -------------------------------------------------------------------------------- /pcbc/README.md: -------------------------------------------------------------------------------- 1 | # RustCrypto: PCBC 2 | 3 | [![crate][crate-image]][crate-link] 4 | [![Docs][docs-image]][docs-link] 5 | [![Build Status][build-image]][build-link] 6 | ![Apache2/MIT licensed][license-image] 7 | ![Rust Version][rustc-image] 8 | [![Project Chat][chat-image]][chat-link] 9 | 10 | Generic implementation of the [Propagating Cipher Block Chaining][PCBC] (PCBC) 11 | block cipher mode of operation. 12 | 13 | 14 | 15 | See [documentation][cipher-doc] of the `cipher` crate for additional information. 16 | 17 | ## License 18 | 19 | Licensed under either of: 20 | 21 | * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) 22 | * [MIT license](http://opensource.org/licenses/MIT) 23 | 24 | at your option. 25 | 26 | ### Contribution 27 | 28 | Unless you explicitly state otherwise, any contribution intentionally submitted 29 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be 30 | dual licensed as above, without any additional terms or conditions. 31 | 32 | [//]: # (badges) 33 | 34 | [crate-image]: https://img.shields.io/crates/v/pcbc.svg?logo=rust 35 | [crate-link]: https://crates.io/crates/pcbc 36 | [docs-image]: https://docs.rs/pcbc/badge.svg 37 | [docs-link]: https://docs.rs/pcbc/ 38 | [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg 39 | [rustc-image]: https://img.shields.io/badge/rustc-1.85+-blue.svg 40 | [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg 41 | [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/308460-block-modes 42 | [build-image]: https://github.com/RustCrypto/block-modes/actions/workflows/pcbc.yaml/badge.svg 43 | [build-link]: https://github.com/RustCrypto/block-modes/actions/workflows/pbcb.yaml 44 | 45 | [//]: # (general links) 46 | 47 | [PCBC]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Propagating_cipher_block_chaining_(PCBC) 48 | [cipher-doc]: https://docs.rs/cipher/ 49 | -------------------------------------------------------------------------------- /pcbc/benches/aes128.rs: -------------------------------------------------------------------------------- 1 | #![feature(test)] 2 | extern crate test; 3 | 4 | use aes::Aes128; 5 | 6 | cipher::block_encryptor_bench!( 7 | KeyIv: pcbc::Encryptor, 8 | pcbc_aes128_encrypt_block, 9 | pcbc_aes128_encrypt_blocks, 10 | ); 11 | 12 | cipher::block_decryptor_bench!( 13 | KeyIv: pcbc::Decryptor, 14 | pcbc_aes128_decrypt_block, 15 | pcbc_aes128_decrypt_blocks, 16 | ); 17 | -------------------------------------------------------------------------------- /pcbc/src/decrypt.rs: -------------------------------------------------------------------------------- 1 | use crate::xor; 2 | use cipher::{ 3 | AlgorithmName, Block, BlockCipherDecBackend, BlockCipherDecClosure, BlockCipherDecrypt, 4 | BlockModeDecBackend, BlockModeDecClosure, BlockModeDecrypt, BlockSizeUser, InnerIvInit, Iv, 5 | IvState, ParBlocksSizeUser, 6 | array::Array, 7 | consts::U1, 8 | crypto_common::{BlockSizes, InnerUser, IvSizeUser}, 9 | inout::InOut, 10 | }; 11 | use core::fmt; 12 | 13 | #[cfg(feature = "zeroize")] 14 | use cipher::zeroize::{Zeroize, ZeroizeOnDrop}; 15 | 16 | /// PCBC mode decryptor. 17 | #[derive(Clone)] 18 | pub struct Decryptor 19 | where 20 | C: BlockCipherDecrypt, 21 | { 22 | cipher: C, 23 | iv: Block, 24 | } 25 | 26 | impl BlockSizeUser for Decryptor 27 | where 28 | C: BlockCipherDecrypt, 29 | { 30 | type BlockSize = C::BlockSize; 31 | } 32 | 33 | impl BlockModeDecrypt for Decryptor 34 | where 35 | C: BlockCipherDecrypt, 36 | { 37 | fn decrypt_with_backend(&mut self, f: impl BlockModeDecClosure) { 38 | /// This closure is used to recieve block cipher backend and create 39 | /// respective `Backend` based on it. 40 | struct Closure<'a, BS, BC> 41 | where 42 | BS: BlockSizes, 43 | BC: BlockModeDecClosure, 44 | { 45 | iv: &'a mut Array, 46 | f: BC, 47 | } 48 | 49 | impl BlockSizeUser for Closure<'_, BS, BC> 50 | where 51 | BS: BlockSizes, 52 | BC: BlockModeDecClosure, 53 | { 54 | type BlockSize = BS; 55 | } 56 | 57 | impl BlockCipherDecClosure for Closure<'_, BS, BC> 58 | where 59 | BS: BlockSizes, 60 | BC: BlockModeDecClosure, 61 | { 62 | #[inline(always)] 63 | fn call>( 64 | self, 65 | cipher_backend: &B, 66 | ) { 67 | let Self { iv, f } = self; 68 | f.call(&mut Backend { iv, cipher_backend }); 69 | } 70 | } 71 | 72 | let Self { cipher, iv } = self; 73 | cipher.decrypt_with_backend(Closure { iv, f }) 74 | } 75 | } 76 | 77 | impl InnerUser for Decryptor 78 | where 79 | C: BlockCipherDecrypt, 80 | { 81 | type Inner = C; 82 | } 83 | 84 | impl IvSizeUser for Decryptor 85 | where 86 | C: BlockCipherDecrypt, 87 | { 88 | type IvSize = C::BlockSize; 89 | } 90 | 91 | impl InnerIvInit for Decryptor 92 | where 93 | C: BlockCipherDecrypt, 94 | { 95 | #[inline] 96 | fn inner_iv_init(cipher: C, iv: &Iv) -> Self { 97 | Self { 98 | cipher, 99 | iv: iv.clone(), 100 | } 101 | } 102 | } 103 | 104 | impl IvState for Decryptor 105 | where 106 | C: BlockCipherDecrypt, 107 | { 108 | #[inline] 109 | fn iv_state(&self) -> Iv { 110 | self.iv.clone() 111 | } 112 | } 113 | 114 | impl AlgorithmName for Decryptor 115 | where 116 | C: BlockCipherDecrypt + AlgorithmName, 117 | { 118 | fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { 119 | f.write_str("pcbc::Decryptor<")?; 120 | ::write_alg_name(f)?; 121 | f.write_str(">") 122 | } 123 | } 124 | 125 | impl fmt::Debug for Decryptor 126 | where 127 | C: BlockCipherDecrypt + AlgorithmName, 128 | { 129 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 130 | f.write_str("pcbc::Decryptor<")?; 131 | ::write_alg_name(f)?; 132 | f.write_str("> { ... }") 133 | } 134 | } 135 | 136 | #[cfg(feature = "zeroize")] 137 | impl Drop for Decryptor { 138 | fn drop(&mut self) { 139 | self.iv.zeroize(); 140 | } 141 | } 142 | 143 | #[cfg(feature = "zeroize")] 144 | impl ZeroizeOnDrop for Decryptor {} 145 | 146 | struct Backend<'a, BS, BK> 147 | where 148 | BS: BlockSizes, 149 | BK: BlockCipherDecBackend, 150 | { 151 | iv: &'a mut Array, 152 | cipher_backend: &'a BK, 153 | } 154 | 155 | impl BlockSizeUser for Backend<'_, BS, BK> 156 | where 157 | BS: BlockSizes, 158 | BK: BlockCipherDecBackend, 159 | { 160 | type BlockSize = BS; 161 | } 162 | 163 | impl ParBlocksSizeUser for Backend<'_, BS, BK> 164 | where 165 | BS: BlockSizes, 166 | BK: BlockCipherDecBackend, 167 | { 168 | type ParBlocksSize = U1; 169 | } 170 | 171 | impl BlockModeDecBackend for Backend<'_, BS, BK> 172 | where 173 | BS: BlockSizes, 174 | BK: BlockCipherDecBackend, 175 | { 176 | #[inline(always)] 177 | fn decrypt_block(&mut self, mut block: InOut<'_, '_, Block>) { 178 | let mut t1 = block.clone_in(); 179 | let mut t2 = block.clone_in(); 180 | self.cipher_backend.decrypt_block((&mut t1).into()); 181 | xor(&mut t1, self.iv); 182 | xor(&mut t2, &t1); 183 | *self.iv = t2; 184 | *block.get_out() = t1; 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /pcbc/src/encrypt.rs: -------------------------------------------------------------------------------- 1 | use crate::xor; 2 | use cipher::{ 3 | AlgorithmName, Block, BlockCipherEncBackend, BlockCipherEncClosure, BlockCipherEncrypt, 4 | BlockModeEncBackend, BlockModeEncClosure, BlockModeEncrypt, BlockSizeUser, InnerIvInit, Iv, 5 | IvState, ParBlocksSizeUser, 6 | array::Array, 7 | consts::U1, 8 | crypto_common::{BlockSizes, InnerUser, IvSizeUser}, 9 | inout::InOut, 10 | }; 11 | use core::fmt; 12 | 13 | #[cfg(feature = "zeroize")] 14 | use cipher::zeroize::{Zeroize, ZeroizeOnDrop}; 15 | 16 | /// PCBC mode encryptor. 17 | #[derive(Clone)] 18 | pub struct Encryptor 19 | where 20 | C: BlockCipherEncrypt, 21 | { 22 | cipher: C, 23 | iv: Block, 24 | } 25 | 26 | impl BlockSizeUser for Encryptor 27 | where 28 | C: BlockCipherEncrypt, 29 | { 30 | type BlockSize = C::BlockSize; 31 | } 32 | 33 | impl BlockModeEncrypt for Encryptor 34 | where 35 | C: BlockCipherEncrypt, 36 | { 37 | fn encrypt_with_backend(&mut self, f: impl BlockModeEncClosure) { 38 | /// This closure is used to recieve block cipher backend and create 39 | /// respective `Backend` based on it. 40 | struct Closure<'a, BS, BC> 41 | where 42 | BS: BlockSizes, 43 | BC: BlockModeEncClosure, 44 | { 45 | iv: &'a mut Array, 46 | f: BC, 47 | } 48 | 49 | impl BlockSizeUser for Closure<'_, BS, BC> 50 | where 51 | BS: BlockSizes, 52 | BC: BlockModeEncClosure, 53 | { 54 | type BlockSize = BS; 55 | } 56 | 57 | impl BlockCipherEncClosure for Closure<'_, BS, BC> 58 | where 59 | BS: BlockSizes, 60 | BC: BlockModeEncClosure, 61 | { 62 | #[inline(always)] 63 | fn call>(self, backend: &B) { 64 | let Self { iv, f } = self; 65 | f.call(&mut Backend { iv, backend }); 66 | } 67 | } 68 | 69 | let Self { cipher, iv } = self; 70 | cipher.encrypt_with_backend(Closure { iv, f }) 71 | } 72 | } 73 | 74 | impl InnerUser for Encryptor 75 | where 76 | C: BlockCipherEncrypt, 77 | { 78 | type Inner = C; 79 | } 80 | 81 | impl IvSizeUser for Encryptor 82 | where 83 | C: BlockCipherEncrypt, 84 | { 85 | type IvSize = C::BlockSize; 86 | } 87 | 88 | impl InnerIvInit for Encryptor 89 | where 90 | C: BlockCipherEncrypt, 91 | { 92 | #[inline] 93 | fn inner_iv_init(cipher: C, iv: &Iv) -> Self { 94 | Self { 95 | cipher, 96 | iv: iv.clone(), 97 | } 98 | } 99 | } 100 | 101 | impl IvState for Encryptor 102 | where 103 | C: BlockCipherEncrypt, 104 | { 105 | #[inline] 106 | fn iv_state(&self) -> Iv { 107 | self.iv.clone() 108 | } 109 | } 110 | 111 | impl AlgorithmName for Encryptor 112 | where 113 | C: BlockCipherEncrypt + AlgorithmName, 114 | { 115 | fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { 116 | f.write_str("pcbc::Encryptor<")?; 117 | ::write_alg_name(f)?; 118 | f.write_str(">") 119 | } 120 | } 121 | 122 | impl fmt::Debug for Encryptor 123 | where 124 | C: BlockCipherEncrypt + AlgorithmName, 125 | { 126 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 127 | f.write_str("pcbc::Encryptor<")?; 128 | ::write_alg_name(f)?; 129 | f.write_str("> { ... }") 130 | } 131 | } 132 | 133 | impl Drop for Encryptor { 134 | fn drop(&mut self) { 135 | #[cfg(feature = "zeroize")] 136 | self.iv.zeroize(); 137 | } 138 | } 139 | 140 | #[cfg(feature = "zeroize")] 141 | impl ZeroizeOnDrop for Encryptor {} 142 | 143 | struct Backend<'a, BS, BK> 144 | where 145 | BS: BlockSizes, 146 | BK: BlockCipherEncBackend, 147 | { 148 | iv: &'a mut Array, 149 | backend: &'a BK, 150 | } 151 | 152 | impl BlockSizeUser for Backend<'_, BS, BK> 153 | where 154 | BS: BlockSizes, 155 | BK: BlockCipherEncBackend, 156 | { 157 | type BlockSize = BS; 158 | } 159 | 160 | impl ParBlocksSizeUser for Backend<'_, BS, BK> 161 | where 162 | BS: BlockSizes, 163 | BK: BlockCipherEncBackend, 164 | { 165 | type ParBlocksSize = U1; 166 | } 167 | 168 | impl BlockModeEncBackend for Backend<'_, BS, BK> 169 | where 170 | BS: BlockSizes, 171 | BK: BlockCipherEncBackend, 172 | { 173 | #[inline(always)] 174 | fn encrypt_block(&mut self, mut block: InOut<'_, '_, Block>) { 175 | let mut t1 = block.clone_in(); 176 | let mut t2 = block.clone_in(); 177 | xor(&mut t1, self.iv); 178 | self.backend.encrypt_block((&mut t1).into()); 179 | xor(&mut t2, &t1); 180 | *block.get_out() = t1; 181 | *self.iv = t2; 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /pcbc/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! [Propagating Cipher Block Chaining][1] (PCBC) mode. 2 | //! 3 | //! 4 | //! 5 | //! 6 | //! Mode functionality is accessed using traits from re-exported [`cipher`] crate. 7 | //! 8 | //! # ⚠️ Security Warning: Hazmat! 9 | //! 10 | //! This crate does not ensure ciphertexts are authentic! Thus ciphertext integrity 11 | //! is not verified, which can lead to serious vulnerabilities! 12 | //! [AEADs][https://github.com/RustCrypto/AEADs] provide simple authenticated encryption, 13 | //! which is much less error-prone than manual integrity verification. 14 | //! 15 | //! # Example 16 | //! ``` 17 | //! # #[cfg(feature = "block-padding")] { 18 | //! use aes::cipher::{block_padding::Pkcs7, BlockModeEncrypt, BlockModeDecrypt, KeyIvInit}; 19 | //! use hex_literal::hex; 20 | //! 21 | //! type Aes128PcbcEnc = pcbc::Encryptor; 22 | //! type Aes128PcbcDec = pcbc::Decryptor; 23 | //! 24 | //! let key = [0x42; 16]; 25 | //! let iv = [0x24; 16]; 26 | //! let plaintext = *b"hello world! this is my plaintext."; 27 | //! let ciphertext = hex!( 28 | //! "c7fe247ef97b21f07cbdd26cb5d346bf" 29 | //! "ab13156d0b2f05f91c4837db5157bad5" 30 | //! "62cb0b6fa7816e254a2fc8d852fb4315" 31 | //! ); 32 | //! 33 | //! // encrypt/decrypt in-place 34 | //! // buffer must be big enough for padded plaintext 35 | //! let mut buf = vec![0u8; 48]; 36 | //! let pt_len = plaintext.len(); 37 | //! buf[..pt_len].copy_from_slice(&plaintext); 38 | //! let ct = Aes128PcbcEnc::new(&key.into(), &iv.into()) 39 | //! .encrypt_padded::(&mut buf, pt_len) 40 | //! .unwrap(); 41 | //! assert_eq!(ct, &ciphertext[..]); 42 | //! 43 | //! let pt = Aes128PcbcDec::new(&key.into(), &iv.into()) 44 | //! .decrypt_padded::(&mut buf) 45 | //! .unwrap(); 46 | //! assert_eq!(pt, &plaintext); 47 | //! 48 | //! // encrypt/decrypt from buffer to buffer 49 | //! let mut buf = vec![0u8; 48]; 50 | //! let ct = Aes128PcbcEnc::new(&key.into(), &iv.into()) 51 | //! .encrypt_padded_b2b::(&plaintext, &mut buf) 52 | //! .unwrap(); 53 | //! assert_eq!(ct, &ciphertext[..]); 54 | //! 55 | //! let mut buf = vec![0u8; 48]; 56 | //! let pt = Aes128PcbcDec::new(&key.into(), &iv.into()) 57 | //! .decrypt_padded_b2b::(&ct, &mut buf) 58 | //! .unwrap(); 59 | //! assert_eq!(pt, &plaintext); 60 | //! # } 61 | //! ``` 62 | //! 63 | //! With enabled `alloc` (or `std`) feature you also can use allocating 64 | //! convenience methods: 65 | //! ``` 66 | //! # #[cfg(all(feature = "alloc", feature = "block-padding"))] { 67 | //! # use aes::cipher::{block_padding::Pkcs7, BlockModeEncrypt, BlockModeDecrypt, KeyIvInit}; 68 | //! # use hex_literal::hex; 69 | //! # type Aes128PcbcEnc = pcbc::Encryptor; 70 | //! # type Aes128PcbcDec = pcbc::Decryptor; 71 | //! # let key = [0x42; 16]; 72 | //! # let iv = [0x24; 16]; 73 | //! # let plaintext = *b"hello world! this is my plaintext."; 74 | //! # let ciphertext = hex!( 75 | //! # "c7fe247ef97b21f07cbdd26cb5d346bf" 76 | //! # "ab13156d0b2f05f91c4837db5157bad5" 77 | //! # "62cb0b6fa7816e254a2fc8d852fb4315" 78 | //! # ); 79 | //! let res = Aes128PcbcEnc::new(&key.into(), &iv.into()) 80 | //! .encrypt_padded_vec::(&plaintext); 81 | //! assert_eq!(res[..], ciphertext[..]); 82 | //! let res = Aes128PcbcDec::new(&key.into(), &iv.into()) 83 | //! .decrypt_padded_vec::(&res) 84 | //! .unwrap(); 85 | //! assert_eq!(res[..], plaintext[..]); 86 | //! # } 87 | //! ``` 88 | //! 89 | //! [1]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Propagating_cipher_block_chaining_(PCBC) 90 | 91 | #![no_std] 92 | #![doc( 93 | html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", 94 | html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg" 95 | )] 96 | #![forbid(unsafe_code)] 97 | #![cfg_attr(docsrs, feature(doc_auto_cfg))] 98 | #![warn(missing_debug_implementations, missing_docs, rust_2018_idioms)] 99 | 100 | mod decrypt; 101 | mod encrypt; 102 | 103 | pub use cipher; 104 | pub use decrypt::Decryptor; 105 | pub use encrypt::Encryptor; 106 | 107 | use cipher::array::{Array, ArraySize}; 108 | 109 | #[inline(always)] 110 | fn xor(out: &mut Array, buf: &Array) { 111 | for (a, b) in out.iter_mut().zip(buf) { 112 | *a ^= *b; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /pcbc/tests/aes.rs: -------------------------------------------------------------------------------- 1 | use aes::{Aes128, Aes128Dec, Aes128Enc}; 2 | use cipher::{block_mode_dec_test, block_mode_enc_test, iv_state_test}; 3 | use pcbc::{Decryptor, Encryptor}; 4 | 5 | iv_state_test!(aes128_pcbc_enc_iv_state, Encryptor, encrypt); 6 | iv_state_test!(aes128_pcbc_dec_iv_state, Decryptor, decrypt); 7 | 8 | // The test vectors are generated using this implementation. 9 | block_mode_enc_test!(aes128_pcbc_enc_test, "aes128", Encryptor); 10 | block_mode_dec_test!(aes128_pcbc_dec_test, "aes128", Decryptor); 11 | block_mode_enc_test!(aes128enc_pcbc_enc_test, "aes128", Encryptor); 12 | block_mode_dec_test!(aes128dec_pcbc_dec_test, "aes128", Decryptor); 13 | -------------------------------------------------------------------------------- /pcbc/tests/data/aes128.blb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RustCrypto/block-modes/e52ed9c70aa22b8dd07285f4b15981f137960cd5/pcbc/tests/data/aes128.blb --------------------------------------------------------------------------------