From bf53411848d764748e39defb5fc0584360d9c42f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Thu, 10 Feb 2022 11:34:22 +0300 Subject: [PATCH 1/2] Update crates to cipher v0.4 --- .github/workflows/aes.yml | 135 ++++-- .github/workflows/block-modes.yml | 56 --- .github/workflows/blowfish.yml | 4 +- .github/workflows/cast5.yml | 4 +- .github/workflows/des.yml | 4 +- .github/workflows/gost-modes.yml | 55 --- .github/workflows/idea.yml | 4 +- .github/workflows/kuznyechik.yml | 21 +- .github/workflows/magma.yml | 4 +- .github/workflows/rc2.yml | 4 +- .github/workflows/serpent.yml | 4 +- .github/workflows/sm4.yml | 4 +- .github/workflows/threefish.yml | 4 +- .github/workflows/twofish.yml | 4 +- .github/workflows/workspace.yml | 2 +- .gitignore | 2 + Cargo.lock | 144 ++---- Cargo.toml | 5 +- README.md | 135 ++---- aes/CHANGELOG.md | 11 +- aes/Cargo.lock | 114 ----- aes/Cargo.toml | 28 +- aes/README.md | 4 +- aes/benches/aes128.rs | 61 --- aes/benches/aes192.rs | 61 --- aes/benches/aes256.rs | 61 --- aes/benches/mod.rs | 62 +++ aes/src/armv8.rs | 421 ++++++++--------- aes/src/armv8/decrypt.rs | 72 --- aes/src/armv8/encdec.rs | 158 +++++++ aes/src/armv8/encrypt.rs | 72 --- aes/src/armv8/expand.rs | 2 +- aes/src/armv8/hazmat.rs | 6 +- aes/src/armv8/test_expand.rs | 130 ++++++ aes/src/autodetect.rs | 413 +++++++++++------ aes/src/hazmat.rs | 25 +- aes/src/lib.rs | 99 ++-- aes/src/ni.rs | 313 ++++++++++++- aes/src/ni/aes128.rs | 280 ++++++------ aes/src/ni/aes128/expand.rs | 53 --- aes/src/ni/aes128/test_expand.rs | 107 ----- aes/src/ni/aes192.rs | 336 +++++++------- aes/src/ni/aes192/expand.rs | 110 ----- aes/src/ni/aes192/test_expand.rs | 93 ---- aes/src/ni/aes256.rs | 349 +++++++------- aes/src/ni/aes256/expand.rs | 91 ---- aes/src/ni/aes256/test_expand.rs | 103 ----- aes/src/ni/ctr.rs | 232 ---------- aes/src/ni/hazmat.rs | 12 +- aes/src/ni/test_expand.rs | 275 +++++++++++ aes/src/ni/utils.rs | 40 +- aes/src/soft.rs | 278 ++++++++++-- aes/src/soft/ctr.rs | 17 - aes/src/soft/fixslice32.rs | 122 +++-- aes/src/soft/fixslice64.rs | 124 +++-- aes/tests/ctr.rs | 9 - aes/tests/data/aes128-ctr.blb | Bin 2039 -> 0 bytes aes/tests/data/aes256-ctr.blb | Bin 2055 -> 0 bytes aes/tests/hazmat.rs | 10 +- aes/tests/{lib.rs => mod.rs} | 0 block-modes/CHANGELOG.md | 69 --- block-modes/Cargo.toml | 24 - block-modes/LICENSE-APACHE | 201 -------- block-modes/LICENSE-MIT | 26 -- block-modes/README.md | 64 --- block-modes/src/cbc.rs | 94 ---- block-modes/src/cfb.rs | 124 ----- block-modes/src/cfb8.rs | 74 --- block-modes/src/ecb.rs | 84 ---- block-modes/src/errors.rs | 33 -- block-modes/src/ige.rs | 86 ---- block-modes/src/lib.rs | 111 ----- block-modes/src/ofb.rs | 54 --- block-modes/src/pcbc.rs | 78 ---- block-modes/src/traits.rs | 128 ------ block-modes/src/utils.rs | 43 -- block-modes/tests/data/aes128.iv.bin | Bin 16 -> 0 bytes block-modes/tests/data/aes128.key.bin | 1 - block-modes/tests/data/aes128.plaintext.bin | Bin 288 -> 0 bytes .../tests/data/cbc-aes128.ciphertext.bin | Bin 288 -> 0 bytes .../tests/data/cfb-aes128-2.ciphertext.bin | Bin 480 -> 0 bytes .../tests/data/cfb-aes128-2.plaintext.bin | Bin 480 -> 0 bytes .../tests/data/cfb-aes128.ciphertext.bin | Bin 288 -> 0 bytes .../tests/data/ecb-aes128.ciphertext.bin | Bin 288 -> 0 bytes .../tests/data/ige-aes128-1.ciphertext.bin | 1 - block-modes/tests/data/ige-aes128-1.iv.bin | Bin 32 -> 0 bytes block-modes/tests/data/ige-aes128-1.key.bin | Bin 16 -> 0 bytes .../tests/data/ige-aes128-1.plaintext.bin | Bin 32 -> 0 bytes .../tests/data/ige-aes128-2.ciphertext.bin | 1 - block-modes/tests/data/ige-aes128-2.iv.bin | 1 - block-modes/tests/data/ige-aes128-2.key.bin | 1 - .../tests/data/ige-aes128-2.plaintext.bin | 1 - .../tests/data/ofb-aes128.ciphertext.bin | Bin 288 -> 0 bytes block-modes/tests/lib.rs | 380 ---------------- blowfish/CHANGELOG.md | 8 +- blowfish/Cargo.toml | 17 +- blowfish/README.md | 4 +- blowfish/benches/lib.rs | 3 - blowfish/benches/mod.rs | 16 + blowfish/src/lib.rs | 160 ++++--- blowfish/tests/{lib.rs => mod.rs} | 0 cast5/.gitignore | 1 - cast5/CHANGELOG.md | 8 +- cast5/Cargo.toml | 19 +- cast5/README.md | 4 +- cast5/benches/lib.rs | 3 - cast5/benches/mod.rs | 8 + cast5/src/cast5.rs | 202 --------- cast5/src/lib.rs | 250 +++++++++- cast5/tests/{lib.rs => mod.rs} | 23 +- des/CHANGELOG.md | 8 +- des/Cargo.toml | 18 +- des/README.md | 4 +- des/benches/des.rs | 3 - des/benches/mod.rs | 19 + des/benches/tdes.rs | 3 - des/src/des.rs | 68 ++- des/src/lib.rs | 15 +- des/src/tdes.rs | 329 ++++++++------ des/tests/{lib.rs => mod.rs} | 0 gost-modes/CHANGELOG.md | 38 -- gost-modes/Cargo.toml | 27 -- gost-modes/LICENSE-APACHE | 201 -------- gost-modes/LICENSE-MIT | 25 - gost-modes/README.md | 57 --- gost-modes/src/cbc.rs | 81 ---- gost-modes/src/cfb.rs | 155 ------- gost-modes/src/ctr128.rs | 131 ------ gost-modes/src/ctr64.rs | 131 ------ gost-modes/src/lib.rs | 79 ---- gost-modes/src/ofb.rs | 109 ----- gost-modes/src/utils.rs | 27 -- gost-modes/tests/lib.rs | 206 --------- idea/CHANGELOG.md | 8 +- idea/Cargo.toml | 19 +- idea/README.md | 4 +- idea/benches/lib.rs | 3 - idea/benches/mod.rs | 8 + idea/src/lib.rs | 133 +++--- idea/src/tests.rs | 40 +- idea/tests/{lib.rs => mod.rs} | 0 kuznyechik/CHANGELOG.md | 11 +- kuznyechik/Cargo.toml | 21 +- kuznyechik/README.md | 4 +- kuznyechik/benches/lib.rs | 3 - kuznyechik/benches/mod.rs | 16 + kuznyechik/src/lib.rs | 46 +- kuznyechik/src/macros.rs | 78 ---- kuznyechik/src/soft/backends.rs | 167 +++++++ kuznyechik/src/soft/mod.rs | 271 ++++++----- kuznyechik/src/sse2/backends.rs | 296 ++++++++++++ kuznyechik/src/sse2/mod.rs | 428 ++++++++---------- kuznyechik/tests/lib.rs | 24 - kuznyechik/tests/mod.rs | 70 +++ magma/CHANGELOG.md | 8 +- magma/Cargo.toml | 21 +- magma/README.md | 4 +- magma/benches/lib.rs | 3 - magma/benches/mod.rs | 8 + magma/src/lib.rs | 115 +++-- magma/src/sboxes.rs | 26 +- rc2/CHANGELOG.md | 6 + rc2/Cargo.toml | 17 +- rc2/README.md | 4 +- rc2/benches/lib.rs | 3 - rc2/benches/mod.rs | 8 + rc2/src/lib.rs | 202 +++++---- rc2/tests/{lib.rs => mod.rs} | 2 +- serpent/CHANGELOG.md | 8 +- serpent/Cargo.toml | 19 +- serpent/README.md | 4 +- serpent/benches/lib.rs | 3 - serpent/benches/mod.rs | 8 + serpent/src/lib.rs | 96 ++-- serpent/tests/{lib.rs => mod.rs} | 0 sm4/CHANGELOG.md | 8 +- sm4/Cargo.toml | 30 +- sm4/README.md | 4 +- sm4/benches/lib.rs | 3 - sm4/benches/mod.rs | 8 + sm4/src/consts.rs | 27 ++ sm4/src/lib.rs | 159 ++++--- sm4/tests/{lib.rs => mod.rs} | 2 +- threefish/CHANGELOG.md | 8 +- threefish/Cargo.toml | 24 +- threefish/README.md | 4 +- threefish/benches/lib.rs | 42 -- threefish/benches/mod.rs | 38 ++ threefish/src/consts.rs | 12 +- threefish/src/lib.rs | 123 +++-- threefish/tests/mod.rs | 236 ++++++++++ twofish/CHANGELOG.md | 8 +- twofish/Cargo.toml | 20 +- twofish/README.md | 4 +- twofish/benches/lib.rs | 3 - twofish/benches/mod.rs | 8 + twofish/src/lib.rs | 159 ++++--- twofish/tests/{lib.rs => mod.rs} | 2 +- 198 files changed, 5332 insertions(+), 7303 deletions(-) delete mode 100644 .github/workflows/block-modes.yml delete mode 100644 .github/workflows/gost-modes.yml delete mode 100644 aes/Cargo.lock delete mode 100644 aes/benches/aes128.rs delete mode 100644 aes/benches/aes192.rs delete mode 100644 aes/benches/aes256.rs create mode 100644 aes/benches/mod.rs delete mode 100644 aes/src/armv8/decrypt.rs create mode 100644 aes/src/armv8/encdec.rs delete mode 100644 aes/src/armv8/encrypt.rs create mode 100644 aes/src/armv8/test_expand.rs delete mode 100644 aes/src/ni/aes128/expand.rs delete mode 100644 aes/src/ni/aes128/test_expand.rs delete mode 100644 aes/src/ni/aes192/expand.rs delete mode 100644 aes/src/ni/aes192/test_expand.rs delete mode 100644 aes/src/ni/aes256/expand.rs delete mode 100644 aes/src/ni/aes256/test_expand.rs delete mode 100644 aes/src/ni/ctr.rs create mode 100644 aes/src/ni/test_expand.rs delete mode 100644 aes/src/soft/ctr.rs delete mode 100644 aes/tests/ctr.rs delete mode 100644 aes/tests/data/aes128-ctr.blb delete mode 100644 aes/tests/data/aes256-ctr.blb rename aes/tests/{lib.rs => mod.rs} (100%) delete mode 100644 block-modes/CHANGELOG.md delete mode 100644 block-modes/Cargo.toml delete mode 100644 block-modes/LICENSE-APACHE delete mode 100644 block-modes/LICENSE-MIT delete mode 100644 block-modes/README.md delete mode 100644 block-modes/src/cbc.rs delete mode 100644 block-modes/src/cfb.rs delete mode 100644 block-modes/src/cfb8.rs delete mode 100644 block-modes/src/ecb.rs delete mode 100644 block-modes/src/errors.rs delete mode 100644 block-modes/src/ige.rs delete mode 100644 block-modes/src/lib.rs delete mode 100644 block-modes/src/ofb.rs delete mode 100644 block-modes/src/pcbc.rs delete mode 100644 block-modes/src/traits.rs delete mode 100644 block-modes/src/utils.rs delete mode 100644 block-modes/tests/data/aes128.iv.bin delete mode 100644 block-modes/tests/data/aes128.key.bin delete mode 100644 block-modes/tests/data/aes128.plaintext.bin delete mode 100644 block-modes/tests/data/cbc-aes128.ciphertext.bin delete mode 100644 block-modes/tests/data/cfb-aes128-2.ciphertext.bin delete mode 100644 block-modes/tests/data/cfb-aes128-2.plaintext.bin delete mode 100644 block-modes/tests/data/cfb-aes128.ciphertext.bin delete mode 100644 block-modes/tests/data/ecb-aes128.ciphertext.bin delete mode 100644 block-modes/tests/data/ige-aes128-1.ciphertext.bin delete mode 100644 block-modes/tests/data/ige-aes128-1.iv.bin delete mode 100644 block-modes/tests/data/ige-aes128-1.key.bin delete mode 100644 block-modes/tests/data/ige-aes128-1.plaintext.bin delete mode 100644 block-modes/tests/data/ige-aes128-2.ciphertext.bin delete mode 100644 block-modes/tests/data/ige-aes128-2.iv.bin delete mode 100644 block-modes/tests/data/ige-aes128-2.key.bin delete mode 100644 block-modes/tests/data/ige-aes128-2.plaintext.bin delete mode 100644 block-modes/tests/data/ofb-aes128.ciphertext.bin delete mode 100644 block-modes/tests/lib.rs delete mode 100644 blowfish/benches/lib.rs create mode 100644 blowfish/benches/mod.rs rename blowfish/tests/{lib.rs => mod.rs} (100%) delete mode 100644 cast5/.gitignore delete mode 100644 cast5/benches/lib.rs create mode 100644 cast5/benches/mod.rs delete mode 100644 cast5/src/cast5.rs rename cast5/tests/{lib.rs => mod.rs} (79%) delete mode 100644 des/benches/des.rs create mode 100644 des/benches/mod.rs delete mode 100644 des/benches/tdes.rs rename des/tests/{lib.rs => mod.rs} (100%) delete mode 100644 gost-modes/CHANGELOG.md delete mode 100644 gost-modes/Cargo.toml delete mode 100644 gost-modes/LICENSE-APACHE delete mode 100644 gost-modes/LICENSE-MIT delete mode 100644 gost-modes/README.md delete mode 100644 gost-modes/src/cbc.rs delete mode 100644 gost-modes/src/cfb.rs delete mode 100644 gost-modes/src/ctr128.rs delete mode 100644 gost-modes/src/ctr64.rs delete mode 100644 gost-modes/src/lib.rs delete mode 100644 gost-modes/src/ofb.rs delete mode 100644 gost-modes/src/utils.rs delete mode 100644 gost-modes/tests/lib.rs delete mode 100644 idea/benches/lib.rs create mode 100644 idea/benches/mod.rs rename idea/tests/{lib.rs => mod.rs} (100%) delete mode 100644 kuznyechik/benches/lib.rs create mode 100644 kuznyechik/benches/mod.rs delete mode 100644 kuznyechik/src/macros.rs create mode 100644 kuznyechik/src/soft/backends.rs create mode 100644 kuznyechik/src/sse2/backends.rs delete mode 100644 kuznyechik/tests/lib.rs create mode 100644 kuznyechik/tests/mod.rs delete mode 100644 magma/benches/lib.rs create mode 100644 magma/benches/mod.rs delete mode 100644 rc2/benches/lib.rs create mode 100644 rc2/benches/mod.rs rename rc2/tests/{lib.rs => mod.rs} (97%) delete mode 100644 serpent/benches/lib.rs create mode 100644 serpent/benches/mod.rs rename serpent/tests/{lib.rs => mod.rs} (100%) delete mode 100644 sm4/benches/lib.rs create mode 100644 sm4/benches/mod.rs create mode 100644 sm4/src/consts.rs rename sm4/tests/{lib.rs => mod.rs} (94%) delete mode 100644 threefish/benches/lib.rs create mode 100644 threefish/benches/mod.rs create mode 100644 threefish/tests/mod.rs delete mode 100644 twofish/benches/lib.rs create mode 100644 twofish/benches/mod.rs rename twofish/tests/{lib.rs => mod.rs} (98%) diff --git a/.github/workflows/aes.yml b/.github/workflows/aes.yml index d35e775f..4f8d7690 100644 --- a/.github/workflows/aes.yml +++ b/.github/workflows/aes.yml @@ -23,7 +23,7 @@ jobs: strategy: matrix: rust: - - 1.49.0 # MSRV + - 1.56.0 # MSRV - stable target: - thumbv7em-none-eabi @@ -36,13 +36,25 @@ jobs: target: ${{ matrix.target }} profile: minimal override: true - - run: cargo check --features compact,ctr,force-soft - - run: cargo build --release --target ${{ matrix.target }} - - run: cargo build --release --target ${{ matrix.target }} --features compact - - run: cargo build --release --target ${{ matrix.target }} --features ctr - - run: cargo build --release --target ${{ matrix.target }} --features force-soft - - run: cargo build --release --target ${{ matrix.target }} --features hazmat - - run: cargo build --release --target ${{ matrix.target }} --features compact,ctr,force-soft + - run: cargo check + - run: | + cargo build --target ${{ matrix.target }} + cargo build --target ${{ matrix.target }} --features hazmat + - env: + RUSTFLAGS: "-Dwarnings --cfg aes_force_soft" + run: | + cargo build --target ${{ matrix.target }} + cargo build --target ${{ matrix.target }} --features hazmat + - env: + RUSTFLAGS: "-Dwarnings --cfg aes_compact" + run: | + cargo build --target ${{ matrix.target }} + cargo build --target ${{ matrix.target }} --features hazmat + - env: + RUSTFLAGS: "-Dwarnings --cfg aes_force_soft --cfg aes_compact" + run: | + cargo build --target ${{ matrix.target }} + cargo build --target ${{ matrix.target }} --features hazmat # Tests for the AES-NI backend aesni: @@ -56,7 +68,7 @@ jobs: include: # 32-bit Linux - target: i686-unknown-linux-gnu - rust: 1.49.0 # MSRV + rust: 1.56.0 # MSRV deps: sudo apt update && sudo apt install gcc-multilib - target: i686-unknown-linux-gnu rust: stable @@ -64,7 +76,7 @@ jobs: # 64-bit Linux - target: x86_64-unknown-linux-gnu - rust: 1.49.0 # MSRV + rust: 1.56.0 # MSRV - target: x86_64-unknown-linux-gnu rust: stable steps: @@ -76,12 +88,9 @@ jobs: profile: minimal override: true - run: ${{ matrix.deps }} - - run: cargo test --release --target ${{ matrix.target }} - - run: cargo test --release --target ${{ matrix.target }} --features compact - - run: cargo test --release --target ${{ matrix.target }} --features ctr - - run: cargo test --release --target ${{ matrix.target }} --features force-soft - - run: cargo test --release --target ${{ matrix.target }} --features hazmat - - run: cargo test --release --target ${{ matrix.target }} --all-features + - run: cargo test --target ${{ matrix.target }} + - run: cargo test --target ${{ matrix.target }} --features hazmat + - run: cargo test --target ${{ matrix.target }} --all-features # Tests for CPU feature autodetection with fallback to portable software implementation autodetect: @@ -91,7 +100,7 @@ jobs: include: # 32-bit Linux - target: i686-unknown-linux-gnu - rust: 1.49.0 # MSRV + rust: 1.56.0 # MSRV deps: sudo apt update && sudo apt install gcc-multilib - target: i686-unknown-linux-gnu rust: stable @@ -99,7 +108,7 @@ jobs: # 64-bit Linux - target: x86_64-unknown-linux-gnu - rust: 1.49.0 # MSRV + rust: 1.56.0 # MSRV - target: x86_64-unknown-linux-gnu rust: stable steps: @@ -111,21 +120,21 @@ jobs: profile: minimal override: true - run: ${{ matrix.deps }} - - run: cargo test --release --target ${{ matrix.target }} - - run: cargo test --release --target ${{ matrix.target }} --features compact - - run: cargo test --release --target ${{ matrix.target }} --features ctr - - run: cargo test --release --target ${{ matrix.target }} --features hazmat - - run: cargo test --release --target ${{ matrix.target }} --all-features + - run: cargo test --target ${{ matrix.target }} + - run: cargo test --target ${{ matrix.target }} --features hazmat + - run: cargo test --target ${{ matrix.target }} --all-features - # Tests for the portable software backend (i.e. `force-soft`-only) + # Tests for the portable software backend (i.e. `aes_force_soft`-only) soft: runs-on: ubuntu-latest + env: + RUSTFLAGS: "-Dwarnings --cfg aes_force_soft" strategy: matrix: include: # 32-bit Linux - target: i686-unknown-linux-gnu - rust: 1.41.0 # MSRV (temporarily lower than with CPU feature auto-detection) + rust: 1.56.0 # MSRV deps: sudo apt update && sudo apt install gcc-multilib - target: i686-unknown-linux-gnu rust: stable @@ -133,7 +142,7 @@ jobs: # 64-bit Linux - target: x86_64-unknown-linux-gnu - rust: 1.41.0 # MSRV (temporarily lower than with CPU feature auto-detection) + rust: 1.56.0 # MSRV - target: x86_64-unknown-linux-gnu rust: stable steps: @@ -145,10 +154,9 @@ jobs: profile: minimal override: true - run: ${{ matrix.deps }} - - run: cargo test --release --target ${{ matrix.target }} --features force-soft - - run: cargo test --release --target ${{ matrix.target }} --features force-soft,compact - - run: cargo test --release --target ${{ matrix.target }} --features force-soft,ctr - - run: cargo test --release --target ${{ matrix.target }} --features force-soft,compact,ctr + - run: cargo test --target ${{ matrix.target }} + - run: cargo test --target ${{ matrix.target }} --all-features + # Cross-compiled tests cross: @@ -157,16 +165,20 @@ jobs: include: # ARM64 - target: aarch64-unknown-linux-gnu - rust: 1.49.0 # MSRV + rust: 1.56.0 # MSRV - target: aarch64-unknown-linux-gnu rust: stable # PPC32 - target: powerpc-unknown-linux-gnu - rust: 1.49.0 # MSRV + rust: 1.56.0 # MSRV - target: powerpc-unknown-linux-gnu rust: stable runs-on: ubuntu-latest + # Cross mounts only current package, i.e. by default it ignores workspace's Cargo.toml + defaults: + run: + working-directory: . steps: - uses: actions/checkout@v1 - run: ${{ matrix.deps }} @@ -176,22 +188,45 @@ jobs: target: ${{ matrix.target }} profile: minimal override: true - - run: cargo install cross - - run: cross test --release --target ${{ matrix.target }} - - run: cross test --release --target ${{ matrix.target }} --features compact - - run: cross test --release --target ${{ matrix.target }} --features ctr - - run: cross test --release --target ${{ matrix.target }} --features force-soft - - run: cross test --release --target ${{ matrix.target }} --features hazmat - - run: cross test --release --target ${{ matrix.target }} --features compact,ctr,force-soft,hazmat + - name: Install pre-compiled cross + run: | + export URL=$(curl -s https://api.github.com/repos/cross-rs/cross/releases/latest | jq -r '.assets[] | select(.name | contains("x86_64-unknown-linux-gnu.tar.gz")) | .browser_download_url') + wget -O /tmp/binaries.tar.gz $URL + tar -C /tmp -xzf /tmp/binaries.tar.gz + mv /tmp/cross ~/.cargo/bin + - run: | + cross test --package aes --target ${{ matrix.target }} + cross test --package aes --target ${{ matrix.target }} --features hazmat + - env: + RUSTFLAGS: "-Dwarnings --cfg aes_force_soft" + run: | + cross test --package aes --target ${{ matrix.target }} + cross test --package aes --target ${{ matrix.target }} --features hazmat + - env: + RUSTFLAGS: "-Dwarnings --cfg aes_compact" + run: | + cross test --package aes --target ${{ matrix.target }} + cross test --package aes --target ${{ matrix.target }} --features hazmat + - env: + RUSTFLAGS: "-Dwarnings --cfg aes_force_soft --cfg aes_compact" + run: | + cross test --package aes --target ${{ matrix.target }} + cross test --package aes --target ${{ matrix.target }} --features hazmat # ARMv8 cross-compiled tests for AES intrinsics (nightly-only) armv8: + env: + RUSTFLAGS: "-Dwarnings --cfg aes_armv8" strategy: matrix: include: - target: aarch64-unknown-linux-gnu rust: nightly runs-on: ubuntu-latest + # Cross mounts only current package, i.e. by default it ignores workspace's Cargo.toml + defaults: + run: + working-directory: . steps: - uses: actions/checkout@v1 - run: ${{ matrix.deps }} @@ -201,22 +236,26 @@ jobs: target: ${{ matrix.target }} profile: minimal override: true - - run: cargo install cross - - run: cross test --release --target ${{ matrix.target }} --features armv8 - - run: cross test --release --target ${{ matrix.target }} --features armv8,compact - - run: cross test --release --target ${{ matrix.target }} --features armv8,ctr - - run: cross test --release --target ${{ matrix.target }} --features armv8,force-soft - - run: cross test --release --target ${{ matrix.target }} --features armv8,hazmat - - run: cross test --release --target ${{ matrix.target }} --all-features + - name: Install pre-compiled cross + run: | + export URL=$(curl -s https://api.github.com/repos/cross-rs/cross/releases/latest | jq -r '.assets[] | select(.name | contains("x86_64-unknown-linux-gnu.tar.gz")) | .browser_download_url') + wget -O /tmp/binaries.tar.gz $URL + tar -C /tmp -xzf /tmp/binaries.tar.gz + mv /tmp/cross ~/.cargo/bin + - run: cross test --package aes --target ${{ matrix.target }} + - run: cross test --package aes --target ${{ matrix.target }} --features hazmat + - run: cross test --package aes --target ${{ matrix.target }} --all-features clippy: + env: + RUSTFLAGS: "-Dwarnings --cfg aes_compact" runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - uses: actions-rs/toolchain@v1 with: - toolchain: 1.49.0 # MSRV + toolchain: 1.56.0 # MSRV components: clippy override: true profile: minimal - - run: cargo clippy --features compact,ctr,hazmat -- -D warnings + - run: cargo clippy --features hazmat -- -D warnings diff --git a/.github/workflows/block-modes.yml b/.github/workflows/block-modes.yml deleted file mode 100644 index 3eb1e2b1..00000000 --- a/.github/workflows/block-modes.yml +++ /dev/null @@ -1,56 +0,0 @@ -name: block-modes - -on: - pull_request: - paths: - - "block-modes/**" - - "Cargo.*" - push: - branches: master - -defaults: - run: - working-directory: block-modes - -env: - CARGO_INCREMENTAL: 0 - RUSTFLAGS: "-Dwarnings" - -jobs: - build: - runs-on: ubuntu-latest - strategy: - matrix: - rust: - - 1.41.0 # MSRV - - stable - target: - - thumbv7em-none-eabi - - wasm32-unknown-unknown - steps: - - uses: actions/checkout@v1 - - uses: actions-rs/toolchain@v1 - with: - toolchain: ${{ matrix.rust }} - target: ${{ matrix.target }} - override: true - profile: minimal - - run: cargo build --no-default-features --release --target ${{ matrix.target }} - - test: - runs-on: ubuntu-latest - strategy: - matrix: - rust: - - 1.41.0 # MSRV - - stable - steps: - - uses: actions/checkout@v1 - - uses: actions-rs/toolchain@v1 - with: - toolchain: ${{ matrix.rust }} - override: true - profile: minimal - - run: cargo check - - run: cargo test - - run: cargo test --all-features diff --git a/.github/workflows/blowfish.yml b/.github/workflows/blowfish.yml index bad60955..0eb67575 100644 --- a/.github/workflows/blowfish.yml +++ b/.github/workflows/blowfish.yml @@ -22,7 +22,7 @@ jobs: strategy: matrix: rust: - - 1.41.0 # MSRV + - 1.56.0 # MSRV - stable target: - thumbv7em-none-eabi @@ -42,7 +42,7 @@ jobs: strategy: matrix: rust: - - 1.41.0 # MSRV + - 1.56.0 # MSRV - stable steps: - uses: actions/checkout@v1 diff --git a/.github/workflows/cast5.yml b/.github/workflows/cast5.yml index 76ca07c6..f7be92e7 100644 --- a/.github/workflows/cast5.yml +++ b/.github/workflows/cast5.yml @@ -22,7 +22,7 @@ jobs: strategy: matrix: rust: - - 1.41.0 # MSRV + - 1.56.0 # MSRV - stable target: - thumbv7em-none-eabi @@ -42,7 +42,7 @@ jobs: strategy: matrix: rust: - - 1.41.0 # MSRV + - 1.56.0 # MSRV - stable steps: - uses: actions/checkout@v1 diff --git a/.github/workflows/des.yml b/.github/workflows/des.yml index 697a26bd..b6c15c5c 100644 --- a/.github/workflows/des.yml +++ b/.github/workflows/des.yml @@ -22,7 +22,7 @@ jobs: strategy: matrix: rust: - - 1.41.0 # MSRV + - 1.56.0 # MSRV - stable target: - thumbv7em-none-eabi @@ -42,7 +42,7 @@ jobs: strategy: matrix: rust: - - 1.41.0 # MSRV + - 1.56.0 # MSRV - stable steps: - uses: actions/checkout@v1 diff --git a/.github/workflows/gost-modes.yml b/.github/workflows/gost-modes.yml deleted file mode 100644 index 4faf8cce..00000000 --- a/.github/workflows/gost-modes.yml +++ /dev/null @@ -1,55 +0,0 @@ -name: gost-modes - -on: - pull_request: - paths: - - "gost-modes/**" - - "Cargo.*" - push: - branches: master - -defaults: - run: - working-directory: gost-modes - -env: - CARGO_INCREMENTAL: 0 - RUSTFLAGS: "-Dwarnings" - -jobs: - build: - runs-on: ubuntu-latest - strategy: - matrix: - rust: - - 1.41.0 # MSRV - - stable - target: - - thumbv7em-none-eabi - - wasm32-unknown-unknown - steps: - - uses: actions/checkout@v1 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.rust }} - target: ${{ matrix.target }} - override: true - - run: cargo build --no-default-features --release --target ${{ matrix.target }} - - test: - runs-on: ubuntu-latest - strategy: - matrix: - rust: - - 1.41.0 # MSRV - - stable - steps: - - uses: actions/checkout@v1 - - uses: actions-rs/toolchain@v1 - with: - toolchain: ${{ matrix.rust }} - override: true - profile: minimal - - run: cargo test -- no-default-features - - run: cargo test diff --git a/.github/workflows/idea.yml b/.github/workflows/idea.yml index 76362696..5c9df2e6 100644 --- a/.github/workflows/idea.yml +++ b/.github/workflows/idea.yml @@ -22,7 +22,7 @@ jobs: strategy: matrix: rust: - - 1.41.0 # MSRV + - 1.56.0 # MSRV - stable target: - thumbv7em-none-eabi @@ -42,7 +42,7 @@ jobs: strategy: matrix: rust: - - 1.41.0 # MSRV + - 1.56.0 # MSRV - stable steps: - uses: actions/checkout@v1 diff --git a/.github/workflows/kuznyechik.yml b/.github/workflows/kuznyechik.yml index 4e616896..64b9f1dc 100644 --- a/.github/workflows/kuznyechik.yml +++ b/.github/workflows/kuznyechik.yml @@ -22,7 +22,7 @@ jobs: strategy: matrix: rust: - - 1.41.0 # MSRV + - 1.56.0 # MSRV - stable target: - thumbv7em-none-eabi @@ -35,14 +35,17 @@ jobs: toolchain: ${{ matrix.rust }} target: ${{ matrix.target }} override: true - - run: cargo build --release --target ${{ matrix.target }} + - run: cargo build --target ${{ matrix.target }} + - env: + RUSTFLAGS: "-Dwarnings --cfg kuznyechik_force_soft" + run: cargo build --target ${{ matrix.target }} test: runs-on: ubuntu-latest strategy: matrix: rust: - - 1.41.0 # MSRV + - 1.56.0 # MSRV - stable steps: - uses: actions/checkout@v1 @@ -51,7 +54,11 @@ jobs: toolchain: ${{ matrix.rust }} override: true profile: minimal - - run: cargo test - - run: cargo test --features no_unroll - - run: cargo test --features force-soft - - run: cargo test --features force-soft,no_unroll + - run: | + cargo test + cargo test --all-features + - env: + RUSTFLAGS: "-Dwarnings --cfg kuznyechik_force_soft" + run: | + cargo test + cargo test --all-features diff --git a/.github/workflows/magma.yml b/.github/workflows/magma.yml index ef7806ea..ea7a3768 100644 --- a/.github/workflows/magma.yml +++ b/.github/workflows/magma.yml @@ -22,7 +22,7 @@ jobs: strategy: matrix: rust: - - 1.41.0 # MSRV + - 1.56.0 # MSRV - stable target: - thumbv7em-none-eabi @@ -42,7 +42,7 @@ jobs: strategy: matrix: rust: - - 1.41.0 # MSRV + - 1.56.0 # MSRV - stable steps: - uses: actions/checkout@v1 diff --git a/.github/workflows/rc2.yml b/.github/workflows/rc2.yml index f5ab0e73..f22ece39 100644 --- a/.github/workflows/rc2.yml +++ b/.github/workflows/rc2.yml @@ -22,7 +22,7 @@ jobs: strategy: matrix: rust: - - 1.41.0 # MSRV + - 1.56.0 # MSRV - stable target: - thumbv7em-none-eabi @@ -42,7 +42,7 @@ jobs: strategy: matrix: rust: - - 1.41.0 # MSRV + - 1.56.0 # MSRV - stable steps: - uses: actions/checkout@v1 diff --git a/.github/workflows/serpent.yml b/.github/workflows/serpent.yml index aa20f6c5..3919ab53 100644 --- a/.github/workflows/serpent.yml +++ b/.github/workflows/serpent.yml @@ -22,7 +22,7 @@ jobs: strategy: matrix: rust: - - 1.41.0 # MSRV + - 1.56.0 # MSRV - stable target: - thumbv7em-none-eabi @@ -42,7 +42,7 @@ jobs: strategy: matrix: rust: - - 1.41.0 # MSRV + - 1.56.0 # MSRV - stable steps: - uses: actions/checkout@v1 diff --git a/.github/workflows/sm4.yml b/.github/workflows/sm4.yml index d6add3a8..de7ce34b 100644 --- a/.github/workflows/sm4.yml +++ b/.github/workflows/sm4.yml @@ -22,7 +22,7 @@ jobs: strategy: matrix: rust: - - 1.41.0 # MSRV + - 1.56.0 # MSRV - stable target: - thumbv7em-none-eabi @@ -42,7 +42,7 @@ jobs: strategy: matrix: rust: - - 1.41.0 # MSRV + - 1.56.0 # MSRV - stable steps: - uses: actions/checkout@v1 diff --git a/.github/workflows/threefish.yml b/.github/workflows/threefish.yml index 2fd00efc..566038e9 100644 --- a/.github/workflows/threefish.yml +++ b/.github/workflows/threefish.yml @@ -22,7 +22,7 @@ jobs: strategy: matrix: rust: - - 1.41.0 # MSRV + - 1.56.0 # MSRV - stable target: - thumbv7em-none-eabi @@ -42,7 +42,7 @@ jobs: strategy: matrix: rust: - - 1.41.0 # MSRV + - 1.56.0 # MSRV - stable steps: - uses: actions/checkout@v1 diff --git a/.github/workflows/twofish.yml b/.github/workflows/twofish.yml index bb0f7e8f..4db2428a 100644 --- a/.github/workflows/twofish.yml +++ b/.github/workflows/twofish.yml @@ -22,7 +22,7 @@ jobs: strategy: matrix: rust: - - 1.41.0 # MSRV + - 1.56.0 # MSRV - stable target: - thumbv7em-none-eabi @@ -42,7 +42,7 @@ jobs: strategy: matrix: rust: - - 1.41.0 # MSRV + - 1.56.0 # MSRV - stable steps: - uses: actions/checkout@v1 diff --git a/.github/workflows/workspace.yml b/.github/workflows/workspace.yml index 79bb4c61..92d418ac 100644 --- a/.github/workflows/workspace.yml +++ b/.github/workflows/workspace.yml @@ -16,7 +16,7 @@ jobs: - uses: actions/checkout@v1 - uses: actions-rs/toolchain@v1 with: - toolchain: 1.41.0 # MSRV + toolchain: 1.56.0 # MSRV components: clippy override: true profile: minimal diff --git a/.gitignore b/.gitignore index 2f7896d1..9111bb1d 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ target/ +**/Cargo.lock +**/target/ diff --git a/Cargo.lock b/Cargo.lock index bec276e3..ba1bb0df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,45 +4,26 @@ version = 3 [[package]] name = "aes" -version = "0.7.5" +version = "0.8.0" dependencies = [ "cfg-if", "cipher", "cpufeatures", - "ctr", "hex-literal", - "opaque-debug", ] [[package]] name = "blobby" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc52553543ecb104069b0ff9e0fcc5c739ad16202935528a112d974e8f1a4ee8" - -[[package]] -name = "block-modes" -version = "0.8.1" -dependencies = [ - "aes", - "block-padding", - "cipher", - "hex-literal", -] - -[[package]] -name = "block-padding" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" +checksum = "847495c209977a90e8aad588b959d0ca9f5dc228096d29a6bd3defd53f35eaec" [[package]] name = "blowfish" -version = "0.8.0" +version = "0.9.0" dependencies = [ "byteorder", "cipher", - "opaque-debug", ] [[package]] @@ -53,12 +34,10 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "cast5" -version = "0.10.0" +version = "0.11.0" dependencies = [ - "byteorder", "cipher", "hex-literal", - "opaque-debug", ] [[package]] @@ -69,12 +48,14 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cipher" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +checksum = "a4f3e8c9be82c31c331bc9db0fd70a1068f8a288d980b2414dcaa25ab17ac1e0" dependencies = [ "blobby", - "generic-array", + "crypto-common", + "inout", + "zeroize", ] [[package]] @@ -87,75 +68,56 @@ dependencies = [ ] [[package]] -name = "ctr" -version = "0.8.0" +name = "crypto-common" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" +checksum = "a4600d695eb3f6ce1cd44e6e291adceb2cc3ab12f20a33777ecd0bf6eba34e06" dependencies = [ - "cipher", + "generic-array", ] [[package]] name = "des" -version = "0.7.0" +version = "0.8.0" dependencies = [ - "byteorder", "cipher", - "opaque-debug", ] [[package]] name = "generic-array" -version = "0.14.4" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" dependencies = [ "typenum", "version_check", ] -[[package]] -name = "gost-modes" -version = "0.5.0" -dependencies = [ - "block-modes", - "cipher", - "generic-array", - "hex-literal", - "kuznyechik", - "magma", -] - [[package]] name = "hex-literal" -version = "0.2.1" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "961de220ec9a91af2e1e5bd80d02109155695e516771762381ef8581317066e0" -dependencies = [ - "hex-literal-impl", - "proc-macro-hack", -] +checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" [[package]] -name = "hex-literal-impl" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "853f769599eb31de176303197b7ba4973299c38c7a7604a6bc88c3eef05b9b46" +name = "idea" +version = "0.5.0" dependencies = [ - "proc-macro-hack", + "cipher", ] [[package]] -name = "idea" -version = "0.4.0" +name = "inout" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1d8734d7f28aaff861d726dc3bc8003e2987d2fc26add21f5dab0c35d5c348a" dependencies = [ - "cipher", - "opaque-debug", + "generic-array", ] [[package]] name = "kuznyechik" -version = "0.7.2" +version = "0.8.0" dependencies = [ "cipher", "hex-literal", @@ -163,83 +125,71 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.101" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21" +checksum = "e74d72e0f9b65b5b4ca49a346af3976df0f9c61d550727f349ecd559f251a26c" [[package]] name = "magma" -version = "0.7.0" +version = "0.8.0" dependencies = [ "cipher", "hex-literal", - "opaque-debug", ] -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - -[[package]] -name = "proc-macro-hack" -version = "0.5.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99c605b9a0adc77b7211c6b1f722dcb613d68d66859a44f3d485a6da332b0598" - [[package]] name = "rc2" -version = "0.7.0" +version = "0.8.0" dependencies = [ "cipher", - "opaque-debug", ] [[package]] name = "serpent" -version = "0.4.0" +version = "0.5.0" dependencies = [ "byteorder", "cipher", - "opaque-debug", ] [[package]] name = "sm4" -version = "0.4.0" +version = "0.5.0" dependencies = [ - "byteorder", "cipher", "hex-literal", - "opaque-debug", ] [[package]] name = "threefish" -version = "0.4.0" +version = "0.5.0" dependencies = [ "cipher", + "hex-literal", ] [[package]] name = "twofish" -version = "0.6.0" +version = "0.7.0" dependencies = [ - "byteorder", "cipher", "hex-literal", - "opaque-debug", ] [[package]] name = "typenum" -version = "1.12.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" [[package]] name = "version_check" -version = "0.9.2" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "zeroize" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" +checksum = "7c88870063c39ee00ec285a2f8d6a966e5b6fb2becc4e8dac77ed0d370ed6006" diff --git a/Cargo.toml b/Cargo.toml index 3cc9549c..34d21596 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,8 +2,6 @@ members = [ "aes", "blowfish", - "block-modes", - "gost-modes", "cast5", "des", "idea", @@ -15,3 +13,6 @@ members = [ "twofish", "threefish", ] + +[profile.dev] +opt-level = 2 diff --git a/README.md b/README.md index 445c1583..4327b701 100644 --- a/README.md +++ b/README.md @@ -1,107 +1,42 @@ -# RustCrypto: block ciphers [![Project Chat][chat-image]][chat-link] [![dependency status][deps-image]][deps-link] +# RustCrypto: block ciphers -Collection of [block ciphers][1] and [block modes][2] written in pure Rust. +[![Project Chat][chat-image]][chat-link] +[![dependency status][deps-image]][deps-link] +![Apache2/MIT licensed][license-image] +[![HAZMAT][hazmat-image]][hazmat-link] + +Collection of [block ciphers] written in pure Rust. ## Warnings -Currently only the `aes` crate provides constant-time implementation and has received -a third-party security audit. +Currently only the `aes` crate provides constant-time implementation and has received a third-party security audit. -Other crates in this repository are not implemented in a constant-time manner and have -not yet received any formal cryptographic and security reviews. +Other crates in this repository are not implemented in a constant-time manner and have not yet received any formal cryptographic and security reviews. -It's generally recommended not to use other cipher implementations in this repository -besides the `aes` crate. +It's generally recommended not to use other cipher implementations in this repository besides the `aes` crate. **USE AT YOUR OWN RISK.** ## Supported algorithms -| Name | Crate name | crates.io | Docs | Build Status | -|------|------------|-----------|------|--------------| -| [AES](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard) (Rijndael) | `aes` | [![crates.io](https://img.shields.io/crates/v/aes.svg)](https://crates.io/crates/aes) | [![Documentation](https://docs.rs/aes/badge.svg)](https://docs.rs/aes) | [![aes build](https://github.com/RustCrypto/block-ciphers/workflows/aes/badge.svg?branch=master&event=push)](https://github.com/RustCrypto/block-ciphers/actions?query=workflow:aes+branch:master) -| [Blowfish](https://en.wikipedia.org/wiki/Blowfish_(cipher)) | `blowfish` | [![crates.io](https://img.shields.io/crates/v/blowfish.svg)](https://crates.io/crates/blowfish) | [![Documentation](https://docs.rs/blowfish/badge.svg)](https://docs.rs/blowfish) | [![build](https://github.com/RustCrypto/block-ciphers/workflows/blowfish/badge.svg?branch=master&event=push)](https://github.com/RustCrypto/block-ciphers/actions?query=workflow:blowfish+branch:master) -| [CAST5](https://en.wikipedia.org/wiki/CAST-128) (CAST-128) | `cast5` | [![crates.io](https://img.shields.io/crates/v/cast5.svg)](https://crates.io/crates/cast5) | [![Documentation](https://docs.rs/cast5/badge.svg)](https://docs.rs/cast5) | [![build](https://github.com/RustCrypto/block-ciphers/workflows/cast5/badge.svg?branch=master&event=push)](https://github.com/RustCrypto/block-ciphers/actions?query=workflow:cast5+branch:master) -| [DES](https://en.wikipedia.org/wiki/Data_Encryption_Standard) + [3DES](https://en.wikipedia.org/wiki/Triple_DES) (DEA, 3DEA) | `des` | [![crates.io](https://img.shields.io/crates/v/des.svg)](https://crates.io/crates/des) | [![Documentation](https://docs.rs/des/badge.svg)](https://docs.rs/des) | [![build](https://github.com/RustCrypto/block-ciphers/workflows/des/badge.svg?branch=master&event=push)](https://github.com/RustCrypto/block-ciphers/actions?query=workflow:des+branch:master) -| [IDEA](https://simple.wikipedia.org/wiki/International_Data_Encryption_Algorithm) | `idea` | [![crates.io](https://img.shields.io/crates/v/idea.svg)](https://crates.io/crates/idea) | [![Documentation](https://docs.rs/idea/badge.svg)](https://docs.rs/idea) | [![build](https://github.com/RustCrypto/block-ciphers/workflows/idea/badge.svg?branch=master&event=push)](https://github.com/RustCrypto/block-ciphers/actions?query=workflow:idea+branch:master) -| [Kuznyechik](https://en.wikipedia.org/wiki/Kuznyechik) (GOST R 34.12-2015) | `kuznyechik` | [![crates.io](https://img.shields.io/crates/v/kuznyechik.svg)](https://crates.io/crates/kuznyechik) | [![Documentation](https://docs.rs/kuznyechik/badge.svg)](https://docs.rs/kuznyechik) | [![build](https://github.com/RustCrypto/block-ciphers/workflows/kuznyechik/badge.svg?branch=master&event=push)](https://github.com/RustCrypto/block-ciphers/actions?query=workflow:kuznyechik+branch:master) -| [Magma](https://en.wikipedia.org/wiki/GOST_(block_cipher)) (GOST 28147-89 and GOST R 34.12-2015) | `magma` | [![crates.io](https://img.shields.io/crates/v/magma.svg)](https://crates.io/crates/magma) | [![Documentation](https://docs.rs/magma/badge.svg)](https://docs.rs/magma) | [![build](https://github.com/RustCrypto/block-ciphers/workflows/magma/badge.svg?branch=master&event=push)](https://github.com/RustCrypto/block-ciphers/actions?query=workflow:magma+branch:master) -| [RC2](https://en.wikipedia.org/wiki/RC2) (ARC2) | `rc2` | [![crates.io](https://img.shields.io/crates/v/rc2.svg)](https://crates.io/crates/rc2) | [![Documentation](https://docs.rs/rc2/badge.svg)](https://docs.rs/rc2) | [![build](https://github.com/RustCrypto/block-ciphers/workflows/rc2/badge.svg?branch=master&event=push)](https://github.com/RustCrypto/block-ciphers/actions?query=workflow:rc2+branch:master) -| [Serpent](https://en.wikipedia.org/wiki/Serpent_(cipher)) | `serpent` | [![crates.io](https://img.shields.io/crates/v/serpent.svg)](https://crates.io/crates/serpent) | [![Documentation](https://docs.rs/serpent/badge.svg)](https://docs.rs/serpent) | [![build](https://github.com/RustCrypto/block-ciphers/workflows/serpent/badge.svg?branch=master&event=push)](https://github.com/RustCrypto/block-ciphers/actions?query=workflow:rc2+branch:master) -| [SM4](https://en.wikipedia.org/wiki/SM4_(cipher)) | `sm4` | [![crates.io](https://img.shields.io/crates/v/sm4.svg)](https://crates.io/crates/sm4) | [![Documentation](https://docs.rs/sm4/badge.svg)](https://docs.rs/sm4) | [![build](https://github.com/RustCrypto/block-ciphers/workflows/sm4/badge.svg?branch=master&event=push)](https://github.com/RustCrypto/block-ciphers/actions?query=workflow:sm4+branch:master) -| [Twofish](https://en.wikipedia.org/wiki/Twofish) | `twofish` | [![crates.io](https://img.shields.io/crates/v/twofish.svg)](https://crates.io/crates/twofish) | [![Documentation](https://docs.rs/twofish/badge.svg)](https://docs.rs/twofish) | [![build](https://github.com/RustCrypto/block-ciphers/workflows/twofish/badge.svg?branch=master&event=push)](https://github.com/RustCrypto/block-ciphers/actions?query=workflow:twofish+branch:master) -| [Threefish](https://en.wikipedia.org/wiki/Threefish) | `threefish` | [![crates.io](https://img.shields.io/crates/v/threefish.svg)](https://crates.io/crates/threefish) | [![Documentation](https://docs.rs/threefish/badge.svg)](https://docs.rs/threefish) | [![build](https://github.com/RustCrypto/block-ciphers/workflows/threefish/badge.svg?branch=master&event=push)](https://github.com/RustCrypto/block-ciphers/actions?query=workflow:threefish+branch:master) - -### Additional crates - -| Crate name | crates.io | Docs | Build Status | -|------------|-----------|--------|--------------| -| `block-modes` | [![crates.io](https://img.shields.io/crates/v/block-modes.svg)](https://crates.io/crates/block-modes) | [![Documentation](https://docs.rs/block-modes/badge.svg)](https://docs.rs/block-modes) | [![build](https://github.com/RustCrypto/block-ciphers/workflows/block-modes/badge.svg?branch=master&event=push)](https://github.com/RustCrypto/block-ciphers/actions?query=workflow:block-modes+branch:master) -| `gost-modes` | [![crates.io](https://img.shields.io/crates/v/gost-modes.svg)](https://crates.io/crates/gost-modes) | [![Documentation](https://docs.rs/gost-modes/badge.svg)](https://docs.rs/gost-modes) | [![build](https://github.com/RustCrypto/block-ciphers/workflows/gost-modes/badge.svg?branch=master&event=push)](https://github.com/RustCrypto/block-ciphers/actions?query=workflow:gost-modes+branch:master) - -### Minimum Supported Rust Version -All crates in this repository support Rust 1.22 or higher. (except `aesni` and -`aes` crates, which require Rust 1.27) In future minimum supported Rust version -can be changed, but it will be done with the minor version bump. - -## Usage -Block cipher crates provide only bare block cipher implementations. For most -applications you will need to use some [block cipher mode of operation](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation) -which are generically implemented in the [`block-modes`](https://docs.rs/block-modes/) crate. - -Some block modes (CTR, CFB, OFV) transform block ciphers into stream ciphers.Such modes are published under separate crates in the -[RustCrypto/stream-ciphers][5] repository. - -Lets use AES128-CBC with [PKCS7][3] padding to show an example: - -```rust -use aes::Aes128; -use block_modes::{BlockMode, Cbc}; -use block_modes::block_padding::Pkcs7; -use hex_literal::hex; - -// create an alias for convenience -type Aes128Cbc = Cbc; - -let key = hex!("000102030405060708090a0b0c0d0e0f"); -let iv = hex!("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"); -let plaintext = b"Hello world!"; -let cipher = Aes128Cbc::new_from_slices(&key, &iv).unwrap(); - -// buffer must have enough space for message+padding -let mut buffer = [0u8; 32]; -// copy message to the buffer -let pos = plaintext.len(); -buffer[..pos].copy_from_slice(plaintext); -let ciphertext = cipher.encrypt(&mut buffer, pos).unwrap(); - -assert_eq!(ciphertext, hex!("1b7a4c403124ae2fb52bedc534d82fa8")); - -// re-create cipher mode instance and decrypt the message -let cipher = Aes128Cbc::new_from_slices(&key, &iv).unwrap(); -let mut buf = ciphertext.to_vec(); -let decrypted_ciphertext = cipher.decrypt(&mut buf).unwrap(); - -assert_eq!(decrypted_ciphertext, plaintext); -``` - -With an enabled `std` feature (which is enabled by default) you can use -`encrypt_vec` and `decrypt_vec` methods: - -```rust -let cipher = Aes128Cbc::new_from_slices(&key, &iv).unwrap(); -let ciphertext = cipher.encrypt_vec(plaintext); - -assert_eq!(ciphertext, hex!("1b7a4c403124ae2fb52bedc534d82fa8")); - -let cipher = Aes128Cbc::new_from_slices(&key, &iv).unwrap(); -let decrypted_ciphertext = cipher.decrypt_vec(&ciphertext).unwrap(); - -assert_eq!(decrypted_ciphertext, plaintext); -``` - -Note that this example does not use any authentification which can lead to -serious vulnarabilities! For Message Authentication Code implementations take -a look at [RustCrypto/MACs][4] repository. + +| Name | Crate name | crates.io | Docs | MSRV | +|------|------------|-----------|------|------| +| [AES](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard) (Rijndael) | `aes` | [![crates.io](https://img.shields.io/crates/v/aes.svg)](https://crates.io/crates/aes) | [![Documentation](https://docs.rs/aes/badge.svg)](https://docs.rs/aes) | ![MSRV 1.56][msrv-1.56] | +| [Blowfish](https://en.wikipedia.org/wiki/Blowfish_(cipher)) | `blowfish` | [![crates.io](https://img.shields.io/crates/v/blowfish.svg)](https://crates.io/crates/blowfish) | [![Documentation](https://docs.rs/blowfish/badge.svg)](https://docs.rs/blowfish) | ![MSRV 1.56][msrv-1.56] | +| [CAST5](https://en.wikipedia.org/wiki/CAST-128) (CAST-128) | `cast5` | [![crates.io](https://img.shields.io/crates/v/cast5.svg)](https://crates.io/crates/cast5) | [![Documentation](https://docs.rs/cast5/badge.svg)](https://docs.rs/cast5) | ![MSRV 1.56][msrv-1.56] | +| [DES](https://en.wikipedia.org/wiki/Data_Encryption_Standard) + [3DES](https://en.wikipedia.org/wiki/Triple_DES) (DEA, 3DEA) | `des` | [![crates.io](https://img.shields.io/crates/v/des.svg)](https://crates.io/crates/des) | [![Documentation](https://docs.rs/des/badge.svg)](https://docs.rs/des) | ![MSRV 1.56][msrv-1.56] | +| [IDEA](https://simple.wikipedia.org/wiki/International_Data_Encryption_Algorithm) | `idea` | [![crates.io](https://img.shields.io/crates/v/idea.svg)](https://crates.io/crates/idea) | [![Documentation](https://docs.rs/idea/badge.svg)](https://docs.rs/idea) | ![MSRV 1.56][msrv-1.56] | +| [Kuznyechik](https://en.wikipedia.org/wiki/Kuznyechik) (GOST R 34.12-2015) | `kuznyechik` | [![crates.io](https://img.shields.io/crates/v/kuznyechik.svg)](https://crates.io/crates/kuznyechik) | [![Documentation](https://docs.rs/kuznyechik/badge.svg)](https://docs.rs/kuznyechik) | ![MSRV 1.56][msrv-1.56] | +| [Magma](https://en.wikipedia.org/wiki/GOST_(block_cipher)) (GOST R 34.12-2015) | `magma` | [![crates.io](https://img.shields.io/crates/v/magma.svg)](https://crates.io/crates/magma) | [![Documentation](https://docs.rs/magma/badge.svg)](https://docs.rs/magma) | ![MSRV 1.56][msrv-1.56] | +| [RC2](https://en.wikipedia.org/wiki/RC2) (ARC2) | `rc2` | [![crates.io](https://img.shields.io/crates/v/rc2.svg)](https://crates.io/crates/rc2) | [![Documentation](https://docs.rs/rc2/badge.svg)](https://docs.rs/rc2) | ![MSRV 1.56][msrv-1.56] | +| [Serpent](https://en.wikipedia.org/wiki/Serpent_(cipher)) | `serpent` | [![crates.io](https://img.shields.io/crates/v/serpent.svg)](https://crates.io/crates/serpent) | [![Documentation](https://docs.rs/serpent/badge.svg)](https://docs.rs/serpent) | ![MSRV 1.56][msrv-1.56] | +| [SM4](https://en.wikipedia.org/wiki/SM4_(cipher)) | `sm4` | [![crates.io](https://img.shields.io/crates/v/sm4.svg)](https://crates.io/crates/sm4) | [![Documentation](https://docs.rs/sm4/badge.svg)](https://docs.rs/sm4) | ![MSRV 1.56][msrv-1.56] | +| [Threefish](https://en.wikipedia.org/wiki/Threefish) | `threefish` | [![crates.io](https://img.shields.io/crates/v/threefish.svg)](https://crates.io/crates/threefish) | [![Documentation](https://docs.rs/threefish/badge.svg)](https://docs.rs/threefish) | ![MSRV 1.56][msrv-1.56] | +| [Twofish](https://en.wikipedia.org/wiki/Twofish) | `twofish` | [![crates.io](https://img.shields.io/crates/v/twofish.svg)](https://crates.io/crates/twofish) | [![Documentation](https://docs.rs/twofish/badge.svg)](https://docs.rs/twofish) | ![MSRV 1.56][msrv-1.56] | + +### Minimum Supported Rust Version (MSRV) Policy + +MSRV bump is considered a breaking change and will be performed only with a minor version bump. ## License @@ -124,11 +59,11 @@ dual licensed as above, without any additional terms or conditions. [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260039-block-ciphers [deps-image]: https://deps.rs/repo/github/RustCrypto/block-ciphers/status.svg [deps-link]: https://deps.rs/repo/github/RustCrypto/block-ciphers +[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg +[hazmat-image]: https://img.shields.io/badge/crypto-hazmat%E2%9A%A0-red.svg +[hazmat-link]: https://github.com/RustCrypto/meta/blob/master/HAZMAT.md +[msrv-1.56]: https://img.shields.io/badge/rustc-1.56.0+-blue.svg -[//]: # (footnotes) +[//]: # (links) -[1]: https://en.wikipedia.org/wiki/Block_cipher -[2]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation -[3]: https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS%235_and_PKCS%237 -[4]: https://github.com/RustCrypto/MACs -[5]: https://github.com/RustCrypto/stream-ciphers +[block ciphers]: https://en.wikipedia.org/wiki/Block_cipher diff --git a/aes/CHANGELOG.md b/aes/CHANGELOG.md index 3a91b7af..089fc10b 100644 --- a/aes/CHANGELOG.md +++ b/aes/CHANGELOG.md @@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 0.8.0 (2022-02-10) +### Changed +- Bump `cipher` dependency to v0.4 ([#284]) + +### Added +- Encrypt-only and decrypt-only cipher types ([#284]) + +[#284]: https://github.com/RustCrypto/block-ciphers/pull/284 + ## 0.7.5 (2021-08-26) ### Changed - Bump `ctr` dependency to v0.8 ([#275]) @@ -58,7 +67,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Use `cfg-if` crate ([#203]) - Rename `semi_fixslice` feature to `compact` ([#204]) - Refactor NI backend ([#224], [#225]) -- Bump `cipher` crate dependency to v0.3 release ([#235]) +- Bump `cipher` crate dependency to v0.3 ([#235]) - Bump `ctr` crate dependency to v0.7 ([#237]) [#200]: https://github.com/RustCrypto/block-ciphers/pull/200 diff --git a/aes/Cargo.lock b/aes/Cargo.lock deleted file mode 100644 index 056e8578..00000000 --- a/aes/Cargo.lock +++ /dev/null @@ -1,114 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "aes" -version = "0.7.4" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", - "ctr", - "hex-literal", - "opaque-debug", -] - -[[package]] -name = "blobby" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc52553543ecb104069b0ff9e0fcc5c739ad16202935528a112d974e8f1a4ee8" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "cipher" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" -dependencies = [ - "blobby", - "generic-array", -] - -[[package]] -name = "cpufeatures" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66c99696f6c9dd7f35d486b9d04d7e6e202aa3e8c40d553f2fdf5e7e0c6a71ef" -dependencies = [ - "libc", -] - -[[package]] -name = "ctr" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" -dependencies = [ - "cipher", -] - -[[package]] -name = "generic-array" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "hex-literal" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "961de220ec9a91af2e1e5bd80d02109155695e516771762381ef8581317066e0" -dependencies = [ - "hex-literal-impl", - "proc-macro-hack", -] - -[[package]] -name = "hex-literal-impl" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "853f769599eb31de176303197b7ba4973299c38c7a7604a6bc88c3eef05b9b46" -dependencies = [ - "proc-macro-hack", -] - -[[package]] -name = "libc" -version = "0.2.101" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21" - -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - -[[package]] -name = "proc-macro-hack" -version = "0.5.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" - -[[package]] -name = "typenum" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" - -[[package]] -name = "version_check" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" diff --git a/aes/Cargo.toml b/aes/Cargo.toml index 9fd0436f..7e85ffe7 100644 --- a/aes/Cargo.toml +++ b/aes/Cargo.toml @@ -1,14 +1,12 @@ [package] name = "aes" -version = "0.7.5" -description = """ -Pure Rust implementation of the Advanced Encryption Standard (a.k.a. Rijndael) -including support for AES in counter mode (a.k.a. AES-CTR) -""" +version = "0.8.0" # Also update html_root_url in lib.rs when bumping this +description = "Pure Rust implementation of the Advanced Encryption Standard (a.k.a. Rijndael)" authors = ["RustCrypto Developers"] license = "MIT OR Apache-2.0" +edition = "2021" +rust-version = "1.56" readme = "README.md" -edition = "2018" documentation = "https://docs.rs/aes" repository = "https://github.com/RustCrypto/block-ciphers" keywords = ["crypto", "aes", "rijndael", "block-cipher"] @@ -16,23 +14,19 @@ categories = ["cryptography", "no-std"] [dependencies] cfg-if = "1" -cipher = "0.3" -ctr = { version = "0.8", optional = true } -opaque-debug = "0.3" - -[dev-dependencies] -cipher = { version = "0.3", features = ["dev"] } -hex-literal = "0.2" +cipher = "0.4" [target.'cfg(any(target_arch = "aarch64", target_arch = "x86_64", target_arch = "x86"))'.dependencies] cpufeatures = "0.2" +[dev-dependencies] +cipher = { version = "0.4", features = ["dev"] } +hex-literal = "0.3" + [features] -armv8 = [] # Enable ARMv8 AES intrinsics (nightly-only) -compact = [] # Reduce code size at the cost of slower performance -force-soft = [] # Disable support for AES hardware intrinsics hazmat = [] # Expose cryptographically hazardous APIs +zeroize = ["cipher/zeroize"] [package.metadata.docs.rs] -features = ["ctr"] +all-features = true rustdoc-args = ["--cfg", "docsrs"] diff --git a/aes/README.md b/aes/README.md index 4fd09122..ce95a3a1 100644 --- a/aes/README.md +++ b/aes/README.md @@ -43,7 +43,7 @@ using a portable implementation based on bitslicing. ## Minimum Supported Rust Version -Rust **1.49** or higher. +Rust **1.56** or higher. Minimum supported Rust version can be changed in future releases, but it will be done with a minor version bump. @@ -75,7 +75,7 @@ dual licensed as above, without any additional terms or conditions. [docs-image]: https://docs.rs/aes/badge.svg [docs-link]: https://docs.rs/aes/ [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg -[rustc-image]: https://img.shields.io/badge/rustc-1.49+-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.56+-blue.svg [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260039-block-ciphers [build-image]: https://github.com/RustCrypto/block-ciphers/workflows/aes/badge.svg?branch=master&event=push diff --git a/aes/benches/aes128.rs b/aes/benches/aes128.rs deleted file mode 100644 index 9f882de0..00000000 --- a/aes/benches/aes128.rs +++ /dev/null @@ -1,61 +0,0 @@ -#![feature(test)] -extern crate test; - -use aes::cipher::{BlockDecrypt, BlockEncrypt, NewBlockCipher}; -use aes::Aes128; - -#[bench] -pub fn aes128_new(bh: &mut test::Bencher) { - bh.iter(|| { - let cipher = Aes128::new(&Default::default()); - test::black_box(&cipher); - }); -} - -#[bench] -pub fn aes128_encrypt(bh: &mut test::Bencher) { - let cipher = Aes128::new(&Default::default()); - let mut input = Default::default(); - - bh.iter(|| { - cipher.encrypt_block(&mut input); - test::black_box(&input); - }); - bh.bytes = input.len() as u64; -} - -#[bench] -pub fn aes128_decrypt(bh: &mut test::Bencher) { - let cipher = Aes128::new(&Default::default()); - let mut input = Default::default(); - - bh.iter(|| { - cipher.decrypt_block(&mut input); - test::black_box(&input); - }); - bh.bytes = input.len() as u64; -} - -#[bench] -pub fn aes128_encrypt8(bh: &mut test::Bencher) { - let cipher = Aes128::new(&Default::default()); - let mut input = Default::default(); - - bh.iter(|| { - cipher.encrypt_par_blocks(&mut input); - test::black_box(&input); - }); - bh.bytes = (input[0].len() * input.len()) as u64; -} - -#[bench] -pub fn aes128_decrypt8(bh: &mut test::Bencher) { - let cipher = Aes128::new(&Default::default()); - let mut input = Default::default(); - - bh.iter(|| { - cipher.decrypt_par_blocks(&mut input); - test::black_box(&input); - }); - bh.bytes = (input[0].len() * input.len()) as u64; -} diff --git a/aes/benches/aes192.rs b/aes/benches/aes192.rs deleted file mode 100644 index 913b7a92..00000000 --- a/aes/benches/aes192.rs +++ /dev/null @@ -1,61 +0,0 @@ -#![feature(test)] -extern crate test; - -use aes::cipher::{BlockDecrypt, BlockEncrypt, NewBlockCipher}; -use aes::Aes192; - -#[bench] -pub fn aes192_new(bh: &mut test::Bencher) { - bh.iter(|| { - let cipher = Aes192::new(&Default::default()); - test::black_box(&cipher); - }); -} - -#[bench] -pub fn aes192_encrypt(bh: &mut test::Bencher) { - let cipher = Aes192::new(&Default::default()); - let mut input = Default::default(); - - bh.iter(|| { - cipher.encrypt_block(&mut input); - test::black_box(&input); - }); - bh.bytes = input.len() as u64; -} - -#[bench] -pub fn aes192_decrypt(bh: &mut test::Bencher) { - let cipher = Aes192::new(&Default::default()); - let mut input = Default::default(); - - bh.iter(|| { - cipher.decrypt_block(&mut input); - test::black_box(&input); - }); - bh.bytes = input.len() as u64; -} - -#[bench] -pub fn aes192_encrypt8(bh: &mut test::Bencher) { - let cipher = Aes192::new(&Default::default()); - let mut input = Default::default(); - - bh.iter(|| { - cipher.encrypt_par_blocks(&mut input); - test::black_box(&input); - }); - bh.bytes = (input[0].len() * input.len()) as u64; -} - -#[bench] -pub fn aes192_decrypt8(bh: &mut test::Bencher) { - let cipher = Aes192::new(&Default::default()); - let mut input = Default::default(); - - bh.iter(|| { - cipher.decrypt_par_blocks(&mut input); - test::black_box(&input); - }); - bh.bytes = (input[0].len() * input.len()) as u64; -} diff --git a/aes/benches/aes256.rs b/aes/benches/aes256.rs deleted file mode 100644 index 68c70df0..00000000 --- a/aes/benches/aes256.rs +++ /dev/null @@ -1,61 +0,0 @@ -#![feature(test)] -extern crate test; - -use aes::cipher::{BlockDecrypt, BlockEncrypt, NewBlockCipher}; -use aes::Aes256; - -#[bench] -pub fn aes256_new(bh: &mut test::Bencher) { - bh.iter(|| { - let cipher = Aes256::new(&Default::default()); - test::black_box(&cipher); - }); -} - -#[bench] -pub fn aes256_encrypt(bh: &mut test::Bencher) { - let cipher = Aes256::new(&Default::default()); - let mut input = Default::default(); - - bh.iter(|| { - cipher.encrypt_block(&mut input); - test::black_box(&input); - }); - bh.bytes = input.len() as u64; -} - -#[bench] -pub fn aes256_decrypt(bh: &mut test::Bencher) { - let cipher = Aes256::new(&Default::default()); - let mut input = Default::default(); - - bh.iter(|| { - cipher.decrypt_block(&mut input); - test::black_box(&input); - }); - bh.bytes = input.len() as u64; -} - -#[bench] -pub fn aes256_encrypt8(bh: &mut test::Bencher) { - let cipher = Aes256::new(&Default::default()); - let mut input = Default::default(); - - bh.iter(|| { - cipher.encrypt_par_blocks(&mut input); - test::black_box(&input); - }); - bh.bytes = (input[0].len() * input.len()) as u64; -} - -#[bench] -pub fn aes256_decrypt8(bh: &mut test::Bencher) { - let cipher = Aes256::new(&Default::default()); - let mut input = Default::default(); - - bh.iter(|| { - cipher.decrypt_par_blocks(&mut input); - test::black_box(&input); - }); - bh.bytes = (input[0].len() * input.len()) as u64; -} diff --git a/aes/benches/mod.rs b/aes/benches/mod.rs new file mode 100644 index 00000000..579b0731 --- /dev/null +++ b/aes/benches/mod.rs @@ -0,0 +1,62 @@ +#![feature(test)] +extern crate test; + +use cipher::{block_decryptor_bench, block_encryptor_bench, KeyInit}; + +block_encryptor_bench!( + Key: aes::Aes128, + aes128_encrypt_block, + aes128_encrypt_blocks, +); +block_decryptor_bench!( + Key: aes::Aes128, + aes128_decrypt_block, + aes128_decrypt_blocks, +); +block_encryptor_bench!( + Key: aes::Aes192, + aes192_encrypt_block, + aes192_encrypt_blocks, +); +block_decryptor_bench!( + Key: aes::Aes192, + aes192_decrypt_block, + aes192_decrypt_blocks, +); +block_encryptor_bench!( + Key: aes::Aes256, + aes256_encrypt_block, + aes256_encrypt_blocks, +); +block_decryptor_bench!( + Key: aes::Aes256, + aes256_decrypt_block, + aes256_decrypt_blocks, +); + +#[bench] +fn aes128_new(bh: &mut test::Bencher) { + bh.iter(|| { + let key = test::black_box(Default::default()); + let cipher = aes::Aes128::new(&key); + test::black_box(&cipher); + }); +} + +#[bench] +fn aes192_new(bh: &mut test::Bencher) { + bh.iter(|| { + let key = test::black_box(Default::default()); + let cipher = aes::Aes192::new(&key); + test::black_box(&cipher); + }); +} + +#[bench] +fn aes256_new(bh: &mut test::Bencher) { + bh.iter(|| { + let key = test::black_box(Default::default()); + let cipher = aes::Aes256::new(&key); + test::black_box(&cipher); + }); +} diff --git a/aes/src/armv8.rs b/aes/src/armv8.rs index 187ac1be..6b0bb9b7 100644 --- a/aes/src/armv8.rs +++ b/aes/src/armv8.rs @@ -12,31 +12,35 @@ #[cfg(feature = "hazmat")] pub(crate) mod hazmat; -mod decrypt; -mod encrypt; +mod encdec; mod expand; +#[cfg(test)] +mod test_expand; use self::{ - decrypt::{decrypt, decrypt8}, - encrypt::{encrypt, encrypt8}, + encdec::{decrypt1, decrypt8, encrypt1, encrypt8}, expand::{expand_key, inv_expanded_keys}, }; -use crate::{Block, ParBlocks}; +use crate::{Block, Block8}; use cipher::{ consts::{U16, U24, U32, U8}, - generic_array::GenericArray, - BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher, + inout::InOut, + AlgorithmName, BlockBackend, BlockCipher, BlockClosure, BlockDecrypt, BlockEncrypt, + BlockSizeUser, Key, KeyInit, KeySizeUser, ParBlocksSizeUser, }; use core::arch::aarch64::*; +use core::fmt; macro_rules! define_aes_impl { ( $name:ident, $name_enc:ident, $name_dec:ident, + $name_back_enc:ident, + $name_back_dec:ident, $key_size:ty, $rounds:tt, - $doc:expr + $doc:expr $(,)? ) => { #[doc=$doc] #[doc = "block cipher"] @@ -46,43 +50,75 @@ macro_rules! define_aes_impl { decrypt: $name_dec, } - impl NewBlockCipher for $name { + impl $name { + #[inline(always)] + pub(crate) fn get_enc_backend(&self) -> $name_back_enc<'_> { + self.encrypt.get_enc_backend() + } + + #[inline(always)] + pub(crate) fn get_dec_backend(&self) -> $name_back_dec<'_> { + self.decrypt.get_dec_backend() + } + } + + impl BlockCipher for $name {} + + impl KeySizeUser for $name { type KeySize = $key_size; + } + impl KeyInit for $name { #[inline] - fn new(key: &GenericArray) -> Self { + fn new(key: &Key) -> Self { let encrypt = $name_enc::new(key); let decrypt = $name_dec::from(&encrypt); Self { encrypt, decrypt } } } - impl BlockCipher for $name { - type BlockSize = U16; - type ParBlocks = U8; + impl From<$name_enc> for $name { + #[inline] + fn from(encrypt: $name_enc) -> $name { + let decrypt = (&encrypt).into(); + Self { encrypt, decrypt } + } } - impl BlockEncrypt for $name { + impl From<&$name_enc> for $name { #[inline] - fn encrypt_block(&self, block: &mut Block) { - self.encrypt.encrypt_block(block) + fn from(encrypt: &$name_enc) -> $name { + let decrypt = encrypt.into(); + let encrypt = encrypt.clone(); + Self { encrypt, decrypt } } + } - #[inline] - fn encrypt_par_blocks(&self, blocks: &mut ParBlocks) { - self.encrypt.encrypt_par_blocks(blocks) + impl BlockSizeUser for $name { + type BlockSize = U16; + } + + impl BlockEncrypt for $name { + fn encrypt_with_backend(&self, f: impl BlockClosure) { + self.encrypt.encrypt_with_backend(f) } } impl BlockDecrypt for $name { - #[inline] - fn decrypt_block(&self, block: &mut Block) { - self.decrypt.decrypt_block(block) + fn decrypt_with_backend(&self, f: impl BlockClosure) { + self.decrypt.decrypt_with_backend(f) } + } - #[inline] - fn decrypt_par_blocks(&self, blocks: &mut ParBlocks) { - self.decrypt.decrypt_par_blocks(blocks) + impl fmt::Debug for $name { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str(concat!(stringify!($name), " { .. }")) + } + } + + impl AlgorithmName for $name { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(stringify!($name)) } } @@ -93,28 +129,46 @@ macro_rules! define_aes_impl { round_keys: [uint8x16_t; $rounds], } - impl NewBlockCipher for $name_enc { + impl $name_enc { + #[inline(always)] + pub(crate) fn get_enc_backend(&self) -> $name_back_enc<'_> { + $name_back_enc(self) + } + } + + impl BlockCipher for $name_enc {} + + impl KeySizeUser for $name_enc { type KeySize = $key_size; + } - fn new(key: &GenericArray) -> Self { + impl KeyInit for $name_enc { + fn new(key: &Key) -> Self { Self { round_keys: expand_key(key.as_ref()), } } } - impl BlockCipher for $name_enc { + impl BlockSizeUser for $name_enc { type BlockSize = U16; - type ParBlocks = U8; } impl BlockEncrypt for $name_enc { - fn encrypt_block(&self, block: &mut Block) { - unsafe { encrypt(&self.round_keys, block) } + fn encrypt_with_backend(&self, f: impl BlockClosure) { + f.call(&mut self.get_enc_backend()) } + } + + impl fmt::Debug for $name_enc { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str(concat!(stringify!($name_enc), " { .. }")) + } + } - fn encrypt_par_blocks(&self, blocks: &mut ParBlocks) { - unsafe { encrypt8(&self.round_keys, blocks) } + impl AlgorithmName for $name_enc { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(stringify!($name_enc)) } } @@ -125,15 +179,27 @@ macro_rules! define_aes_impl { round_keys: [uint8x16_t; $rounds], } - impl NewBlockCipher for $name_dec { + impl $name_dec { + #[inline(always)] + pub(crate) fn get_dec_backend(&self) -> $name_back_dec<'_> { + $name_back_dec(self) + } + } + + impl BlockCipher for $name_dec {} + + impl KeySizeUser for $name_dec { type KeySize = $key_size; + } - fn new(key: &GenericArray) -> Self { + impl KeyInit for $name_dec { + fn new(key: &Key) -> Self { $name_enc::new(key).into() } } impl From<$name_enc> for $name_dec { + #[inline] fn from(enc: $name_enc) -> $name_dec { Self::from(&enc) } @@ -147,230 +213,105 @@ macro_rules! define_aes_impl { } } - impl BlockCipher for $name_dec { + impl BlockSizeUser for $name_dec { type BlockSize = U16; - type ParBlocks = U8; } impl BlockDecrypt for $name_dec { - fn decrypt_block(&self, block: &mut Block) { - unsafe { decrypt(&self.round_keys, block) } + fn decrypt_with_backend(&self, f: impl BlockClosure) { + f.call(&mut self.get_dec_backend()); } + } - fn decrypt_par_blocks(&self, blocks: &mut ParBlocks) { - unsafe { decrypt8(&self.round_keys, blocks) } + impl fmt::Debug for $name_dec { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str(concat!(stringify!($name_dec), " { .. }")) } } - opaque_debug::implement!($name); - opaque_debug::implement!($name_enc); - opaque_debug::implement!($name_dec); - }; -} + impl AlgorithmName for $name_dec { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(stringify!($name_dec)) + } + } -define_aes_impl!(Aes128, Aes128Enc, Aes128Dec, U16, 11, "AES-128"); -define_aes_impl!(Aes192, Aes192Enc, Aes192Dec, U24, 13, "AES-192"); -define_aes_impl!(Aes256, Aes256Enc, Aes256Dec, U32, 15, "AES-256"); + pub(crate) struct $name_back_enc<'a>(&'a $name_enc); -#[cfg(test)] -mod tests { - use super::{decrypt, decrypt8, encrypt, encrypt8, expand_key, inv_expanded_keys, ParBlocks}; - use core::{arch::aarch64::*, convert::TryInto}; - use hex_literal::hex; - - /// FIPS 197, Appendix A.1: AES-128 Cipher Key - /// user input, unaligned buffer - const AES128_KEY: [u8; 16] = hex!("2b7e151628aed2a6abf7158809cf4f3c"); - - /// FIPS 197 Appendix A.1: Expansion of a 128-bit Cipher Key - /// library controlled, aligned buffer - const AES128_EXP_KEYS: [[u8; 16]; 11] = [ - AES128_KEY, - hex!("a0fafe1788542cb123a339392a6c7605"), - hex!("f2c295f27a96b9435935807a7359f67f"), - hex!("3d80477d4716fe3e1e237e446d7a883b"), - hex!("ef44a541a8525b7fb671253bdb0bad00"), - hex!("d4d1c6f87c839d87caf2b8bc11f915bc"), - hex!("6d88a37a110b3efddbf98641ca0093fd"), - hex!("4e54f70e5f5fc9f384a64fb24ea6dc4f"), - hex!("ead27321b58dbad2312bf5607f8d292f"), - hex!("ac7766f319fadc2128d12941575c006e"), - hex!("d014f9a8c9ee2589e13f0cc8b6630ca6"), - ]; - - /// Inverse expanded keys for [`AES128_EXPANDED_KEYS`] - const AES128_EXP_INVKEYS: [[u8; 16]; 11] = [ - hex!("d014f9a8c9ee2589e13f0cc8b6630ca6"), - hex!("0c7b5a631319eafeb0398890664cfbb4"), - hex!("df7d925a1f62b09da320626ed6757324"), - hex!("12c07647c01f22c7bc42d2f37555114a"), - hex!("6efcd876d2df54807c5df034c917c3b9"), - hex!("6ea30afcbc238cf6ae82a4b4b54a338d"), - hex!("90884413d280860a12a128421bc89739"), - hex!("7c1f13f74208c219c021ae480969bf7b"), - hex!("cc7505eb3e17d1ee82296c51c9481133"), - hex!("2b3708a7f262d405bc3ebdbf4b617d62"), - AES128_KEY, - ]; - - /// FIPS 197, Appendix A.2: AES-192 Cipher Key - /// user input, unaligned buffer - const AES192_KEY: [u8; 24] = hex!("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"); - - /// FIPS 197 Appendix A.2: Expansion of a 192-bit Cipher Key - /// library controlled, aligned buffer - const AES192_EXP_KEYS: [[u8; 16]; 13] = [ - hex!("8e73b0f7da0e6452c810f32b809079e5"), - hex!("62f8ead2522c6b7bfe0c91f72402f5a5"), - hex!("ec12068e6c827f6b0e7a95b95c56fec2"), - hex!("4db7b4bd69b5411885a74796e92538fd"), - hex!("e75fad44bb095386485af05721efb14f"), - hex!("a448f6d94d6dce24aa326360113b30e6"), - hex!("a25e7ed583b1cf9a27f939436a94f767"), - hex!("c0a69407d19da4e1ec1786eb6fa64971"), - hex!("485f703222cb8755e26d135233f0b7b3"), - hex!("40beeb282f18a2596747d26b458c553e"), - hex!("a7e1466c9411f1df821f750aad07d753"), - hex!("ca4005388fcc5006282d166abc3ce7b5"), - hex!("e98ba06f448c773c8ecc720401002202"), - ]; - - /// FIPS 197, Appendix A.3: AES-256 Cipher Key - /// user input, unaligned buffer - const AES256_KEY: [u8; 32] = - hex!("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"); - - /// FIPS 197 Appendix A.3: Expansion of a 256-bit Cipher Key - /// library controlled, aligned buffer - const AES256_EXP_KEYS: [[u8; 16]; 15] = [ - hex!("603deb1015ca71be2b73aef0857d7781"), - hex!("1f352c073b6108d72d9810a30914dff4"), - hex!("9ba354118e6925afa51a8b5f2067fcde"), - hex!("a8b09c1a93d194cdbe49846eb75d5b9a"), - hex!("d59aecb85bf3c917fee94248de8ebe96"), - hex!("b5a9328a2678a647983122292f6c79b3"), - hex!("812c81addadf48ba24360af2fab8b464"), - hex!("98c5bfc9bebd198e268c3ba709e04214"), - hex!("68007bacb2df331696e939e46c518d80"), - hex!("c814e20476a9fb8a5025c02d59c58239"), - hex!("de1369676ccc5a71fa2563959674ee15"), - hex!("5886ca5d2e2f31d77e0af1fa27cf73c3"), - hex!("749c47ab18501ddae2757e4f7401905a"), - hex!("cafaaae3e4d59b349adf6acebd10190d"), - hex!("fe4890d1e6188d0b046df344706c631e"), - ]; - - /// FIPS 197, Appendix B input - /// user input, unaligned buffer - const INPUT: [u8; 16] = hex!("3243f6a8885a308d313198a2e0370734"); - - /// FIPS 197, Appendix B output - const EXPECTED: [u8; 16] = hex!("3925841d02dc09fbdc118597196a0b32"); - - fn load_expanded_keys(input: [[u8; 16]; N]) -> [uint8x16_t; N] { - let mut output = [unsafe { vdupq_n_u8(0) }; N]; - - for (src, dst) in input.iter().zip(output.iter_mut()) { - *dst = unsafe { vld1q_u8(src.as_ptr()) } - } - - output - } - - fn store_expanded_keys(input: [uint8x16_t; N]) -> [[u8; 16]; N] { - let mut output = [[0u8; 16]; N]; - - for (src, dst) in input.iter().zip(output.iter_mut()) { - unsafe { vst1q_u8(dst.as_mut_ptr(), *src) } - } - - output - } - - #[test] - fn aes128_key_expansion() { - let ek = expand_key(&AES128_KEY); - assert_eq!(store_expanded_keys(ek), AES128_EXP_KEYS); - } - - #[test] - fn aes128_key_expansion_inv() { - let mut ek = load_expanded_keys(AES128_EXP_KEYS); - inv_expanded_keys(&mut ek); - assert_eq!(store_expanded_keys(ek), AES128_EXP_INVKEYS); - } - - #[test] - fn aes192_key_expansion() { - let ek = expand_key(&AES192_KEY); - assert_eq!(store_expanded_keys(ek), AES192_EXP_KEYS); - } - - #[test] - fn aes256_key_expansion() { - let ek = expand_key(&AES256_KEY); - assert_eq!(store_expanded_keys(ek), AES256_EXP_KEYS); - } - - #[test] - fn aes128_encrypt() { - // Intentionally misaligned block - let mut block = [0u8; 19]; - block[3..].copy_from_slice(&INPUT); - - unsafe { - encrypt( - &load_expanded_keys(AES128_EXP_KEYS), - (&mut block[3..]).try_into().unwrap(), - ) - }; - - assert_eq!(&block[3..], &EXPECTED); - } - - #[test] - fn aes128_encrypt8() { - let mut blocks = ParBlocks::default(); - - for block in &mut blocks { - block.copy_from_slice(&INPUT); + impl<'a> BlockSizeUser for $name_back_enc<'a> { + type BlockSize = U16; } - unsafe { encrypt8(&load_expanded_keys(AES128_EXP_KEYS), &mut blocks) }; - - for block in &blocks { - assert_eq!(block.as_slice(), &EXPECTED); - } - } - - #[test] - fn aes128_decrypt() { - // Intentionally misaligned block - let mut block = [0u8; 19]; - block[3..].copy_from_slice(&EXPECTED); + impl<'a> ParBlocksSizeUser for $name_back_enc<'a> { + type ParBlocksSize = U8; + } - unsafe { - decrypt( - &load_expanded_keys(AES128_EXP_INVKEYS), - (&mut block[3..]).try_into().unwrap(), - ) - }; + impl<'a> BlockBackend for $name_back_enc<'a> { + #[inline(always)] + fn proc_block(&mut self, block: InOut<'_, '_, Block>) { + unsafe { + encrypt1(&self.0.round_keys, block); + } + } - assert_eq!(&block[3..], &INPUT); - } + #[inline(always)] + fn proc_par_blocks(&mut self, blocks: InOut<'_, '_, Block8>) { + unsafe { encrypt8(&self.0.round_keys, blocks) } + } + } - #[test] - fn aes128_decrypt8() { - let mut blocks = ParBlocks::default(); + pub(crate) struct $name_back_dec<'a>(&'a $name_dec); - for block in &mut blocks { - block.copy_from_slice(&EXPECTED); + impl<'a> BlockSizeUser for $name_back_dec<'a> { + type BlockSize = U16; } - unsafe { decrypt8(&load_expanded_keys(AES128_EXP_INVKEYS), &mut blocks) }; + impl<'a> ParBlocksSizeUser for $name_back_dec<'a> { + type ParBlocksSize = U8; + } + + impl<'a> BlockBackend for $name_back_dec<'a> { + #[inline(always)] + fn proc_block(&mut self, block: InOut<'_, '_, Block>) { + unsafe { + decrypt1(&self.0.round_keys, block); + } + } - for block in &blocks { - assert_eq!(block.as_slice(), &INPUT); + #[inline(always)] + fn proc_par_blocks(&mut self, blocks: InOut<'_, '_, Block8>) { + unsafe { decrypt8(&self.0.round_keys, blocks) } + } } - } + }; } + +define_aes_impl!( + Aes128, + Aes128Enc, + Aes128Dec, + Aes128BackEnc, + Aes128BackDec, + U16, + 11, + "AES-128", +); +define_aes_impl!( + Aes192, + Aes192Enc, + Aes192Dec, + Aes192BackEnc, + Aes192BackDec, + U24, + 13, + "AES-192", +); +define_aes_impl!( + Aes256, + Aes256Enc, + Aes256Dec, + Aes256BackEnc, + Aes256BackDec, + U32, + 15, + "AES-256", +); diff --git a/aes/src/armv8/decrypt.rs b/aes/src/armv8/decrypt.rs deleted file mode 100644 index cb841931..00000000 --- a/aes/src/armv8/decrypt.rs +++ /dev/null @@ -1,72 +0,0 @@ -//! AES decryption support. - -use crate::{Block, ParBlocks}; -use core::arch::aarch64::*; - -/// Perform AES decryption using the given expanded keys. -#[target_feature(enable = "aes")] -#[target_feature(enable = "neon")] -pub(super) unsafe fn decrypt(expanded_keys: &[uint8x16_t; N], block: &mut Block) { - let rounds = N - 1; - assert!(rounds == 10 || rounds == 12 || rounds == 14); - - let mut state = vld1q_u8(block.as_ptr()); - - for k in expanded_keys.iter().take(rounds - 1) { - // AES single round decryption - state = vaesdq_u8(state, *k); - - // AES inverse mix columns - state = vaesimcq_u8(state); - } - - // AES single round decryption - state = vaesdq_u8(state, expanded_keys[rounds - 1]); - - // Final add (bitwise XOR) - state = veorq_u8(state, expanded_keys[rounds]); - - vst1q_u8(block.as_mut_ptr(), state); -} - -/// Perform parallel AES decryption 8-blocks-at-a-time using the given expanded keys. -#[target_feature(enable = "aes")] -#[target_feature(enable = "neon")] -pub(super) unsafe fn decrypt8( - expanded_keys: &[uint8x16_t; N], - blocks: &mut ParBlocks, -) { - let rounds = N - 1; - assert!(rounds == 10 || rounds == 12 || rounds == 14); - - let mut state = [ - vld1q_u8(blocks[0].as_ptr()), - vld1q_u8(blocks[1].as_ptr()), - vld1q_u8(blocks[2].as_ptr()), - vld1q_u8(blocks[3].as_ptr()), - vld1q_u8(blocks[4].as_ptr()), - vld1q_u8(blocks[5].as_ptr()), - vld1q_u8(blocks[6].as_ptr()), - vld1q_u8(blocks[7].as_ptr()), - ]; - - for k in expanded_keys.iter().take(rounds - 1) { - for i in 0..8 { - // AES single round decryption - state[i] = vaesdq_u8(state[i], *k); - - // AES inverse mix columns - state[i] = vaesimcq_u8(state[i]); - } - } - - for i in 0..8 { - // AES single round decryption - state[i] = vaesdq_u8(state[i], expanded_keys[rounds - 1]); - - // Final add (bitwise XOR) - state[i] = veorq_u8(state[i], expanded_keys[rounds]); - - vst1q_u8(blocks[i].as_mut_ptr(), state[i]); - } -} diff --git a/aes/src/armv8/encdec.rs b/aes/src/armv8/encdec.rs new file mode 100644 index 00000000..ecf7d5c3 --- /dev/null +++ b/aes/src/armv8/encdec.rs @@ -0,0 +1,158 @@ +//! AES encryption support + +use crate::{Block, Block8}; +use cipher::inout::InOut; +use core::arch::aarch64::*; + +/// Perform AES encryption using the given expanded keys. +#[target_feature(enable = "aes")] +#[target_feature(enable = "neon")] +pub(super) unsafe fn encrypt1( + expanded_keys: &[uint8x16_t; N], + block: InOut<'_, '_, Block>, +) { + let rounds = N - 1; + assert!(rounds == 10 || rounds == 12 || rounds == 14); + + let (in_ptr, out_ptr) = block.into_raw(); + + let mut state = vld1q_u8(in_ptr as *const u8); + + for k in expanded_keys.iter().take(rounds - 1) { + // AES single round encryption + state = vaeseq_u8(state, *k); + + // AES mix columns + state = vaesmcq_u8(state); + } + + // AES single round encryption + state = vaeseq_u8(state, expanded_keys[rounds - 1]); + + // Final add (bitwise XOR) + state = veorq_u8(state, expanded_keys[rounds]); + + vst1q_u8(out_ptr as *mut u8, state); +} + +/// Perform parallel AES encryption 8-blocks-at-a-time using the given expanded keys. +#[target_feature(enable = "aes")] +#[target_feature(enable = "neon")] +pub(super) unsafe fn encrypt8( + expanded_keys: &[uint8x16_t; N], + blocks: InOut<'_, '_, Block8>, +) { + let rounds = N - 1; + assert!(rounds == 10 || rounds == 12 || rounds == 14); + + let (in_ptr, out_ptr) = blocks.into_raw(); + let in_ptr = in_ptr as *const Block; + let out_ptr = out_ptr as *const Block; + + let mut state = [ + vld1q_u8(in_ptr.add(0) as *const u8), + vld1q_u8(in_ptr.add(1) as *const u8), + vld1q_u8(in_ptr.add(2) as *const u8), + vld1q_u8(in_ptr.add(3) as *const u8), + vld1q_u8(in_ptr.add(4) as *const u8), + vld1q_u8(in_ptr.add(5) as *const u8), + vld1q_u8(in_ptr.add(6) as *const u8), + vld1q_u8(in_ptr.add(7) as *const u8), + ]; + + for k in expanded_keys.iter().take(rounds - 1) { + for i in 0..8 { + // AES single round encryption + state[i] = vaeseq_u8(state[i], *k); + + // AES mix columns + state[i] = vaesmcq_u8(state[i]); + } + } + + for i in 0..8 { + // AES single round encryption + state[i] = vaeseq_u8(state[i], expanded_keys[rounds - 1]); + + // Final add (bitwise XOR) + state[i] = veorq_u8(state[i], expanded_keys[rounds]); + + vst1q_u8(out_ptr.add(i) as *mut u8, state[i]); + } +} + +/// Perform AES decryption using the given expanded keys. +#[target_feature(enable = "aes")] +#[target_feature(enable = "neon")] +pub(super) unsafe fn decrypt1( + expanded_keys: &[uint8x16_t; N], + block: InOut<'_, '_, Block>, +) { + let rounds = N - 1; + assert!(rounds == 10 || rounds == 12 || rounds == 14); + + let (in_ptr, out_ptr) = block.into_raw(); + let mut state = vld1q_u8(in_ptr as *const u8); + + for k in expanded_keys.iter().take(rounds - 1) { + // AES single round decryption + state = vaesdq_u8(state, *k); + + // AES inverse mix columns + state = vaesimcq_u8(state); + } + + // AES single round decryption + state = vaesdq_u8(state, expanded_keys[rounds - 1]); + + // Final add (bitwise XOR) + state = veorq_u8(state, expanded_keys[rounds]); + + vst1q_u8(out_ptr as *mut u8, state); +} + +/// Perform parallel AES decryption 8-blocks-at-a-time using the given expanded keys. +#[target_feature(enable = "aes")] +#[target_feature(enable = "neon")] +pub(super) unsafe fn decrypt8( + expanded_keys: &[uint8x16_t; N], + blocks: InOut<'_, '_, Block8>, +) { + let rounds = N - 1; + assert!(rounds == 10 || rounds == 12 || rounds == 14); + + let (in_ptr, out_ptr) = blocks.into_raw(); + let in_ptr = in_ptr as *const Block; + let out_ptr = out_ptr as *const Block; + + let mut state = [ + vld1q_u8(in_ptr.add(0) as *const u8), + vld1q_u8(in_ptr.add(1) as *const u8), + vld1q_u8(in_ptr.add(2) as *const u8), + vld1q_u8(in_ptr.add(3) as *const u8), + vld1q_u8(in_ptr.add(4) as *const u8), + vld1q_u8(in_ptr.add(5) as *const u8), + vld1q_u8(in_ptr.add(6) as *const u8), + vld1q_u8(in_ptr.add(7) as *const u8), + ]; + + for k in expanded_keys.iter().take(rounds - 1) { + for i in 0..8 { + // AES single round decryption + state[i] = vaesdq_u8(state[i], *k); + + // AES inverse mix columns + state[i] = vaesimcq_u8(state[i]); + } + } + + for i in 0..8 { + // AES single round decryption + state[i] = vaesdq_u8(state[i], expanded_keys[rounds - 1]); + + // Final add (bitwise XOR) + state[i] = veorq_u8(state[i], expanded_keys[rounds]); + + vst1q_u8(out_ptr.add(i) as *mut u8, state[i]); + } +} diff --git a/aes/src/armv8/encrypt.rs b/aes/src/armv8/encrypt.rs deleted file mode 100644 index 8464173a..00000000 --- a/aes/src/armv8/encrypt.rs +++ /dev/null @@ -1,72 +0,0 @@ -//! AES encryption support - -use crate::{Block, ParBlocks}; -use core::arch::aarch64::*; - -/// Perform AES encryption using the given expanded keys. -#[target_feature(enable = "aes")] -#[target_feature(enable = "neon")] -pub(super) unsafe fn encrypt(expanded_keys: &[uint8x16_t; N], block: &mut Block) { - let rounds = N - 1; - assert!(rounds == 10 || rounds == 12 || rounds == 14); - - let mut state = vld1q_u8(block.as_ptr()); - - for k in expanded_keys.iter().take(rounds - 1) { - // AES single round encryption - state = vaeseq_u8(state, *k); - - // AES mix columns - state = vaesmcq_u8(state); - } - - // AES single round encryption - state = vaeseq_u8(state, expanded_keys[rounds - 1]); - - // Final add (bitwise XOR) - state = veorq_u8(state, expanded_keys[rounds]); - - vst1q_u8(block.as_mut_ptr(), state); -} - -/// Perform parallel AES encryption 8-blocks-at-a-time using the given expanded keys. -#[target_feature(enable = "aes")] -#[target_feature(enable = "neon")] -pub(super) unsafe fn encrypt8( - expanded_keys: &[uint8x16_t; N], - blocks: &mut ParBlocks, -) { - let rounds = N - 1; - assert!(rounds == 10 || rounds == 12 || rounds == 14); - - let mut state = [ - vld1q_u8(blocks[0].as_ptr()), - vld1q_u8(blocks[1].as_ptr()), - vld1q_u8(blocks[2].as_ptr()), - vld1q_u8(blocks[3].as_ptr()), - vld1q_u8(blocks[4].as_ptr()), - vld1q_u8(blocks[5].as_ptr()), - vld1q_u8(blocks[6].as_ptr()), - vld1q_u8(blocks[7].as_ptr()), - ]; - - for k in expanded_keys.iter().take(rounds - 1) { - for i in 0..8 { - // AES single round encryption - state[i] = vaeseq_u8(state[i], *k); - - // AES mix columns - state[i] = vaesmcq_u8(state[i]); - } - } - - for i in 0..8 { - // AES single round encryption - state[i] = vaeseq_u8(state[i], expanded_keys[rounds - 1]); - - // Final add (bitwise XOR) - state[i] = veorq_u8(state[i], expanded_keys[rounds]); - - vst1q_u8(blocks[i].as_mut_ptr(), state[i]); - } -} diff --git a/aes/src/armv8/expand.rs b/aes/src/armv8/expand.rs index 2e26e391..8e5cf88c 100644 --- a/aes/src/armv8/expand.rs +++ b/aes/src/armv8/expand.rs @@ -1,6 +1,6 @@ //! AES key expansion support. -use core::{arch::aarch64::*, convert::TryInto, mem, slice}; +use core::{arch::aarch64::*, mem, slice}; /// There are 4 AES words in a block. const BLOCK_WORDS: usize = 4; diff --git a/aes/src/armv8/hazmat.rs b/aes/src/armv8/hazmat.rs index 022db3a6..f094243c 100644 --- a/aes/src/armv8/hazmat.rs +++ b/aes/src/armv8/hazmat.rs @@ -4,7 +4,7 @@ //! implementations in this crate, but instead provides raw AES-NI accelerated //! access to the AES round function gated under the `hazmat` crate feature. -use crate::{Block, ParBlocks}; +use crate::{Block, Block8}; use core::arch::aarch64::*; /// AES cipher (encrypt) round function. @@ -29,7 +29,7 @@ pub(crate) unsafe fn cipher_round(block: &mut Block, round_key: &Block) { /// AES cipher (encrypt) round function: parallel version. #[allow(clippy::cast_ptr_alignment)] #[target_feature(enable = "aes")] -pub(crate) unsafe fn cipher_round_par(blocks: &mut ParBlocks, round_keys: &ParBlocks) { +pub(crate) unsafe fn cipher_round_par(blocks: &mut Block8, round_keys: &Block8) { for i in 0..8 { let mut state = vld1q_u8(blocks[i].as_ptr()); @@ -68,7 +68,7 @@ pub(crate) unsafe fn equiv_inv_cipher_round(block: &mut Block, round_key: &Block /// AES equivalent inverse cipher (decrypt) round function: parallel version. #[allow(clippy::cast_ptr_alignment)] #[target_feature(enable = "aes")] -pub(crate) unsafe fn equiv_inv_cipher_round_par(blocks: &mut ParBlocks, round_keys: &ParBlocks) { +pub(crate) unsafe fn equiv_inv_cipher_round_par(blocks: &mut Block8, round_keys: &Block8) { for i in 0..8 { let mut state = vld1q_u8(blocks[i].as_ptr()); diff --git a/aes/src/armv8/test_expand.rs b/aes/src/armv8/test_expand.rs new file mode 100644 index 00000000..c52bda74 --- /dev/null +++ b/aes/src/armv8/test_expand.rs @@ -0,0 +1,130 @@ +use super::{expand_key, inv_expanded_keys}; +use core::arch::aarch64::*; +use hex_literal::hex; + +/// FIPS 197, Appendix A.1: AES-128 Cipher Key +/// user input, unaligned buffer +const AES128_KEY: [u8; 16] = hex!("2b7e151628aed2a6abf7158809cf4f3c"); + +/// FIPS 197 Appendix A.1: Expansion of a 128-bit Cipher Key +/// library controlled, aligned buffer +const AES128_EXP_KEYS: [[u8; 16]; 11] = [ + AES128_KEY, + hex!("a0fafe1788542cb123a339392a6c7605"), + hex!("f2c295f27a96b9435935807a7359f67f"), + hex!("3d80477d4716fe3e1e237e446d7a883b"), + hex!("ef44a541a8525b7fb671253bdb0bad00"), + hex!("d4d1c6f87c839d87caf2b8bc11f915bc"), + hex!("6d88a37a110b3efddbf98641ca0093fd"), + hex!("4e54f70e5f5fc9f384a64fb24ea6dc4f"), + hex!("ead27321b58dbad2312bf5607f8d292f"), + hex!("ac7766f319fadc2128d12941575c006e"), + hex!("d014f9a8c9ee2589e13f0cc8b6630ca6"), +]; + +/// Inverse expanded keys for [`AES128_EXPANDED_KEYS`] +const AES128_EXP_INVKEYS: [[u8; 16]; 11] = [ + hex!("d014f9a8c9ee2589e13f0cc8b6630ca6"), + hex!("0c7b5a631319eafeb0398890664cfbb4"), + hex!("df7d925a1f62b09da320626ed6757324"), + hex!("12c07647c01f22c7bc42d2f37555114a"), + hex!("6efcd876d2df54807c5df034c917c3b9"), + hex!("6ea30afcbc238cf6ae82a4b4b54a338d"), + hex!("90884413d280860a12a128421bc89739"), + hex!("7c1f13f74208c219c021ae480969bf7b"), + hex!("cc7505eb3e17d1ee82296c51c9481133"), + hex!("2b3708a7f262d405bc3ebdbf4b617d62"), + AES128_KEY, +]; + +/// FIPS 197, Appendix A.2: AES-192 Cipher Key +/// user input, unaligned buffer +const AES192_KEY: [u8; 24] = hex!("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"); + +/// FIPS 197 Appendix A.2: Expansion of a 192-bit Cipher Key +/// library controlled, aligned buffer +const AES192_EXP_KEYS: [[u8; 16]; 13] = [ + hex!("8e73b0f7da0e6452c810f32b809079e5"), + hex!("62f8ead2522c6b7bfe0c91f72402f5a5"), + hex!("ec12068e6c827f6b0e7a95b95c56fec2"), + hex!("4db7b4bd69b5411885a74796e92538fd"), + hex!("e75fad44bb095386485af05721efb14f"), + hex!("a448f6d94d6dce24aa326360113b30e6"), + hex!("a25e7ed583b1cf9a27f939436a94f767"), + hex!("c0a69407d19da4e1ec1786eb6fa64971"), + hex!("485f703222cb8755e26d135233f0b7b3"), + hex!("40beeb282f18a2596747d26b458c553e"), + hex!("a7e1466c9411f1df821f750aad07d753"), + hex!("ca4005388fcc5006282d166abc3ce7b5"), + hex!("e98ba06f448c773c8ecc720401002202"), +]; + +/// FIPS 197, Appendix A.3: AES-256 Cipher Key +/// user input, unaligned buffer +const AES256_KEY: [u8; 32] = + hex!("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"); + +/// FIPS 197 Appendix A.3: Expansion of a 256-bit Cipher Key +/// library controlled, aligned buffer +const AES256_EXP_KEYS: [[u8; 16]; 15] = [ + hex!("603deb1015ca71be2b73aef0857d7781"), + hex!("1f352c073b6108d72d9810a30914dff4"), + hex!("9ba354118e6925afa51a8b5f2067fcde"), + hex!("a8b09c1a93d194cdbe49846eb75d5b9a"), + hex!("d59aecb85bf3c917fee94248de8ebe96"), + hex!("b5a9328a2678a647983122292f6c79b3"), + hex!("812c81addadf48ba24360af2fab8b464"), + hex!("98c5bfc9bebd198e268c3ba709e04214"), + hex!("68007bacb2df331696e939e46c518d80"), + hex!("c814e20476a9fb8a5025c02d59c58239"), + hex!("de1369676ccc5a71fa2563959674ee15"), + hex!("5886ca5d2e2f31d77e0af1fa27cf73c3"), + hex!("749c47ab18501ddae2757e4f7401905a"), + hex!("cafaaae3e4d59b349adf6acebd10190d"), + hex!("fe4890d1e6188d0b046df344706c631e"), +]; + +fn load_expanded_keys(input: [[u8; 16]; N]) -> [uint8x16_t; N] { + let mut output = [unsafe { vdupq_n_u8(0) }; N]; + + for (src, dst) in input.iter().zip(output.iter_mut()) { + *dst = unsafe { vld1q_u8(src.as_ptr()) } + } + + output +} + +fn store_expanded_keys(input: [uint8x16_t; N]) -> [[u8; 16]; N] { + let mut output = [[0u8; 16]; N]; + + for (src, dst) in input.iter().zip(output.iter_mut()) { + unsafe { vst1q_u8(dst.as_mut_ptr(), *src) } + } + + output +} + +#[test] +fn aes128_key_expansion() { + let ek = expand_key(&AES128_KEY); + assert_eq!(store_expanded_keys(ek), AES128_EXP_KEYS); +} + +#[test] +fn aes128_key_expansion_inv() { + let mut ek = load_expanded_keys(AES128_EXP_KEYS); + inv_expanded_keys(&mut ek); + assert_eq!(store_expanded_keys(ek), AES128_EXP_INVKEYS); +} + +#[test] +fn aes192_key_expansion() { + let ek = expand_key(&AES192_KEY); + assert_eq!(store_expanded_keys(ek), AES192_EXP_KEYS); +} + +#[test] +fn aes256_key_expansion() { + let ek = expand_key(&AES256_KEY); + assert_eq!(store_expanded_keys(ek), AES256_EXP_KEYS); +} diff --git a/aes/src/autodetect.rs b/aes/src/autodetect.rs index dbbdeabf..8c3b1c12 100644 --- a/aes/src/autodetect.rs +++ b/aes/src/autodetect.rs @@ -1,15 +1,16 @@ //! Autodetection support for hardware accelerated AES backends with fallback //! to the fixsliced "soft" implementation. -use crate::{soft, Block, ParBlocks}; +use crate::soft; use cipher::{ - consts::{U16, U24, U32, U8}, - generic_array::GenericArray, - BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher, + consts::{U16, U24, U32}, + AlgorithmName, BlockCipher, BlockClosure, BlockDecrypt, BlockEncrypt, BlockSizeUser, Key, + KeyInit, KeySizeUser, }; +use core::fmt; use core::mem::ManuallyDrop; -#[cfg(all(target_arch = "aarch64", feature = "armv8"))] +#[cfg(all(target_arch = "aarch64", aes_armv8))] use crate::armv8 as intrinsics; #[cfg(any(target_arch = "x86_64", target_arch = "x86"))] @@ -19,17 +20,13 @@ cpufeatures::new!(aes_intrinsics, "aes"); macro_rules! define_aes_impl { ( - $name:tt, + $name:ident, + $name_enc:ident, + $name_dec:ident, $module:tt, $key_size:ty, - $doc:expr + $doc:expr $(,)? ) => { - #[doc=$doc] - pub struct $name { - inner: $module::Inner, - token: aes_intrinsics::InitToken, - } - mod $module { use super::{intrinsics, soft}; use core::mem::ManuallyDrop; @@ -38,13 +35,60 @@ macro_rules! define_aes_impl { pub(super) intrinsics: ManuallyDrop, pub(super) soft: ManuallyDrop, } + + pub(super) union InnerEnc { + pub(super) intrinsics: ManuallyDrop, + pub(super) soft: ManuallyDrop, + } + + pub(super) union InnerDec { + pub(super) intrinsics: ManuallyDrop, + pub(super) soft: ManuallyDrop, + } } - impl NewBlockCipher for $name { + #[doc=$doc] + #[doc = "block cipher"] + pub struct $name { + inner: $module::Inner, + token: aes_intrinsics::InitToken, + } + + impl KeySizeUser for $name { type KeySize = $key_size; + } + impl From<$name_enc> for $name { + #[inline] + fn from(enc: $name_enc) -> $name { + Self::from(&enc) + } + } + impl From<&$name_enc> for $name { + fn from(enc: &$name_enc) -> $name { + use core::ops::Deref; + let inner = if enc.token.get() { + $module::Inner { + intrinsics: ManuallyDrop::new(unsafe { + enc.inner.intrinsics.deref().into() + }), + } + } else { + $module::Inner { + soft: ManuallyDrop::new(unsafe { enc.inner.soft.deref().into() }), + } + }; + + Self { + inner, + token: enc.token, + } + } + } + + impl KeyInit for $name { #[inline] - fn new(key: &GenericArray) -> Self { + fn new(key: &Key) -> Self { let (token, aesni_present) = aes_intrinsics::init_get(); let inner = if aesni_present { @@ -80,180 +124,265 @@ macro_rules! define_aes_impl { } } - impl BlockCipher for $name { + impl BlockSizeUser for $name { type BlockSize = U16; - type ParBlocks = U8; } + impl BlockCipher for $name {} + impl BlockEncrypt for $name { - #[inline] - fn encrypt_block(&self, block: &mut Block) { - if self.token.get() { - unsafe { self.inner.intrinsics.encrypt_block(block) } - } else { - unsafe { self.inner.soft.encrypt_block(block) } + fn encrypt_with_backend(&self, f: impl BlockClosure) { + unsafe { + if self.token.get() { + #[target_feature(enable = "aes")] + unsafe fn inner( + state: &intrinsics::$name, + f: impl BlockClosure, + ) { + f.call(&mut state.get_enc_backend()); + } + inner(&self.inner.intrinsics, f); + } else { + f.call(&mut self.inner.soft.get_enc_backend()); + } } } + } - #[inline] - fn encrypt_par_blocks(&self, blocks: &mut ParBlocks) { - if self.token.get() { - unsafe { self.inner.intrinsics.encrypt_par_blocks(blocks) } - } else { - unsafe { self.inner.soft.encrypt_par_blocks(blocks) } + impl BlockDecrypt for $name { + fn decrypt_with_backend(&self, f: impl BlockClosure) { + unsafe { + if self.token.get() { + #[target_feature(enable = "aes")] + unsafe fn inner( + state: &intrinsics::$name, + f: impl BlockClosure, + ) { + f.call(&mut state.get_dec_backend()); + } + inner(&self.inner.intrinsics, f); + } else { + f.call(&mut self.inner.soft.get_dec_backend()); + } } } } - impl BlockDecrypt for $name { - #[inline] - fn decrypt_block(&self, block: &mut Block) { - if self.token.get() { - unsafe { self.inner.intrinsics.decrypt_block(block) } - } else { - unsafe { self.inner.soft.decrypt_block(block) } - } + impl fmt::Debug for $name { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str(concat!(stringify!($name), " { .. }")) } + } - #[inline] - fn decrypt_par_blocks(&self, blocks: &mut ParBlocks) { - if self.token.get() { - unsafe { self.inner.intrinsics.decrypt_par_blocks(blocks) } - } else { - unsafe { self.inner.soft.decrypt_par_blocks(blocks) } - } + impl AlgorithmName for $name { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(stringify!($name)) } } - opaque_debug::implement!($name); - }; -} + #[doc=$doc] + #[doc = "block cipher (encrypt-only)"] + pub struct $name_enc { + inner: $module::InnerEnc, + token: aes_intrinsics::InitToken, + } -define_aes_impl!(Aes128, aes128, U16, "AES-128 block cipher instance"); -define_aes_impl!(Aes192, aes192, U24, "AES-192 block cipher instance"); -define_aes_impl!(Aes256, aes256, U32, "AES-256 block cipher instance"); + impl KeySizeUser for $name_enc { + type KeySize = $key_size; + } -#[cfg(all(feature = "ctr", target_arch = "aarch64"))] -pub(crate) mod ctr { - use super::{Aes128, Aes192, Aes256}; + impl KeyInit for $name_enc { + #[inline] + fn new(key: &Key) -> Self { + let (token, aesni_present) = aes_intrinsics::init_get(); - /// AES-128 in CTR mode - pub type Aes128Ctr = ::ctr::Ctr64BE; + let inner = if aesni_present { + $module::InnerEnc { + intrinsics: ManuallyDrop::new(intrinsics::$name_enc::new(key)), + } + } else { + $module::InnerEnc { + soft: ManuallyDrop::new(soft::$name_enc::new(key)), + } + }; - /// AES-192 in CTR mode - pub type Aes192Ctr = ::ctr::Ctr64BE; + Self { inner, token } + } + } - /// AES-256 in CTR mode - pub type Aes256Ctr = ::ctr::Ctr64BE; -} + impl Clone for $name_enc { + fn clone(&self) -> Self { + let inner = if self.token.get() { + $module::InnerEnc { + intrinsics: unsafe { self.inner.intrinsics.clone() }, + } + } else { + $module::InnerEnc { + soft: unsafe { self.inner.soft.clone() }, + } + }; -#[cfg(all(feature = "ctr", any(target_arch = "x86_64", target_arch = "x86")))] -pub(crate) mod ctr { - use super::{Aes128, Aes192, Aes256}; - use crate::{ni, soft}; - use cipher::{ - errors::{LoopError, OverflowError}, - generic_array::GenericArray, - BlockCipher, FromBlockCipher, SeekNum, StreamCipher, StreamCipherSeek, - }; - use core::mem::ManuallyDrop; - - cpufeatures::new!(aes_ssse3_cpuid, "aes", "ssse3"); - - macro_rules! define_aes_ctr_impl { - ( - $name:tt, - $cipher:ident, - $module:tt, - $doc:expr - ) => { - #[doc=$doc] - #[cfg_attr(docsrs, doc(cfg(feature = "ctr")))] - pub struct $name { - inner: $module::Inner, - token: aes_ssse3_cpuid::InitToken, + Self { + inner, + token: self.token, + } } + } + + impl BlockSizeUser for $name_enc { + type BlockSize = U16; + } - mod $module { - use crate::{ni, soft}; - use core::mem::ManuallyDrop; + impl BlockCipher for $name_enc {} - pub(super) union Inner { - pub(super) ni: ManuallyDrop, - pub(super) soft: ManuallyDrop, + impl BlockEncrypt for $name_enc { + fn encrypt_with_backend(&self, f: impl BlockClosure) { + unsafe { + if self.token.get() { + #[target_feature(enable = "aes")] + unsafe fn inner( + state: &intrinsics::$name_enc, + f: impl BlockClosure, + ) { + f.call(&mut state.get_enc_backend()); + } + inner(&self.inner.intrinsics, f); + } else { + f.call(&mut self.inner.soft.get_enc_backend()); + } } } + } - impl FromBlockCipher for $name { - type BlockCipher = $cipher; - type NonceSize = <$cipher as BlockCipher>::BlockSize; + impl fmt::Debug for $name_enc { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str(concat!(stringify!($name_enc), " { .. }")) + } + } + + impl AlgorithmName for $name_enc { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(stringify!($name_enc)) + } + } - fn from_block_cipher( - cipher: $cipher, - nonce: &GenericArray, - ) -> Self { - let (token, aesni_present) = aes_ssse3_cpuid::init_get(); + #[doc=$doc] + #[doc = "block cipher (decrypt-only)"] + pub struct $name_dec { + inner: $module::InnerDec, + token: aes_intrinsics::InitToken, + } - let inner = if aesni_present { - let ni = ni::$name::from_block_cipher( - unsafe { (*cipher.inner.intrinsics).clone() }, - nonce, - ); + impl KeySizeUser for $name_dec { + type KeySize = $key_size; + } - $module::Inner { - ni: ManuallyDrop::new(ni), - } - } else { - let soft = soft::$name::from_block_cipher( - unsafe { (*cipher.inner.soft).clone() }, - nonce, - ); + impl From<$name_enc> for $name_dec { + #[inline] + fn from(enc: $name_enc) -> $name_dec { + Self::from(&enc) + } + } - $module::Inner { - soft: ManuallyDrop::new(soft), - } - }; + impl From<&$name_enc> for $name_dec { + fn from(enc: &$name_enc) -> $name_dec { + use core::ops::Deref; + let inner = if enc.token.get() { + $module::InnerDec { + intrinsics: ManuallyDrop::new(unsafe { + enc.inner.intrinsics.deref().into() + }), + } + } else { + $module::InnerDec { + soft: ManuallyDrop::new(unsafe { enc.inner.soft.deref().into() }), + } + }; - Self { inner, token } + Self { + inner, + token: enc.token, } } + } - impl StreamCipher for $name { - #[inline] - fn try_apply_keystream(&mut self, data: &mut [u8]) -> Result<(), LoopError> { - if self.token.get() { - unsafe { (*self.inner.ni).try_apply_keystream(data) } - } else { - unsafe { (*self.inner.soft).try_apply_keystream(data) } + impl KeyInit for $name_dec { + #[inline] + fn new(key: &Key) -> Self { + let (token, aesni_present) = aes_intrinsics::init_get(); + + let inner = if aesni_present { + $module::InnerDec { + intrinsics: ManuallyDrop::new(intrinsics::$name_dec::new(key)), } - } + } else { + $module::InnerDec { + soft: ManuallyDrop::new(soft::$name_dec::new(key)), + } + }; + + Self { inner, token } } + } - impl StreamCipherSeek for $name { - #[inline] - fn try_current_pos(&self) -> Result { - if self.token.get() { - unsafe { (*self.inner.ni).try_current_pos() } - } else { - unsafe { (*self.inner.soft).try_current_pos() } + impl Clone for $name_dec { + fn clone(&self) -> Self { + let inner = if self.token.get() { + $module::InnerDec { + intrinsics: unsafe { self.inner.intrinsics.clone() }, + } + } else { + $module::InnerDec { + soft: unsafe { self.inner.soft.clone() }, } + }; + + Self { + inner, + token: self.token, } + } + } + + impl BlockSizeUser for $name_dec { + type BlockSize = U16; + } - #[inline] - fn try_seek(&mut self, pos: T) -> Result<(), LoopError> { + impl BlockCipher for $name_dec {} + + impl BlockDecrypt for $name_dec { + fn decrypt_with_backend(&self, f: impl BlockClosure) { + unsafe { if self.token.get() { - unsafe { (*self.inner.ni).try_seek(pos) } + #[target_feature(enable = "aes")] + unsafe fn inner( + state: &intrinsics::$name_dec, + f: impl BlockClosure, + ) { + f.call(&mut state.get_dec_backend()); + } + inner(&self.inner.intrinsics, f); } else { - unsafe { (*self.inner.soft).try_seek(pos) } + f.call(&mut self.inner.soft.get_dec_backend()); } } } + } - opaque_debug::implement!($name); - }; - } + impl fmt::Debug for $name_dec { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str(concat!(stringify!($name_dec), " { .. }")) + } + } - define_aes_ctr_impl!(Aes128Ctr, Aes128, aes128ctr, "AES-128 in CTR mode"); - define_aes_ctr_impl!(Aes192Ctr, Aes192, aes192ctr, "AES-192 in CTR mode"); - define_aes_ctr_impl!(Aes256Ctr, Aes256, aes256ctr, "AES-256 in CTR mode"); + impl AlgorithmName for $name_dec { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(stringify!($name_dec)) + } + } + }; } + +define_aes_impl!(Aes128, Aes128Enc, Aes128Dec, aes128, U16, "AES-128"); +define_aes_impl!(Aes192, Aes192Enc, Aes192Dec, aes192, U24, "AES-192"); +define_aes_impl!(Aes256, Aes256Enc, Aes256Dec, aes256, U32, "AES-256"); diff --git a/aes/src/hazmat.rs b/aes/src/hazmat.rs index ff628e59..9b5555ea 100644 --- a/aes/src/hazmat.rs +++ b/aes/src/hazmat.rs @@ -11,28 +11,21 @@ //! We do NOT recommending using it to implement any algorithm which has not //! received extensive peer review by cryptographers. -use crate::{soft::fixslice::hazmat as soft, Block, ParBlocks}; +use crate::{soft::fixslice::hazmat as soft, Block, Block8}; -#[cfg(all( - target_arch = "aarch64", - feature = "armv8", - not(feature = "force-soft") -))] +#[cfg(all(target_arch = "aarch64", aes_armv8, not(aes_force_soft)))] use crate::armv8::hazmat as intrinsics; -#[cfg(all( - any(target_arch = "x86_64", target_arch = "x86"), - not(feature = "force-soft") -))] +#[cfg(all(any(target_arch = "x86_64", target_arch = "x86"), not(aes_force_soft)))] use crate::ni::hazmat as intrinsics; #[cfg(all( any( target_arch = "x86", target_arch = "x86_64", - all(target_arch = "aarch64", feature = "armv8") + all(target_arch = "aarch64", aes_armv8) ), - not(feature = "force-soft") + not(aes_force_soft) ))] cpufeatures::new!(aes_intrinsics, "aes"); @@ -44,9 +37,9 @@ macro_rules! if_intrinsics_available { any( target_arch = "x86", target_arch = "x86_64", - all(target_arch = "aarch64", feature = "armv8") + all(target_arch = "aarch64", aes_armv8) ), - not(feature = "force-soft") + not(aes_force_soft) ))] if aes_intrinsics::get() { unsafe { $body } @@ -87,7 +80,7 @@ pub fn cipher_round(block: &mut Block, round_key: &Block) { /// /// Use this function with great care! See the [module-level documentation][crate::hazmat] /// for more information. -pub fn cipher_round_par(blocks: &mut ParBlocks, round_keys: &ParBlocks) { +pub fn cipher_round_par(blocks: &mut Block8, round_keys: &Block8) { if_intrinsics_available! { intrinsics::cipher_round_par(blocks, round_keys) } @@ -127,7 +120,7 @@ pub fn equiv_inv_cipher_round(block: &mut Block, round_key: &Block) { /// /// Use this function with great care! See the [module-level documentation][crate::hazmat] /// for more information. -pub fn equiv_inv_cipher_round_par(blocks: &mut ParBlocks, round_keys: &ParBlocks) { +pub fn equiv_inv_cipher_round_par(blocks: &mut Block8, round_keys: &Block8) { if_intrinsics_available! { intrinsics::equiv_inv_cipher_round_par(blocks, round_keys) } diff --git a/aes/src/lib.rs b/aes/src/lib.rs index f33183c1..d8c9bf86 100644 --- a/aes/src/lib.rs +++ b/aes/src/lib.rs @@ -1,5 +1,5 @@ -//! Pure Rust implementation of the Advanced Encryption Standard -//! (a.k.a. Rijndael) +//! Pure Rust implementation of the [Advanced Encryption Standard][AES] +//! (AES, a.k.a. Rijndael). //! //! # Supported backends //! This crate provides multiple backends including a portable pure Rust @@ -44,15 +44,14 @@ //! //! # Usage example //! ``` -//! use aes::{Aes128, Block, ParBlocks}; +//! use aes::Aes128; //! use aes::cipher::{ -//! BlockCipher, BlockEncrypt, BlockDecrypt, NewBlockCipher, +//! BlockCipher, BlockEncrypt, BlockDecrypt, KeyInit, //! generic_array::GenericArray, //! }; //! -//! let key = GenericArray::from_slice(&[0u8; 16]); -//! let mut block = Block::default(); -//! let mut block8 = ParBlocks::default(); +//! let key = GenericArray::from([0u8; 16]); +//! let mut block = GenericArray::from([42u8; 16]); //! //! // Initialize cipher //! let cipher = Aes128::new(&key); @@ -66,32 +65,57 @@ //! cipher.decrypt_block(&mut block); //! assert_eq!(block, block_copy); //! -//! // We can encrypt 8 blocks simultaneously using -//! // instruction-level parallelism -//! let block8_copy = block8.clone(); -//! cipher.encrypt_par_blocks(&mut block8); -//! cipher.decrypt_par_blocks(&mut block8); -//! assert_eq!(block8, block8_copy); +//! // implementation supports parrallel block processing +//! // number of blocks processed in parallel depends in general +//! // on hardware capabilities +//! let mut blocks = [block; 100]; +//! cipher.encrypt_blocks(&mut blocks); +//! +//! for block in blocks.iter_mut() { +//! cipher.decrypt_block(block); +//! assert_eq!(block, &block_copy); +//! } +//! +//! cipher.decrypt_blocks(&mut blocks); +//! +//! for block in blocks.iter_mut() { +//! cipher.encrypt_block(block); +//! assert_eq!(block, &block_copy); +//! } //! ``` //! //! For implementations of block cipher modes of operation see //! [`block-modes`] crate. //! +//! # Configuration Flags +//! +//! You can modify crate using the following configuration flags: +//! +//! - `aes_armv8`: enable ARMv8 AES intrinsics (nightly-only). +//! - `aes_force_soft`: force software implementation. +//! - `aes_compact`: reduce code size at the cost of slower performance +//! (affects only software backend). +//! +//! It can be enabled using `RUSTFLAGS` enviromental variable +//! (e.g. `RUSTFLAGS="--cfg aes_compact"`) or by modifying `.cargo/config`. +//! +//! [AES]: https://en.wikipedia.org/wiki/Advanced_Encryption_Standard //! [fixslicing]: https://eprint.iacr.org/2020/1123.pdf //! [AES-NI]: https://en.wikipedia.org/wiki/AES_instruction_set //! [`block-modes`]: https://docs.rs/block-modes #![no_std] -#![cfg_attr( - all(feature = "armv8", target_arch = "aarch64"), - feature(stdsimd, aarch64_target_feature) -)] -#![cfg_attr(docsrs, feature(doc_cfg))] #![doc( - html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg", - html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg" + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg", + html_root_url = "https://docs.rs/aes/0.8.0" )] +#![cfg_attr(docsrs, feature(doc_cfg))] #![warn(missing_docs, rust_2018_idioms)] +#![cfg_attr( + all(aes_armv8, target_arch = "aarch64"), + feature(stdsimd, aarch64_target_feature) +)] #[cfg(feature = "hazmat")] pub mod hazmat; @@ -101,38 +125,29 @@ mod soft; use cfg_if::cfg_if; cfg_if! { - if #[cfg(all(target_arch = "aarch64", feature = "armv8", not(feature = "force-soft")))] { + if #[cfg(all(target_arch = "aarch64", aes_armv8, not(aes_force_soft)))] { mod armv8; mod autodetect; - pub use autodetect::{Aes128, Aes192, Aes256}; - - #[cfg(feature = "ctr")] - pub use autodetect::ctr::{Aes128Ctr, Aes192Ctr, Aes256Ctr}; + pub use autodetect::*; } else if #[cfg(all( any(target_arch = "x86", target_arch = "x86_64"), - not(feature = "force-soft") + not(aes_force_soft) ))] { mod autodetect; mod ni; - pub use autodetect::{Aes128, Aes192, Aes256}; - - #[cfg(feature = "ctr")] - pub use autodetect::ctr::{Aes128Ctr, Aes192Ctr, Aes256Ctr}; + pub use autodetect::*; } else { - pub use soft::{Aes128, Aes192, Aes256}; - - #[cfg(feature = "ctr")] - pub use soft::{Aes128Ctr, Aes192Ctr, Aes256Ctr}; + pub use soft::*; } } -pub use cipher::{self, BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher}; +pub use cipher; +use cipher::{ + consts::{U16, U8}, + generic_array::GenericArray, +}; /// 128-bit AES block -pub type Block = cipher::generic_array::GenericArray; - -/// 8 x 128-bit AES blocks to be processed in parallel -pub type ParBlocks = cipher::generic_array::GenericArray; - -/// Size of an AES block (128-bits; 16-bytes) -pub const BLOCK_SIZE: usize = 16; +pub type Block = GenericArray; +/// Eight 128-bit AES blocks +pub type Block8 = GenericArray; diff --git a/aes/src/ni.rs b/aes/src/ni.rs index 56e8e1f8..f5bdbbc1 100644 --- a/aes/src/ni.rs +++ b/aes/src/ni.rs @@ -3,12 +3,6 @@ //! Ciphers functionality is accessed using `BlockCipher` trait from the //! [`cipher`](https://docs.rs/cipher) crate. //! -//! # CTR mode -//! In addition to core block cipher functionality this crate provides optimized -//! CTR mode implementation. This functionality requires additional `ssse3` -//! target feature and feature-gated behind `ctr` feature flag, which is enabled -//! by default. -//! //! # Vulnerability //! Lazy FP state restory vulnerability can allow local process to leak content //! of the FPU register, in which round keys are stored. This vulnerability @@ -28,8 +22,8 @@ mod aes128; mod aes192; mod aes256; -#[cfg(feature = "ctr")] -mod ctr; +#[cfg(test)] +mod test_expand; #[cfg(feature = "hazmat")] pub(crate) mod hazmat; @@ -39,7 +33,304 @@ use core::arch::x86 as arch; #[cfg(target_arch = "x86_64")] use core::arch::x86_64 as arch; -pub use self::{aes128::Aes128, aes192::Aes192, aes256::Aes256}; +use crate::{Block, Block8}; +use cipher::{ + consts::{U16, U24, U32, U8}, + inout::InOut, + AlgorithmName, BlockBackend, BlockCipher, BlockClosure, BlockDecrypt, BlockEncrypt, + BlockSizeUser, Key, KeyInit, KeySizeUser, ParBlocksSizeUser, +}; +use core::fmt; + +macro_rules! define_aes_impl { + ( + $name:tt, + $name_enc:ident, + $name_dec:ident, + $name_back_enc:ident, + $name_back_dec:ident, + $module:tt, + $key_size:ty, + $doc:expr $(,)? + ) => { + #[doc=$doc] + #[doc = "block cipher"] + #[derive(Clone)] + pub struct $name { + encrypt: $name_enc, + decrypt: $name_dec, + } + + impl $name { + #[inline(always)] + pub(crate) fn get_enc_backend(&self) -> $name_back_enc<'_> { + self.encrypt.get_enc_backend() + } + + #[inline(always)] + pub(crate) fn get_dec_backend(&self) -> $name_back_dec<'_> { + self.decrypt.get_dec_backend() + } + } + + impl BlockCipher for $name {} + + impl KeySizeUser for $name { + type KeySize = $key_size; + } + + impl KeyInit for $name { + #[inline] + fn new(key: &Key) -> Self { + let encrypt = $name_enc::new(key); + let decrypt = $name_dec::from(&encrypt); + Self { encrypt, decrypt } + } + } + + impl From<$name_enc> for $name { + #[inline] + fn from(encrypt: $name_enc) -> $name { + let decrypt = (&encrypt).into(); + Self { encrypt, decrypt } + } + } + + impl From<&$name_enc> for $name { + #[inline] + fn from(encrypt: &$name_enc) -> $name { + let decrypt = encrypt.into(); + let encrypt = encrypt.clone(); + Self { encrypt, decrypt } + } + } + + impl BlockSizeUser for $name { + type BlockSize = U16; + } + + impl BlockEncrypt for $name { + fn encrypt_with_backend(&self, f: impl BlockClosure) { + self.encrypt.encrypt_with_backend(f) + } + } + + impl BlockDecrypt for $name { + fn decrypt_with_backend(&self, f: impl BlockClosure) { + self.decrypt.decrypt_with_backend(f) + } + } + + impl fmt::Debug for $name { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str(concat!(stringify!($name), " { .. }")) + } + } + + impl AlgorithmName for $name { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(stringify!($name)) + } + } + + #[doc=$doc] + #[doc = "block cipher (encrypt-only)"] + #[derive(Clone)] + pub struct $name_enc { + round_keys: $module::RoundKeys, + } + + impl $name_enc { + #[inline(always)] + pub(crate) fn get_enc_backend(&self) -> $name_back_enc<'_> { + $name_back_enc(self) + } + } + + impl BlockCipher for $name_enc {} + + impl KeySizeUser for $name_enc { + type KeySize = $key_size; + } + + impl KeyInit for $name_enc { + fn new(key: &Key) -> Self { + // SAFETY: we enforce that this code is called only when + // target features required by `expand` were properly checked. + Self { + round_keys: unsafe { $module::expand_key(key.as_ref()) }, + } + } + } + + impl BlockSizeUser for $name_enc { + type BlockSize = U16; + } + + impl BlockEncrypt for $name_enc { + fn encrypt_with_backend(&self, f: impl BlockClosure) { + f.call(&mut self.get_enc_backend()) + } + } + + impl fmt::Debug for $name_enc { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str(concat!(stringify!($name_enc), " { .. }")) + } + } + + impl AlgorithmName for $name_enc { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(stringify!($name_enc)) + } + } + + #[doc=$doc] + #[doc = "block cipher (decrypt-only)"] + #[derive(Clone)] + pub struct $name_dec { + round_keys: $module::RoundKeys, + } + + impl $name_dec { + #[inline(always)] + pub(crate) fn get_dec_backend(&self) -> $name_back_dec<'_> { + $name_back_dec(self) + } + } + + impl BlockCipher for $name_dec {} + + impl KeySizeUser for $name_dec { + type KeySize = $key_size; + } + + impl KeyInit for $name_dec { + fn new(key: &Key) -> Self { + $name_enc::new(key).into() + } + } + + impl From<$name_enc> for $name_dec { + #[inline] + fn from(enc: $name_enc) -> $name_dec { + Self::from(&enc) + } + } + + impl From<&$name_enc> for $name_dec { + #[inline] + fn from(enc: &$name_enc) -> $name_dec { + let round_keys = unsafe { $module::inv_expanded_keys(&enc.round_keys) }; + Self { round_keys } + } + } + + impl BlockSizeUser for $name_dec { + type BlockSize = U16; + } + + impl BlockDecrypt for $name_dec { + fn decrypt_with_backend(&self, f: impl BlockClosure) { + f.call(&mut self.get_dec_backend()); + } + } + + impl fmt::Debug for $name_dec { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str(concat!(stringify!($name_dec), " { .. }")) + } + } + + impl AlgorithmName for $name_dec { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(stringify!($name_dec)) + } + } + + pub(crate) struct $name_back_enc<'a>(&'a $name_enc); + + impl<'a> BlockSizeUser for $name_back_enc<'a> { + type BlockSize = U16; + } + + impl<'a> ParBlocksSizeUser for $name_back_enc<'a> { + type ParBlocksSize = U8; + } + + impl<'a> BlockBackend for $name_back_enc<'a> { + #[inline(always)] + fn proc_block(&mut self, block: InOut<'_, '_, Block>) { + unsafe { + $module::encrypt1(&self.0.round_keys, block); + } + } + + #[inline(always)] + fn proc_par_blocks(&mut self, blocks: InOut<'_, '_, Block8>) { + unsafe { + $module::encrypt8(&self.0.round_keys, blocks); + } + } + } + + pub(crate) struct $name_back_dec<'a>(&'a $name_dec); + + impl<'a> BlockSizeUser for $name_back_dec<'a> { + type BlockSize = U16; + } + + impl<'a> ParBlocksSizeUser for $name_back_dec<'a> { + type ParBlocksSize = U8; + } + + impl<'a> BlockBackend for $name_back_dec<'a> { + #[inline(always)] + fn proc_block(&mut self, block: InOut<'_, '_, Block>) { + unsafe { + $module::decrypt1(&self.0.round_keys, block); + } + } + + #[inline(always)] + fn proc_par_blocks(&mut self, blocks: InOut<'_, '_, Block8>) { + unsafe { + $module::decrypt8(&self.0.round_keys, blocks); + } + } + } + }; +} + +define_aes_impl!( + Aes128, + Aes128Enc, + Aes128Dec, + Aes128BackEnc, + Aes128BackDec, + aes128, + U16, + "AES-128", +); + +define_aes_impl!( + Aes192, + Aes192Enc, + Aes192Dec, + Aes192BackEnc, + Aes192BackDec, + aes192, + U24, + "AES-192", +); -#[cfg(feature = "ctr")] -pub use self::ctr::{Aes128Ctr, Aes192Ctr, Aes256Ctr}; +define_aes_impl!( + Aes256, + Aes256Enc, + Aes256Dec, + Aes256BackEnc, + Aes256BackDec, + aes256, + U32, + "AES-256", +); diff --git a/aes/src/ni/aes128.rs b/aes/src/ni/aes128.rs index f079fdd1..b0836a16 100644 --- a/aes/src/ni/aes128.rs +++ b/aes/src/ni/aes128.rs @@ -1,163 +1,145 @@ -use super::{ - arch::*, - utils::{aesdec8, aesdeclast8, aesenc8, aesenclast8, load8, store8, xor8, U128x8}, -}; -use crate::{Block, ParBlocks}; -use cipher::{ - consts::{U16, U8}, - generic_array::GenericArray, - BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher, -}; - -mod expand; -#[cfg(test)] -mod test_expand; +use super::{arch::*, utils::*}; +use crate::{Block, Block8}; +use cipher::inout::InOut; +use core::mem; /// AES-128 round keys -type RoundKeys = [__m128i; 11]; - -/// AES-128 block cipher -#[derive(Clone)] -pub struct Aes128 { - encrypt_keys: RoundKeys, - decrypt_keys: RoundKeys, +pub(super) type RoundKeys = [__m128i; 11]; + +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn encrypt1(keys: &RoundKeys, block: InOut<'_, '_, Block>) { + let (in_ptr, out_ptr) = block.into_raw(); + let mut b = _mm_loadu_si128(in_ptr as *const __m128i); + b = _mm_xor_si128(b, keys[0]); + b = _mm_aesenc_si128(b, keys[1]); + b = _mm_aesenc_si128(b, keys[2]); + b = _mm_aesenc_si128(b, keys[3]); + b = _mm_aesenc_si128(b, keys[4]); + b = _mm_aesenc_si128(b, keys[5]); + b = _mm_aesenc_si128(b, keys[6]); + b = _mm_aesenc_si128(b, keys[7]); + b = _mm_aesenc_si128(b, keys[8]); + b = _mm_aesenc_si128(b, keys[9]); + b = _mm_aesenclast_si128(b, keys[10]); + _mm_storeu_si128(out_ptr as *mut __m128i, b); } -impl Aes128 { - #[inline(always)] - pub(crate) fn encrypt8(&self, mut blocks: U128x8) -> U128x8 { - #[inline] - #[target_feature(enable = "aes")] - unsafe fn aesni128_encrypt8(keys: &RoundKeys, blocks: &mut U128x8) { - xor8(blocks, keys[0]); - aesenc8(blocks, keys[1]); - aesenc8(blocks, keys[2]); - aesenc8(blocks, keys[3]); - aesenc8(blocks, keys[4]); - aesenc8(blocks, keys[5]); - aesenc8(blocks, keys[6]); - aesenc8(blocks, keys[7]); - aesenc8(blocks, keys[8]); - aesenc8(blocks, keys[9]); - aesenclast8(blocks, keys[10]); - } - unsafe { aesni128_encrypt8(&self.encrypt_keys, &mut blocks) }; - blocks - } - - #[inline(always)] - pub(crate) fn encrypt(&self, block: __m128i) -> __m128i { - #[inline] - #[target_feature(enable = "aes")] - unsafe fn aesni128_encrypt1(keys: &RoundKeys, mut block: __m128i) -> __m128i { - block = _mm_xor_si128(block, keys[0]); - block = _mm_aesenc_si128(block, keys[1]); - block = _mm_aesenc_si128(block, keys[2]); - block = _mm_aesenc_si128(block, keys[3]); - block = _mm_aesenc_si128(block, keys[4]); - block = _mm_aesenc_si128(block, keys[5]); - block = _mm_aesenc_si128(block, keys[6]); - block = _mm_aesenc_si128(block, keys[7]); - block = _mm_aesenc_si128(block, keys[8]); - block = _mm_aesenc_si128(block, keys[9]); - _mm_aesenclast_si128(block, keys[10]) - } - unsafe { aesni128_encrypt1(&self.encrypt_keys, block) } - } +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn encrypt8(keys: &RoundKeys, blocks: InOut<'_, '_, Block8>) { + let (in_ptr, out_ptr) = blocks.into_raw(); + let mut b = load8(in_ptr); + xor8(&mut b, keys[0]); + aesenc8(&mut b, keys[1]); + aesenc8(&mut b, keys[2]); + aesenc8(&mut b, keys[3]); + aesenc8(&mut b, keys[4]); + aesenc8(&mut b, keys[5]); + aesenc8(&mut b, keys[6]); + aesenc8(&mut b, keys[7]); + aesenc8(&mut b, keys[8]); + aesenc8(&mut b, keys[9]); + aesenclast8(&mut b, keys[10]); + store8(out_ptr, b); } -impl NewBlockCipher for Aes128 { - type KeySize = U16; - - #[inline] - fn new(key: &GenericArray) -> Self { - let key = unsafe { &*(key as *const _ as *const [u8; 16]) }; - - let (encrypt_keys, decrypt_keys) = expand::expand(key); - - Self { - encrypt_keys, - decrypt_keys, - } - } +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn decrypt1(keys: &RoundKeys, block: InOut<'_, '_, Block>) { + let (in_ptr, out_ptr) = block.into_raw(); + let mut b = _mm_loadu_si128(in_ptr as *const __m128i); + b = _mm_xor_si128(b, keys[10]); + b = _mm_aesdec_si128(b, keys[9]); + b = _mm_aesdec_si128(b, keys[8]); + b = _mm_aesdec_si128(b, keys[7]); + b = _mm_aesdec_si128(b, keys[6]); + b = _mm_aesdec_si128(b, keys[5]); + b = _mm_aesdec_si128(b, keys[4]); + b = _mm_aesdec_si128(b, keys[3]); + b = _mm_aesdec_si128(b, keys[2]); + b = _mm_aesdec_si128(b, keys[1]); + b = _mm_aesdeclast_si128(b, keys[0]); + _mm_storeu_si128(out_ptr as *mut __m128i, b); } -impl BlockCipher for Aes128 { - type BlockSize = U16; - type ParBlocks = U8; +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn decrypt8(keys: &RoundKeys, blocks: InOut<'_, '_, Block8>) { + let (in_ptr, out_ptr) = blocks.into_raw(); + let mut b = load8(in_ptr); + xor8(&mut b, keys[10]); + aesdec8(&mut b, keys[9]); + aesdec8(&mut b, keys[8]); + aesdec8(&mut b, keys[7]); + aesdec8(&mut b, keys[6]); + aesdec8(&mut b, keys[5]); + aesdec8(&mut b, keys[4]); + aesdec8(&mut b, keys[3]); + aesdec8(&mut b, keys[2]); + aesdec8(&mut b, keys[1]); + aesdeclast8(&mut b, keys[0]); + store8(out_ptr, b); } -impl BlockEncrypt for Aes128 { - #[inline] - fn encrypt_block(&self, block: &mut Block) { - // Safety: `loadu` and `storeu` support unaligned access - #[allow(clippy::cast_ptr_alignment)] - unsafe { - let b = _mm_loadu_si128(block.as_ptr() as *const __m128i); - let b = self.encrypt(b); - _mm_storeu_si128(block.as_mut_ptr() as *mut __m128i, b); - } - } - - #[inline] - fn encrypt_par_blocks(&self, blocks: &mut ParBlocks) { - let b = self.encrypt8(load8(blocks)); - store8(blocks, b); - } +macro_rules! expand_round { + ($keys:expr, $pos:expr, $round:expr) => { + let mut t1 = $keys[$pos - 1]; + let mut t2; + let mut t3; + + t2 = _mm_aeskeygenassist_si128(t1, $round); + t2 = _mm_shuffle_epi32(t2, 0xff); + t3 = _mm_slli_si128(t1, 0x4); + t1 = _mm_xor_si128(t1, t3); + t3 = _mm_slli_si128(t3, 0x4); + t1 = _mm_xor_si128(t1, t3); + t3 = _mm_slli_si128(t3, 0x4); + t1 = _mm_xor_si128(t1, t3); + t1 = _mm_xor_si128(t1, t2); + + $keys[$pos] = t1; + }; } -impl BlockDecrypt for Aes128 { - #[inline] - fn decrypt_block(&self, block: &mut Block) { - #[inline] - #[target_feature(enable = "aes")] - unsafe fn aes128_decrypt1(block: &mut Block, keys: &RoundKeys) { - // Safety: `loadu` and `storeu` support unaligned access - #[allow(clippy::cast_ptr_alignment)] - let mut b = _mm_loadu_si128(block.as_ptr() as *const __m128i); - - b = _mm_xor_si128(b, keys[10]); - b = _mm_aesdec_si128(b, keys[9]); - b = _mm_aesdec_si128(b, keys[8]); - b = _mm_aesdec_si128(b, keys[7]); - b = _mm_aesdec_si128(b, keys[6]); - b = _mm_aesdec_si128(b, keys[5]); - b = _mm_aesdec_si128(b, keys[4]); - b = _mm_aesdec_si128(b, keys[3]); - b = _mm_aesdec_si128(b, keys[2]); - b = _mm_aesdec_si128(b, keys[1]); - b = _mm_aesdeclast_si128(b, keys[0]); - - // Safety: `loadu` and `storeu` support unaligned access - #[allow(clippy::cast_ptr_alignment)] - _mm_storeu_si128(block.as_mut_ptr() as *mut __m128i, b); - } - - unsafe { aes128_decrypt1(block, &self.decrypt_keys) } - } - - #[inline] - fn decrypt_par_blocks(&self, blocks: &mut ParBlocks) { - #[inline] - #[target_feature(enable = "aes")] - unsafe fn aes128_decrypt8(blocks: &mut ParBlocks, keys: &RoundKeys) { - let mut b = load8(blocks); - xor8(&mut b, keys[10]); - aesdec8(&mut b, keys[9]); - aesdec8(&mut b, keys[8]); - aesdec8(&mut b, keys[7]); - aesdec8(&mut b, keys[6]); - aesdec8(&mut b, keys[5]); - aesdec8(&mut b, keys[4]); - aesdec8(&mut b, keys[3]); - aesdec8(&mut b, keys[2]); - aesdec8(&mut b, keys[1]); - aesdeclast8(&mut b, keys[0]); - store8(blocks, b); - } - - unsafe { aes128_decrypt8(blocks, &self.decrypt_keys) } - } +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn expand_key(key: &[u8; 16]) -> RoundKeys { + // SAFETY: `RoundKeys` is a `[__m128i; 11]` which can be initialized + // with all zeroes. + let mut keys: RoundKeys = mem::zeroed(); + + let k = _mm_loadu_si128(key.as_ptr() as *const __m128i); + keys[0] = k; + + expand_round!(keys, 1, 0x01); + expand_round!(keys, 2, 0x02); + expand_round!(keys, 3, 0x04); + expand_round!(keys, 4, 0x08); + expand_round!(keys, 5, 0x10); + expand_round!(keys, 6, 0x20); + expand_round!(keys, 7, 0x40); + expand_round!(keys, 8, 0x80); + expand_round!(keys, 9, 0x1B); + expand_round!(keys, 10, 0x36); + + keys } -opaque_debug::implement!(Aes128); +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn inv_expanded_keys(keys: &RoundKeys) -> RoundKeys { + [ + keys[0], + _mm_aesimc_si128(keys[1]), + _mm_aesimc_si128(keys[2]), + _mm_aesimc_si128(keys[3]), + _mm_aesimc_si128(keys[4]), + _mm_aesimc_si128(keys[5]), + _mm_aesimc_si128(keys[6]), + _mm_aesimc_si128(keys[7]), + _mm_aesimc_si128(keys[8]), + _mm_aesimc_si128(keys[9]), + keys[10], + ] +} diff --git a/aes/src/ni/aes128/expand.rs b/aes/src/ni/aes128/expand.rs deleted file mode 100644 index f7b65b66..00000000 --- a/aes/src/ni/aes128/expand.rs +++ /dev/null @@ -1,53 +0,0 @@ -use super::RoundKeys; -use crate::ni::arch::*; - -use core::mem; - -macro_rules! expand_round { - ($enc_keys:expr, $dec_keys:expr, $pos:expr, $round:expr) => { - let mut t1 = $enc_keys[$pos - 1]; - let mut t2; - let mut t3; - - t2 = _mm_aeskeygenassist_si128(t1, $round); - t2 = _mm_shuffle_epi32(t2, 0xff); - t3 = _mm_slli_si128(t1, 0x4); - t1 = _mm_xor_si128(t1, t3); - t3 = _mm_slli_si128(t3, 0x4); - t1 = _mm_xor_si128(t1, t3); - t3 = _mm_slli_si128(t3, 0x4); - t1 = _mm_xor_si128(t1, t3); - t1 = _mm_xor_si128(t1, t2); - - $enc_keys[$pos] = t1; - let t1 = if $pos != 10 { _mm_aesimc_si128(t1) } else { t1 }; - $dec_keys[$pos] = t1; - }; -} - -#[inline(always)] -pub(super) fn expand(key: &[u8; 16]) -> (RoundKeys, RoundKeys) { - unsafe { - let mut enc_keys: RoundKeys = mem::zeroed(); - let mut dec_keys: RoundKeys = mem::zeroed(); - - // Safety: `loadu` supports unaligned loads - #[allow(clippy::cast_ptr_alignment)] - let k = _mm_loadu_si128(key.as_ptr() as *const __m128i); - enc_keys[0] = k; - dec_keys[0] = k; - - expand_round!(enc_keys, dec_keys, 1, 0x01); - expand_round!(enc_keys, dec_keys, 2, 0x02); - expand_round!(enc_keys, dec_keys, 3, 0x04); - expand_round!(enc_keys, dec_keys, 4, 0x08); - expand_round!(enc_keys, dec_keys, 5, 0x10); - expand_round!(enc_keys, dec_keys, 6, 0x20); - expand_round!(enc_keys, dec_keys, 7, 0x40); - expand_round!(enc_keys, dec_keys, 8, 0x80); - expand_round!(enc_keys, dec_keys, 9, 0x1B); - expand_round!(enc_keys, dec_keys, 10, 0x36); - - (enc_keys, dec_keys) - } -} diff --git a/aes/src/ni/aes128/test_expand.rs b/aes/src/ni/aes128/test_expand.rs deleted file mode 100644 index 38744e65..00000000 --- a/aes/src/ni/aes128/test_expand.rs +++ /dev/null @@ -1,107 +0,0 @@ -use super::expand::expand; -use crate::ni::utils::check; - -#[test] -fn test() { - let enc_keys = expand(&[0x00; 16]).0; - check( - &enc_keys, - &[ - [0x0000000000000000, 0x0000000000000000], - [0x6263636362636363, 0x6263636362636363], - [0x9b9898c9f9fbfbaa, 0x9b9898c9f9fbfbaa], - [0x90973450696ccffa, 0xf2f457330b0fac99], - [0xee06da7b876a1581, 0x759e42b27e91ee2b], - [0x7f2e2b88f8443e09, 0x8dda7cbbf34b9290], - [0xec614b851425758c, 0x99ff09376ab49ba7], - [0x217517873550620b, 0xacaf6b3cc61bf09b], - [0x0ef903333ba96138, 0x97060a04511dfa9f], - [0xb1d4d8e28a7db9da, 0x1d7bb3de4c664941], - [0xb4ef5bcb3e92e211, 0x23e951cf6f8f188e], - ], - ); - - let enc_keys = expand(&[0xff; 16]).0; - check( - &enc_keys, - &[ - [0xffffffffffffffff, 0xffffffffffffffff], - [0xe8e9e9e917161616, 0xe8e9e9e917161616], - [0xadaeae19bab8b80f, 0x525151e6454747f0], - [0x090e2277b3b69a78, 0xe1e7cb9ea4a08c6e], - [0xe16abd3e52dc2746, 0xb33becd8179b60b6], - [0xe5baf3ceb766d488, 0x045d385013c658e6], - [0x71d07db3c6b6a93b, 0xc2eb916bd12dc98d], - [0xe90d208d2fbb89b6, 0xed5018dd3c7dd150], - [0x96337366b988fad0, 0x54d8e20d68a5335d], - [0x8bf03f233278c5f3, 0x66a027fe0e0514a3], - [0xd60a3588e472f07b, 0x82d2d7858cd7c326], - ], - ); - - let enc_keys = expand(&[ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x0f, - ]) - .0; - check( - &enc_keys, - &[ - [0x0001020304050607, 0x08090a0b0c0d0e0f], - [0xd6aa74fdd2af72fa, 0xdaa678f1d6ab76fe], - [0xb692cf0b643dbdf1, 0xbe9bc5006830b3fe], - [0xb6ff744ed2c2c9bf, 0x6c590cbf0469bf41], - [0x47f7f7bc95353e03, 0xf96c32bcfd058dfd], - [0x3caaa3e8a99f9deb, 0x50f3af57adf622aa], - [0x5e390f7df7a69296, 0xa7553dc10aa31f6b], - [0x14f9701ae35fe28c, 0x440adf4d4ea9c026], - [0x47438735a41c65b9, 0xe016baf4aebf7ad2], - [0x549932d1f0855768, 0x1093ed9cbe2c974e], - [0x13111d7fe3944a17, 0xf307a78b4d2b30c5], - ], - ); - - let enc_keys = expand(&[ - 0x69, 0x20, 0xe2, 0x99, 0xa5, 0x20, 0x2a, 0x6d, 0x65, 0x6e, 0x63, 0x68, 0x69, 0x74, 0x6f, - 0x2a, - ]) - .0; - check( - &enc_keys, - &[ - [0x6920e299a5202a6d, 0x656e636869746f2a], - [0xfa8807605fa82d0d, 0x3ac64e6553b2214f], - [0xcf75838d90ddae80, 0xaa1be0e5f9a9c1aa], - [0x180d2f1488d08194, 0x22cb6171db62a0db], - [0xbaed96ad323d1739, 0x10f67648cb94d693], - [0x881b4ab2ba265d8b, 0xaad02bc36144fd50], - [0xb34f195d096944d6, 0xa3b96f15c2fd9245], - [0xa7007778ae6933ae, 0x0dd05cbbcf2dcefe], - [0xff8bccf251e2ff5c, 0x5c32a3e7931f6d19], - [0x24b7182e7555e772, 0x29674495ba78298c], - [0xae127cdadb479ba8, 0xf220df3d4858f6b1], - ], - ); - - let enc_keys = expand(&[ - 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, - 0x3c, - ]) - .0; - check( - &enc_keys, - &[ - [0x2b7e151628aed2a6, 0xabf7158809cf4f3c], - [0xa0fafe1788542cb1, 0x23a339392a6c7605], - [0xf2c295f27a96b943, 0x5935807a7359f67f], - [0x3d80477d4716fe3e, 0x1e237e446d7a883b], - [0xef44a541a8525b7f, 0xb671253bdb0bad00], - [0xd4d1c6f87c839d87, 0xcaf2b8bc11f915bc], - [0x6d88a37a110b3efd, 0xdbf98641ca0093fd], - [0x4e54f70e5f5fc9f3, 0x84a64fb24ea6dc4f], - [0xead27321b58dbad2, 0x312bf5607f8d292f], - [0xac7766f319fadc21, 0x28d12941575c006e], - [0xd014f9a8c9ee2589, 0xe13f0cc8b6630ca6], - ], - ); -} diff --git a/aes/src/ni/aes192.rs b/aes/src/ni/aes192.rs index fb642890..eee1f211 100644 --- a/aes/src/ni/aes192.rs +++ b/aes/src/ni/aes192.rs @@ -1,169 +1,197 @@ -use super::{ - arch::*, - utils::{aesdec8, aesdeclast8, aesenc8, aesenclast8, load8, store8, xor8, U128x8}, -}; -use crate::{Block, ParBlocks}; -use cipher::{ - consts::{U16, U24, U8}, - generic_array::GenericArray, - BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher, -}; - -mod expand; -#[cfg(test)] -mod test_expand; +use super::{arch::*, utils::*}; +use crate::{Block, Block8}; +use cipher::inout::InOut; +use core::{mem, ptr}; /// AES-192 round keys -type RoundKeys = [__m128i; 13]; +pub(super) type RoundKeys = [__m128i; 13]; + +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn encrypt1(keys: &RoundKeys, block: InOut<'_, '_, Block>) { + let (in_ptr, out_ptr) = block.into_raw(); + let mut b = _mm_loadu_si128(in_ptr as *const __m128i); + b = _mm_xor_si128(b, keys[0]); + b = _mm_aesenc_si128(b, keys[1]); + b = _mm_aesenc_si128(b, keys[2]); + b = _mm_aesenc_si128(b, keys[3]); + b = _mm_aesenc_si128(b, keys[4]); + b = _mm_aesenc_si128(b, keys[5]); + b = _mm_aesenc_si128(b, keys[6]); + b = _mm_aesenc_si128(b, keys[7]); + b = _mm_aesenc_si128(b, keys[8]); + b = _mm_aesenc_si128(b, keys[9]); + b = _mm_aesenc_si128(b, keys[10]); + b = _mm_aesenc_si128(b, keys[11]); + b = _mm_aesenclast_si128(b, keys[12]); + _mm_storeu_si128(out_ptr as *mut __m128i, b); +} -/// AES-192 block cipher -#[derive(Clone)] -pub struct Aes192 { - encrypt_keys: RoundKeys, - decrypt_keys: RoundKeys, +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn encrypt8(keys: &RoundKeys, blocks: InOut<'_, '_, Block8>) { + let (in_ptr, out_ptr) = blocks.into_raw(); + let mut b = load8(in_ptr); + xor8(&mut b, keys[0]); + aesenc8(&mut b, keys[1]); + aesenc8(&mut b, keys[2]); + aesenc8(&mut b, keys[3]); + aesenc8(&mut b, keys[4]); + aesenc8(&mut b, keys[5]); + aesenc8(&mut b, keys[6]); + aesenc8(&mut b, keys[7]); + aesenc8(&mut b, keys[8]); + aesenc8(&mut b, keys[9]); + aesenc8(&mut b, keys[10]); + aesenc8(&mut b, keys[11]); + aesenclast8(&mut b, keys[12]); + store8(out_ptr, b); } -impl Aes192 { - #[inline(always)] - pub(crate) fn encrypt8(&self, mut blocks: U128x8) -> U128x8 { - #[inline] - #[target_feature(enable = "aes")] - unsafe fn aesni192_encrypt8(keys: &RoundKeys, blocks: &mut U128x8) { - xor8(blocks, keys[0]); - aesenc8(blocks, keys[1]); - aesenc8(blocks, keys[2]); - aesenc8(blocks, keys[3]); - aesenc8(blocks, keys[4]); - aesenc8(blocks, keys[5]); - aesenc8(blocks, keys[6]); - aesenc8(blocks, keys[7]); - aesenc8(blocks, keys[8]); - aesenc8(blocks, keys[9]); - aesenc8(blocks, keys[10]); - aesenc8(blocks, keys[11]); - aesenclast8(blocks, keys[12]); - } - unsafe { aesni192_encrypt8(&self.encrypt_keys, &mut blocks) }; - blocks - } - - #[inline(always)] - pub(crate) fn encrypt(&self, block: __m128i) -> __m128i { - #[inline] - #[target_feature(enable = "aes")] - unsafe fn aesni192_encrypt1(keys: &RoundKeys, mut block: __m128i) -> __m128i { - block = _mm_xor_si128(block, keys[0]); - block = _mm_aesenc_si128(block, keys[1]); - block = _mm_aesenc_si128(block, keys[2]); - block = _mm_aesenc_si128(block, keys[3]); - block = _mm_aesenc_si128(block, keys[4]); - block = _mm_aesenc_si128(block, keys[5]); - block = _mm_aesenc_si128(block, keys[6]); - block = _mm_aesenc_si128(block, keys[7]); - block = _mm_aesenc_si128(block, keys[8]); - block = _mm_aesenc_si128(block, keys[9]); - block = _mm_aesenc_si128(block, keys[10]); - block = _mm_aesenc_si128(block, keys[11]); - _mm_aesenclast_si128(block, keys[12]) - } - unsafe { aesni192_encrypt1(&self.encrypt_keys, block) } - } +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn decrypt1(keys: &RoundKeys, block: InOut<'_, '_, Block>) { + let (in_ptr, out_ptr) = block.into_raw(); + let mut b = _mm_loadu_si128(in_ptr as *const __m128i); + b = _mm_xor_si128(b, keys[12]); + b = _mm_aesdec_si128(b, keys[11]); + b = _mm_aesdec_si128(b, keys[10]); + b = _mm_aesdec_si128(b, keys[9]); + b = _mm_aesdec_si128(b, keys[8]); + b = _mm_aesdec_si128(b, keys[7]); + b = _mm_aesdec_si128(b, keys[6]); + b = _mm_aesdec_si128(b, keys[5]); + b = _mm_aesdec_si128(b, keys[4]); + b = _mm_aesdec_si128(b, keys[3]); + b = _mm_aesdec_si128(b, keys[2]); + b = _mm_aesdec_si128(b, keys[1]); + b = _mm_aesdeclast_si128(b, keys[0]); + _mm_storeu_si128(out_ptr as *mut __m128i, b); } -impl NewBlockCipher for Aes192 { - type KeySize = U24; - - #[inline] - fn new(key: &GenericArray) -> Self { - let key = unsafe { &*(key as *const _ as *const [u8; 24]) }; - let (encrypt_keys, decrypt_keys) = expand::expand(key); - Self { - encrypt_keys, - decrypt_keys, - } - } +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn decrypt8(keys: &RoundKeys, blocks: InOut<'_, '_, Block8>) { + let (in_ptr, out_ptr) = blocks.into_raw(); + let mut b = load8(in_ptr); + xor8(&mut b, keys[12]); + aesdec8(&mut b, keys[11]); + aesdec8(&mut b, keys[10]); + aesdec8(&mut b, keys[9]); + aesdec8(&mut b, keys[8]); + aesdec8(&mut b, keys[7]); + aesdec8(&mut b, keys[6]); + aesdec8(&mut b, keys[5]); + aesdec8(&mut b, keys[4]); + aesdec8(&mut b, keys[3]); + aesdec8(&mut b, keys[2]); + aesdec8(&mut b, keys[1]); + aesdeclast8(&mut b, keys[0]); + store8(out_ptr, b); } -impl BlockCipher for Aes192 { - type BlockSize = U16; - type ParBlocks = U8; +macro_rules! expand_round { + ($t1:expr, $t3:expr, $round:expr) => {{ + let mut t1 = $t1; + let mut t2; + let mut t3 = $t3; + let mut t4; + + t2 = _mm_aeskeygenassist_si128(t3, $round); + t2 = _mm_shuffle_epi32(t2, 0x55); + t4 = _mm_slli_si128(t1, 0x4); + t1 = _mm_xor_si128(t1, t4); + t4 = _mm_slli_si128(t4, 0x4); + t1 = _mm_xor_si128(t1, t4); + t4 = _mm_slli_si128(t4, 0x4); + t1 = _mm_xor_si128(t1, t4); + t1 = _mm_xor_si128(t1, t2); + t2 = _mm_shuffle_epi32(t1, 0xff); + t4 = _mm_slli_si128(t3, 0x4); + t3 = _mm_xor_si128(t3, t4); + t3 = _mm_xor_si128(t3, t2); + + (t1, t3) + }}; } -impl BlockEncrypt for Aes192 { - #[inline] - fn encrypt_block(&self, block: &mut Block) { - // Safety: `loadu` and `storeu` support unaligned access - #[allow(clippy::cast_ptr_alignment)] - unsafe { - let b = _mm_loadu_si128(block.as_ptr() as *const __m128i); - let b = self.encrypt(b); - _mm_storeu_si128(block.as_mut_ptr() as *mut __m128i, b); - } - } - - #[inline] - fn encrypt_par_blocks(&self, blocks: &mut ParBlocks) { - let b = self.encrypt8(load8(blocks)); - store8(blocks, b); - } +macro_rules! shuffle { + ($a:expr, $b:expr, $imm:expr) => { + mem::transmute::<_, __m128i>(_mm_shuffle_pd(mem::transmute($a), mem::transmute($b), $imm)) + }; } -impl BlockDecrypt for Aes192 { - #[inline] - fn decrypt_block(&self, block: &mut Block) { - #[inline] - #[target_feature(enable = "aes")] - unsafe fn aes192_decrypt1(block: &mut Block, keys: &RoundKeys) { - // Safety: `loadu` and `storeu` support unaligned access - #[allow(clippy::cast_ptr_alignment)] - let mut b = _mm_loadu_si128(block.as_ptr() as *const __m128i); - - b = _mm_xor_si128(b, keys[12]); - b = _mm_aesdec_si128(b, keys[11]); - b = _mm_aesdec_si128(b, keys[10]); - b = _mm_aesdec_si128(b, keys[9]); - b = _mm_aesdec_si128(b, keys[8]); - b = _mm_aesdec_si128(b, keys[7]); - b = _mm_aesdec_si128(b, keys[6]); - b = _mm_aesdec_si128(b, keys[5]); - b = _mm_aesdec_si128(b, keys[4]); - b = _mm_aesdec_si128(b, keys[3]); - b = _mm_aesdec_si128(b, keys[2]); - b = _mm_aesdec_si128(b, keys[1]); - b = _mm_aesdeclast_si128(b, keys[0]); - - // Safety: `loadu` and `storeu` support unaligned access - #[allow(clippy::cast_ptr_alignment)] - _mm_storeu_si128(block.as_mut_ptr() as *mut __m128i, b); - } - - unsafe { aes192_decrypt1(block, &self.decrypt_keys) } - } - - #[inline] - fn decrypt_par_blocks(&self, blocks: &mut ParBlocks) { - #[inline] - #[target_feature(enable = "aes")] - unsafe fn aes192_decrypt8(blocks: &mut ParBlocks, keys: &RoundKeys) { - let mut b = load8(blocks); - xor8(&mut b, keys[12]); - aesdec8(&mut b, keys[11]); - aesdec8(&mut b, keys[10]); - aesdec8(&mut b, keys[9]); - aesdec8(&mut b, keys[8]); - aesdec8(&mut b, keys[7]); - aesdec8(&mut b, keys[6]); - aesdec8(&mut b, keys[5]); - aesdec8(&mut b, keys[4]); - aesdec8(&mut b, keys[3]); - aesdec8(&mut b, keys[2]); - aesdec8(&mut b, keys[1]); - aesdeclast8(&mut b, keys[0]); - store8(blocks, b); - } - - unsafe { aes192_decrypt8(blocks, &self.decrypt_keys) } - } +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn expand_key(key: &[u8; 24]) -> RoundKeys { + // SAFETY: `RoundKeys` is a `[__m128i; 13]` which can be initialized + // with all zeroes. + let mut keys: RoundKeys = mem::zeroed(); + // we are being extra pedantic here to remove out-of-bound access. + // this should be optimized out into movups, movsd sequence + // note that unaligned load MUST be used here, even though we read + // from the array (compiler missoptimizes aligned load) + let (k0, k1l) = { + let mut t = [0u8; 32]; + ptr::write(t.as_mut_ptr() as *mut [u8; 24], *key); + + ( + _mm_loadu_si128(t.as_ptr() as *const __m128i), + _mm_loadu_si128(t.as_ptr().offset(16) as *const __m128i), + ) + }; + + keys[0] = k0; + + let (k1_2, k2r) = expand_round!(k0, k1l, 0x01); + keys[1] = shuffle!(k1l, k1_2, 0); + keys[2] = shuffle!(k1_2, k2r, 1); + + let (k3, k4l) = expand_round!(k1_2, k2r, 0x02); + keys[3] = k3; + + let (k4_5, k5r) = expand_round!(k3, k4l, 0x04); + let k4 = shuffle!(k4l, k4_5, 0); + let k5 = shuffle!(k4_5, k5r, 1); + keys[4] = k4; + keys[5] = k5; + + let (k6, k7l) = expand_round!(k4_5, k5r, 0x08); + keys[6] = k6; + + let (k7_8, k8r) = expand_round!(k6, k7l, 0x10); + keys[7] = shuffle!(k7l, k7_8, 0); + keys[8] = shuffle!(k7_8, k8r, 1); + + let (k9, k10l) = expand_round!(k7_8, k8r, 0x20); + keys[9] = k9; + + let (k10_11, k11r) = expand_round!(k9, k10l, 0x40); + keys[10] = shuffle!(k10l, k10_11, 0); + keys[11] = shuffle!(k10_11, k11r, 1); + + let (k12, _) = expand_round!(k10_11, k11r, 0x80); + keys[12] = k12; + + keys } -opaque_debug::implement!(Aes192); +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn inv_expanded_keys(keys: &RoundKeys) -> RoundKeys { + [ + keys[0], + _mm_aesimc_si128(keys[1]), + _mm_aesimc_si128(keys[2]), + _mm_aesimc_si128(keys[3]), + _mm_aesimc_si128(keys[4]), + _mm_aesimc_si128(keys[5]), + _mm_aesimc_si128(keys[6]), + _mm_aesimc_si128(keys[7]), + _mm_aesimc_si128(keys[8]), + _mm_aesimc_si128(keys[9]), + _mm_aesimc_si128(keys[10]), + _mm_aesimc_si128(keys[11]), + keys[12], + ] +} diff --git a/aes/src/ni/aes192/expand.rs b/aes/src/ni/aes192/expand.rs deleted file mode 100644 index 20f9af21..00000000 --- a/aes/src/ni/aes192/expand.rs +++ /dev/null @@ -1,110 +0,0 @@ -use super::RoundKeys; -use crate::ni::arch::*; - -use core::{mem, ptr}; - -macro_rules! expand_round { - ($t1:expr, $t3:expr, $round:expr) => {{ - let mut t1 = $t1; - let mut t2; - let mut t3 = $t3; - let mut t4; - - t2 = _mm_aeskeygenassist_si128(t3, $round); - t2 = _mm_shuffle_epi32(t2, 0x55); - t4 = _mm_slli_si128(t1, 0x4); - t1 = _mm_xor_si128(t1, t4); - t4 = _mm_slli_si128(t4, 0x4); - t1 = _mm_xor_si128(t1, t4); - t4 = _mm_slli_si128(t4, 0x4); - t1 = _mm_xor_si128(t1, t4); - t1 = _mm_xor_si128(t1, t2); - t2 = _mm_shuffle_epi32(t1, 0xff); - t4 = _mm_slli_si128(t3, 0x4); - t3 = _mm_xor_si128(t3, t4); - t3 = _mm_xor_si128(t3, t2); - - (t1, t3) - }}; -} - -macro_rules! shuffle { - ($a:expr, $b:expr, $imm:expr) => { - mem::transmute::<_, __m128i>(_mm_shuffle_pd(mem::transmute($a), mem::transmute($b), $imm)) - }; -} - -#[inline(always)] -pub(super) fn expand(key: &[u8; 24]) -> (RoundKeys, RoundKeys) { - unsafe { - // SAFETY: `RoundKeys` is a `[__m128i; 13]` which can be initialized - // with all zeroes. - let mut enc_keys: RoundKeys = mem::zeroed(); - let mut dec_keys: RoundKeys = mem::zeroed(); - - macro_rules! store { - ($i:expr, $k:expr) => { - enc_keys[$i] = $k; - dec_keys[$i] = _mm_aesimc_si128($k); - }; - } - - // we are being extra pedantic here to remove out-of-bound access. - // this should be optimized out into movups, movsd sequence - // note that unaligned load MUST be used here, even though we read - // from the array (compiler missoptimizes aligned load) - let (k0, k1l) = { - let mut t = [0u8; 32]; - ptr::write(t.as_mut_ptr() as *mut [u8; 24], *key); - - // Safety: `loadu` supports unaligned loads - #[allow(clippy::cast_ptr_alignment)] - ( - _mm_loadu_si128(t.as_ptr() as *const __m128i), - _mm_loadu_si128(t.as_ptr().offset(16) as *const __m128i), - ) - }; - - enc_keys[0] = k0; - dec_keys[0] = k0; - - let (k1_2, k2r) = expand_round!(k0, k1l, 0x01); - let k1 = shuffle!(k1l, k1_2, 0); - let k2 = shuffle!(k1_2, k2r, 1); - store!(1, k1); - store!(2, k2); - - let (k3, k4l) = expand_round!(k1_2, k2r, 0x02); - store!(3, k3); - - let (k4_5, k5r) = expand_round!(k3, k4l, 0x04); - let k4 = shuffle!(k4l, k4_5, 0); - let k5 = shuffle!(k4_5, k5r, 1); - store!(4, k4); - store!(5, k5); - - let (k6, k7l) = expand_round!(k4_5, k5r, 0x08); - store!(6, k6); - - let (k7_8, k8r) = expand_round!(k6, k7l, 0x10); - let k7 = shuffle!(k7l, k7_8, 0); - let k8 = shuffle!(k7_8, k8r, 1); - store!(7, k7); - store!(8, k8); - - let (k9, k10l) = expand_round!(k7_8, k8r, 0x20); - store!(9, k9); - - let (k10_11, k11r) = expand_round!(k9, k10l, 0x40); - let k10 = shuffle!(k10l, k10_11, 0); - let k11 = shuffle!(k10_11, k11r, 1); - store!(10, k10); - store!(11, k11); - - let (k12, _) = expand_round!(k10_11, k11r, 0x80); - enc_keys[12] = k12; - dec_keys[12] = k12; - - (enc_keys, dec_keys) - } -} diff --git a/aes/src/ni/aes192/test_expand.rs b/aes/src/ni/aes192/test_expand.rs deleted file mode 100644 index 7811d4c8..00000000 --- a/aes/src/ni/aes192/test_expand.rs +++ /dev/null @@ -1,93 +0,0 @@ -use super::expand::expand; -use crate::ni::utils::check; - -#[test] -fn test() { - let enc_keys = expand(&[0x00; 24]).0; - check( - &enc_keys, - &[ - [0x0000000000000000, 0x0000000000000000], - [0x0000000000000000, 0x6263636362636363], - [0x6263636362636363, 0x6263636362636363], - [0x9b9898c9f9fbfbaa, 0x9b9898c9f9fbfbaa], - [0x9b9898c9f9fbfbaa, 0x90973450696ccffa], - [0xf2f457330b0fac99, 0x90973450696ccffa], - [0xc81d19a9a171d653, 0x53858160588a2df9], - [0xc81d19a9a171d653, 0x7bebf49bda9a22c8], - [0x891fa3a8d1958e51, 0x198897f8b8f941ab], - [0xc26896f718f2b43f, 0x91ed1797407899c6], - [0x59f00e3ee1094f95, 0x83ecbc0f9b1e0830], - [0x0af31fa74a8b8661, 0x137b885ff272c7ca], - [0x432ac886d834c0b6, 0xd2c7df11984c5970], - ], - ); - - let enc_keys = expand(&[0xff; 24]).0; - check( - &enc_keys, - &[ - [0xffffffffffffffff, 0xffffffffffffffff], - [0xffffffffffffffff, 0xe8e9e9e917161616], - [0xe8e9e9e917161616, 0xe8e9e9e917161616], - [0xadaeae19bab8b80f, 0x525151e6454747f0], - [0xadaeae19bab8b80f, 0xc5c2d8ed7f7a60e2], - [0x2d2b3104686c76f4, 0xc5c2d8ed7f7a60e2], - [0x1712403f686820dd, 0x454311d92d2f672d], - [0xe8edbfc09797df22, 0x8f8cd3b7e7e4f36a], - [0xa2a7e2b38f88859e, 0x67653a5ef0f2e57c], - [0x2655c33bc1b13051, 0x6316d2e2ec9e577c], - [0x8bfb6d227b09885e, 0x67919b1aa620ab4b], - [0xc53679a929a82ed5, 0xa25343f7d95acba9], - [0x598e482fffaee364, 0x3a989acd1330b418], - ], - ); - - let enc_keys = expand(&[ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - ]) - .0; - check( - &enc_keys, - &[ - [0x0001020304050607, 0x08090a0b0c0d0e0f], - [0x1011121314151617, 0x5846f2f95c43f4fe], - [0x544afef55847f0fa, 0x4856e2e95c43f4fe], - [0x40f949b31cbabd4d, 0x48f043b810b7b342], - [0x58e151ab04a2a555, 0x7effb5416245080c], - [0x2ab54bb43a02f8f6, 0x62e3a95d66410c08], - [0xf501857297448d7e, 0xbdf1c6ca87f33e3c], - [0xe510976183519b69, 0x34157c9ea351f1e0], - [0x1ea0372a99530916, 0x7c439e77ff12051e], - [0xdd7e0e887e2fff68, 0x608fc842f9dcc154], - [0x859f5f237a8d5a3d, 0xc0c02952beefd63a], - [0xde601e7827bcdf2c, 0xa223800fd8aeda32], - [0xa4970a331a78dc09, 0xc418c271e3a41d5d], - ], - ); - - let enc_keys = expand(&[ - 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, - 0xe5, 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b, - ]) - .0; - check( - &enc_keys, - &[ - [0x8e73b0f7da0e6452, 0xc810f32b809079e5], - [0x62f8ead2522c6b7b, 0xfe0c91f72402f5a5], - [0xec12068e6c827f6b, 0x0e7a95b95c56fec2], - [0x4db7b4bd69b54118, 0x85a74796e92538fd], - [0xe75fad44bb095386, 0x485af05721efb14f], - [0xa448f6d94d6dce24, 0xaa326360113b30e6], - [0xa25e7ed583b1cf9a, 0x27f939436a94f767], - [0xc0a69407d19da4e1, 0xec1786eb6fa64971], - [0x485f703222cb8755, 0xe26d135233f0b7b3], - [0x40beeb282f18a259, 0x6747d26b458c553e], - [0xa7e1466c9411f1df, 0x821f750aad07d753], - [0xca4005388fcc5006, 0x282d166abc3ce7b5], - [0xe98ba06f448c773c, 0x8ecc720401002202], - ], - ); -} diff --git a/aes/src/ni/aes256.rs b/aes/src/ni/aes256.rs index 9a752c16..bea090ab 100644 --- a/aes/src/ni/aes256.rs +++ b/aes/src/ni/aes256.rs @@ -1,177 +1,196 @@ -use super::{ - arch::*, - utils::{aesdec8, aesdeclast8, aesenc8, aesenclast8, load8, store8, xor8, U128x8}, -}; -use crate::{Block, ParBlocks}; -use cipher::{ - consts::{U16, U32, U8}, - generic_array::GenericArray, - BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher, -}; - -mod expand; -#[cfg(test)] -mod test_expand; - -/// AES-256 round keys -type RoundKeys = [__m128i; 15]; - -/// AES-256 block cipher -#[derive(Clone)] -pub struct Aes256 { - encrypt_keys: RoundKeys, - decrypt_keys: RoundKeys, +use super::{arch::*, utils::*}; +use crate::{Block, Block8}; +use cipher::inout::InOut; +use core::mem; + +/// AES-192 round keys +pub(super) type RoundKeys = [__m128i; 15]; + +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn encrypt1(keys: &RoundKeys, block: InOut<'_, '_, Block>) { + let (in_ptr, out_ptr) = block.into_raw(); + let mut b = _mm_loadu_si128(in_ptr as *const __m128i); + b = _mm_xor_si128(b, keys[0]); + b = _mm_aesenc_si128(b, keys[1]); + b = _mm_aesenc_si128(b, keys[2]); + b = _mm_aesenc_si128(b, keys[3]); + b = _mm_aesenc_si128(b, keys[4]); + b = _mm_aesenc_si128(b, keys[5]); + b = _mm_aesenc_si128(b, keys[6]); + b = _mm_aesenc_si128(b, keys[7]); + b = _mm_aesenc_si128(b, keys[8]); + b = _mm_aesenc_si128(b, keys[9]); + b = _mm_aesenc_si128(b, keys[10]); + b = _mm_aesenc_si128(b, keys[11]); + b = _mm_aesenc_si128(b, keys[12]); + b = _mm_aesenc_si128(b, keys[13]); + b = _mm_aesenclast_si128(b, keys[14]); + _mm_storeu_si128(out_ptr as *mut __m128i, b); } -impl Aes256 { - #[inline(always)] - pub(crate) fn encrypt8(&self, mut blocks: U128x8) -> U128x8 { - #[inline] - #[target_feature(enable = "aes")] - unsafe fn aesni256_encrypt8(keys: &RoundKeys, blocks: &mut U128x8) { - xor8(blocks, keys[0]); - aesenc8(blocks, keys[1]); - aesenc8(blocks, keys[2]); - aesenc8(blocks, keys[3]); - aesenc8(blocks, keys[4]); - aesenc8(blocks, keys[5]); - aesenc8(blocks, keys[6]); - aesenc8(blocks, keys[7]); - aesenc8(blocks, keys[8]); - aesenc8(blocks, keys[9]); - aesenc8(blocks, keys[10]); - aesenc8(blocks, keys[11]); - aesenc8(blocks, keys[12]); - aesenc8(blocks, keys[13]); - aesenclast8(blocks, keys[14]); - } - unsafe { aesni256_encrypt8(&self.encrypt_keys, &mut blocks) }; - blocks - } - - #[inline(always)] - pub(crate) fn encrypt(&self, block: __m128i) -> __m128i { - #[inline] - #[target_feature(enable = "aes")] - unsafe fn aesni256_encrypt1(keys: &RoundKeys, mut block: __m128i) -> __m128i { - block = _mm_xor_si128(block, keys[0]); - block = _mm_aesenc_si128(block, keys[1]); - block = _mm_aesenc_si128(block, keys[2]); - block = _mm_aesenc_si128(block, keys[3]); - block = _mm_aesenc_si128(block, keys[4]); - block = _mm_aesenc_si128(block, keys[5]); - block = _mm_aesenc_si128(block, keys[6]); - block = _mm_aesenc_si128(block, keys[7]); - block = _mm_aesenc_si128(block, keys[8]); - block = _mm_aesenc_si128(block, keys[9]); - block = _mm_aesenc_si128(block, keys[10]); - block = _mm_aesenc_si128(block, keys[11]); - block = _mm_aesenc_si128(block, keys[12]); - block = _mm_aesenc_si128(block, keys[13]); - _mm_aesenclast_si128(block, keys[14]) - } - unsafe { aesni256_encrypt1(&self.encrypt_keys, block) } - } +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn encrypt8(keys: &RoundKeys, blocks: InOut<'_, '_, Block8>) { + let (in_ptr, out_ptr) = blocks.into_raw(); + let mut b = load8(in_ptr); + xor8(&mut b, keys[0]); + aesenc8(&mut b, keys[1]); + aesenc8(&mut b, keys[2]); + aesenc8(&mut b, keys[3]); + aesenc8(&mut b, keys[4]); + aesenc8(&mut b, keys[5]); + aesenc8(&mut b, keys[6]); + aesenc8(&mut b, keys[7]); + aesenc8(&mut b, keys[8]); + aesenc8(&mut b, keys[9]); + aesenc8(&mut b, keys[10]); + aesenc8(&mut b, keys[11]); + aesenc8(&mut b, keys[12]); + aesenc8(&mut b, keys[13]); + aesenclast8(&mut b, keys[14]); + store8(out_ptr, b); } -impl NewBlockCipher for Aes256 { - type KeySize = U32; - - #[inline] - fn new(key: &GenericArray) -> Self { - let key = unsafe { &*(key as *const _ as *const [u8; 32]) }; - let (encrypt_keys, decrypt_keys) = expand::expand(key); - Self { - encrypt_keys, - decrypt_keys, - } - } +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn decrypt1(keys: &RoundKeys, block: InOut<'_, '_, Block>) { + let (in_ptr, out_ptr) = block.into_raw(); + let mut b = _mm_loadu_si128(in_ptr as *const __m128i); + b = _mm_xor_si128(b, keys[14]); + b = _mm_aesdec_si128(b, keys[13]); + b = _mm_aesdec_si128(b, keys[12]); + b = _mm_aesdec_si128(b, keys[11]); + b = _mm_aesdec_si128(b, keys[10]); + b = _mm_aesdec_si128(b, keys[9]); + b = _mm_aesdec_si128(b, keys[8]); + b = _mm_aesdec_si128(b, keys[7]); + b = _mm_aesdec_si128(b, keys[6]); + b = _mm_aesdec_si128(b, keys[5]); + b = _mm_aesdec_si128(b, keys[4]); + b = _mm_aesdec_si128(b, keys[3]); + b = _mm_aesdec_si128(b, keys[2]); + b = _mm_aesdec_si128(b, keys[1]); + b = _mm_aesdeclast_si128(b, keys[0]); + _mm_storeu_si128(out_ptr as *mut __m128i, b); } -impl BlockCipher for Aes256 { - type BlockSize = U16; - type ParBlocks = U8; +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn decrypt8(keys: &RoundKeys, blocks: InOut<'_, '_, Block8>) { + let (in_ptr, out_ptr) = blocks.into_raw(); + let mut b = load8(in_ptr); + xor8(&mut b, keys[14]); + aesdec8(&mut b, keys[13]); + aesdec8(&mut b, keys[12]); + aesdec8(&mut b, keys[11]); + aesdec8(&mut b, keys[10]); + aesdec8(&mut b, keys[9]); + aesdec8(&mut b, keys[8]); + aesdec8(&mut b, keys[7]); + aesdec8(&mut b, keys[6]); + aesdec8(&mut b, keys[5]); + aesdec8(&mut b, keys[4]); + aesdec8(&mut b, keys[3]); + aesdec8(&mut b, keys[2]); + aesdec8(&mut b, keys[1]); + aesdeclast8(&mut b, keys[0]); + store8(out_ptr, b); } -impl BlockEncrypt for Aes256 { - #[inline] - fn encrypt_block(&self, block: &mut Block) { - // Safety: `loadu` and `storeu` support unaligned access - #[allow(clippy::cast_ptr_alignment)] - unsafe { - let b = _mm_loadu_si128(block.as_ptr() as *const __m128i); - let b = self.encrypt(b); - _mm_storeu_si128(block.as_mut_ptr() as *mut __m128i, b); - } - } - - #[inline] - fn encrypt_par_blocks(&self, blocks: &mut ParBlocks) { - let b = self.encrypt8(load8(blocks)); - store8(blocks, b); - } +macro_rules! expand_round { + ($keys:expr, $pos:expr, $round:expr) => { + let mut t1 = $keys[$pos - 2]; + let mut t2; + let mut t3 = $keys[$pos - 1]; + let mut t4; + + t2 = _mm_aeskeygenassist_si128(t3, $round); + t2 = _mm_shuffle_epi32(t2, 0xff); + t4 = _mm_slli_si128(t1, 0x4); + t1 = _mm_xor_si128(t1, t4); + t4 = _mm_slli_si128(t4, 0x4); + t1 = _mm_xor_si128(t1, t4); + t4 = _mm_slli_si128(t4, 0x4); + t1 = _mm_xor_si128(t1, t4); + t1 = _mm_xor_si128(t1, t2); + + $keys[$pos] = t1; + + t4 = _mm_aeskeygenassist_si128(t1, 0x00); + t2 = _mm_shuffle_epi32(t4, 0xaa); + t4 = _mm_slli_si128(t3, 0x4); + t3 = _mm_xor_si128(t3, t4); + t4 = _mm_slli_si128(t4, 0x4); + t3 = _mm_xor_si128(t3, t4); + t4 = _mm_slli_si128(t4, 0x4); + t3 = _mm_xor_si128(t3, t4); + t3 = _mm_xor_si128(t3, t2); + + $keys[$pos + 1] = t3; + }; } -impl BlockDecrypt for Aes256 { - #[inline] - fn decrypt_block(&self, block: &mut Block) { - #[inline] - #[target_feature(enable = "aes")] - unsafe fn aes256_decrypt1(block: &mut Block, keys: &RoundKeys) { - // Safety: `loadu` and `storeu` support unaligned access - #[allow(clippy::cast_ptr_alignment)] - let mut b = _mm_loadu_si128(block.as_ptr() as *const __m128i); - - b = _mm_xor_si128(b, keys[14]); - b = _mm_aesdec_si128(b, keys[13]); - b = _mm_aesdec_si128(b, keys[12]); - b = _mm_aesdec_si128(b, keys[11]); - b = _mm_aesdec_si128(b, keys[10]); - b = _mm_aesdec_si128(b, keys[9]); - b = _mm_aesdec_si128(b, keys[8]); - b = _mm_aesdec_si128(b, keys[7]); - b = _mm_aesdec_si128(b, keys[6]); - b = _mm_aesdec_si128(b, keys[5]); - b = _mm_aesdec_si128(b, keys[4]); - b = _mm_aesdec_si128(b, keys[3]); - b = _mm_aesdec_si128(b, keys[2]); - b = _mm_aesdec_si128(b, keys[1]); - b = _mm_aesdeclast_si128(b, keys[0]); - - // Safety: `loadu` and `storeu` support unaligned access - #[allow(clippy::cast_ptr_alignment)] - _mm_storeu_si128(block.as_mut_ptr() as *mut __m128i, b); - } - - unsafe { aes256_decrypt1(block, &self.decrypt_keys) } - } - - #[inline] - fn decrypt_par_blocks(&self, blocks: &mut ParBlocks) { - #[inline] - #[target_feature(enable = "aes")] - unsafe fn aes256_decrypt8(blocks: &mut ParBlocks, keys: &RoundKeys) { - let mut b = load8(blocks); - xor8(&mut b, keys[14]); - aesdec8(&mut b, keys[13]); - aesdec8(&mut b, keys[12]); - aesdec8(&mut b, keys[11]); - aesdec8(&mut b, keys[10]); - aesdec8(&mut b, keys[9]); - aesdec8(&mut b, keys[8]); - aesdec8(&mut b, keys[7]); - aesdec8(&mut b, keys[6]); - aesdec8(&mut b, keys[5]); - aesdec8(&mut b, keys[4]); - aesdec8(&mut b, keys[3]); - aesdec8(&mut b, keys[2]); - aesdec8(&mut b, keys[1]); - aesdeclast8(&mut b, keys[0]); - store8(blocks, b); - } - - unsafe { aes256_decrypt8(blocks, &self.decrypt_keys) } - } +macro_rules! expand_round_last { + ($keys:expr, $pos:expr, $round:expr) => { + let mut t1 = $keys[$pos - 2]; + let mut t2; + let t3 = $keys[$pos - 1]; + let mut t4; + + t2 = _mm_aeskeygenassist_si128(t3, $round); + t2 = _mm_shuffle_epi32(t2, 0xff); + t4 = _mm_slli_si128(t1, 0x4); + t1 = _mm_xor_si128(t1, t4); + t4 = _mm_slli_si128(t4, 0x4); + t1 = _mm_xor_si128(t1, t4); + t4 = _mm_slli_si128(t4, 0x4); + t1 = _mm_xor_si128(t1, t4); + t1 = _mm_xor_si128(t1, t2); + + $keys[$pos] = t1; + }; } -opaque_debug::implement!(Aes256); +#[inline(always)] +pub(super) unsafe fn expand_key(key: &[u8; 32]) -> RoundKeys { + // SAFETY: `RoundKeys` is a `[__m128i; 15]` which can be initialized + // with all zeroes. + let mut keys: RoundKeys = mem::zeroed(); + + let kp = key.as_ptr() as *const __m128i; + keys[0] = _mm_loadu_si128(kp); + keys[1] = _mm_loadu_si128(kp.add(1)); + + expand_round!(keys, 2, 0x01); + expand_round!(keys, 4, 0x02); + expand_round!(keys, 6, 0x04); + expand_round!(keys, 8, 0x08); + expand_round!(keys, 10, 0x10); + expand_round!(keys, 12, 0x20); + expand_round_last!(keys, 14, 0x40); + + keys +} + +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn inv_expanded_keys(keys: &RoundKeys) -> RoundKeys { + [ + keys[0], + _mm_aesimc_si128(keys[1]), + _mm_aesimc_si128(keys[2]), + _mm_aesimc_si128(keys[3]), + _mm_aesimc_si128(keys[4]), + _mm_aesimc_si128(keys[5]), + _mm_aesimc_si128(keys[6]), + _mm_aesimc_si128(keys[7]), + _mm_aesimc_si128(keys[8]), + _mm_aesimc_si128(keys[9]), + _mm_aesimc_si128(keys[10]), + _mm_aesimc_si128(keys[11]), + _mm_aesimc_si128(keys[12]), + _mm_aesimc_si128(keys[13]), + keys[14], + ] +} diff --git a/aes/src/ni/aes256/expand.rs b/aes/src/ni/aes256/expand.rs deleted file mode 100644 index 5273197b..00000000 --- a/aes/src/ni/aes256/expand.rs +++ /dev/null @@ -1,91 +0,0 @@ -use super::RoundKeys; -use crate::ni::arch::*; - -use core::mem; - -macro_rules! expand_round { - ($enc_keys:expr, $dec_keys:expr, $pos:expr, $round:expr) => { - let mut t1 = $enc_keys[$pos - 2]; - let mut t2; - let mut t3 = $enc_keys[$pos - 1]; - let mut t4; - - t2 = _mm_aeskeygenassist_si128(t3, $round); - t2 = _mm_shuffle_epi32(t2, 0xff); - t4 = _mm_slli_si128(t1, 0x4); - t1 = _mm_xor_si128(t1, t4); - t4 = _mm_slli_si128(t4, 0x4); - t1 = _mm_xor_si128(t1, t4); - t4 = _mm_slli_si128(t4, 0x4); - t1 = _mm_xor_si128(t1, t4); - t1 = _mm_xor_si128(t1, t2); - - $enc_keys[$pos] = t1; - $dec_keys[$pos] = _mm_aesimc_si128(t1); - - t4 = _mm_aeskeygenassist_si128(t1, 0x00); - t2 = _mm_shuffle_epi32(t4, 0xaa); - t4 = _mm_slli_si128(t3, 0x4); - t3 = _mm_xor_si128(t3, t4); - t4 = _mm_slli_si128(t4, 0x4); - t3 = _mm_xor_si128(t3, t4); - t4 = _mm_slli_si128(t4, 0x4); - t3 = _mm_xor_si128(t3, t4); - t3 = _mm_xor_si128(t3, t2); - - $enc_keys[$pos + 1] = t3; - $dec_keys[$pos + 1] = _mm_aesimc_si128(t3); - }; -} - -macro_rules! expand_round_last { - ($enc_keys:expr, $dec_keys:expr, $pos:expr, $round:expr) => { - let mut t1 = $enc_keys[$pos - 2]; - let mut t2; - let t3 = $enc_keys[$pos - 1]; - let mut t4; - - t2 = _mm_aeskeygenassist_si128(t3, $round); - t2 = _mm_shuffle_epi32(t2, 0xff); - t4 = _mm_slli_si128(t1, 0x4); - t1 = _mm_xor_si128(t1, t4); - t4 = _mm_slli_si128(t4, 0x4); - t1 = _mm_xor_si128(t1, t4); - t4 = _mm_slli_si128(t4, 0x4); - t1 = _mm_xor_si128(t1, t4); - t1 = _mm_xor_si128(t1, t2); - - $enc_keys[$pos] = t1; - $dec_keys[$pos] = t1; - }; -} - -#[inline(always)] -pub(super) fn expand(key: &[u8; 32]) -> (RoundKeys, RoundKeys) { - // SAFETY: - // - `RoundKeys` is a `[__m128i; 15]` which can be initialized with all zeroes. - // - `loadu` and `storeu` support unaligned access - #[allow(clippy::cast_ptr_alignment)] - unsafe { - let mut enc_keys: RoundKeys = mem::zeroed(); - let mut dec_keys: RoundKeys = mem::zeroed(); - - let kp = key.as_ptr() as *const __m128i; - let k1 = _mm_loadu_si128(kp); - let k2 = _mm_loadu_si128(kp.offset(1)); - enc_keys[0] = k1; - dec_keys[0] = k1; - enc_keys[1] = k2; - dec_keys[1] = _mm_aesimc_si128(k2); - - expand_round!(enc_keys, dec_keys, 2, 0x01); - expand_round!(enc_keys, dec_keys, 4, 0x02); - expand_round!(enc_keys, dec_keys, 6, 0x04); - expand_round!(enc_keys, dec_keys, 8, 0x08); - expand_round!(enc_keys, dec_keys, 10, 0x10); - expand_round!(enc_keys, dec_keys, 12, 0x20); - expand_round_last!(enc_keys, dec_keys, 14, 0x40); - - (enc_keys, dec_keys) - } -} diff --git a/aes/src/ni/aes256/test_expand.rs b/aes/src/ni/aes256/test_expand.rs deleted file mode 100644 index 52e728ff..00000000 --- a/aes/src/ni/aes256/test_expand.rs +++ /dev/null @@ -1,103 +0,0 @@ -use super::expand::expand; -use crate::ni::utils::check; - -#[test] -fn test() { - let enc_keys = expand(&[0x00; 32]).0; - check( - &enc_keys, - &[ - [0x0000000000000000, 0x0000000000000000], - [0x0000000000000000, 0x0000000000000000], - [0x6263636362636363, 0x6263636362636363], - [0xaafbfbfbaafbfbfb, 0xaafbfbfbaafbfbfb], - [0x6f6c6ccf0d0f0fac, 0x6f6c6ccf0d0f0fac], - [0x7d8d8d6ad7767691, 0x7d8d8d6ad7767691], - [0x5354edc15e5be26d, 0x31378ea23c38810e], - [0x968a81c141fcf750, 0x3c717a3aeb070cab], - [0x9eaa8f28c0f16d45, 0xf1c6e3e7cdfe62e9], - [0x2b312bdf6acddc8f, 0x56bca6b5bdbbaa1e], - [0x6406fd52a4f79017, 0x553173f098cf1119], - [0x6dbba90b07767584, 0x51cad331ec71792f], - [0xe7b0e89c4347788b, 0x16760b7b8eb91a62], - [0x74ed0ba1739b7e25, 0x2251ad14ce20d43b], - [0x10f80a1753bf729c, 0x45c979e7cb706385], - ], - ); - - let enc_keys = expand(&[0xff; 32]).0; - check( - &enc_keys, - &[ - [0xffffffffffffffff, 0xffffffffffffffff], - [0xffffffffffffffff, 0xffffffffffffffff], - [0xe8e9e9e917161616, 0xe8e9e9e917161616], - [0x0fb8b8b8f0474747, 0x0fb8b8b8f0474747], - [0x4a4949655d5f5f73, 0xb5b6b69aa2a0a08c], - [0x355858dcc51f1f9b, 0xcaa7a7233ae0e064], - [0xafa80ae5f2f75596, 0x4741e30ce5e14380], - [0xeca0421129bf5d8a, 0xe318faa9d9f81acd], - [0xe60ab7d014fde246, 0x53bc014ab65d42ca], - [0xa2ec6e658b5333ef, 0x684bc946b1b3d38b], - [0x9b6c8a188f91685e, 0xdc2d69146a702bde], - [0xa0bd9f782beeac97, 0x43a565d1f216b65a], - [0xfc22349173b35ccf, 0xaf9e35dbc5ee1e05], - [0x0695ed132d7b4184, 0x6ede24559cc8920f], - [0x546d424f27de1e80, 0x88402b5b4dae355e], - ], - ); - - let enc_keys = expand(&[ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, - 0x1e, 0x1f, - ]) - .0; - check( - &enc_keys, - &[ - [0x0001020304050607, 0x08090a0b0c0d0e0f], - [0x1011121314151617, 0x18191a1b1c1d1e1f], - [0xa573c29fa176c498, 0xa97fce93a572c09c], - [0x1651a8cd0244beda, 0x1a5da4c10640bade], - [0xae87dff00ff11b68, 0xa68ed5fb03fc1567], - [0x6de1f1486fa54f92, 0x75f8eb5373b8518d], - [0xc656827fc9a79917, 0x6f294cec6cd5598b], - [0x3de23a75524775e7, 0x27bf9eb45407cf39], - [0x0bdc905fc27b0948, 0xad5245a4c1871c2f], - [0x45f5a66017b2d387, 0x300d4d33640a820a], - [0x7ccff71cbeb4fe54, 0x13e6bbf0d261a7df], - [0xf01afafee7a82979, 0xd7a5644ab3afe640], - [0x2541fe719bf50025, 0x8813bbd55a721c0a], - [0x4e5a6699a9f24fe0, 0x7e572baacdf8cdea], - [0x24fc79ccbf0979e9, 0x371ac23c6d68de36], - ], - ); - - let enc_keys = expand(&[ - 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, - 0x81, 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, - 0xdf, 0xf4, - ]) - .0; - check( - &enc_keys, - &[ - [0x603deb1015ca71be, 0x2b73aef0857d7781], - [0x1f352c073b6108d7, 0x2d9810a30914dff4], - [0x9ba354118e6925af, 0xa51a8b5f2067fcde], - [0xa8b09c1a93d194cd, 0xbe49846eb75d5b9a], - [0xd59aecb85bf3c917, 0xfee94248de8ebe96], - [0xb5a9328a2678a647, 0x983122292f6c79b3], - [0x812c81addadf48ba, 0x24360af2fab8b464], - [0x98c5bfc9bebd198e, 0x268c3ba709e04214], - [0x68007bacb2df3316, 0x96e939e46c518d80], - [0xc814e20476a9fb8a, 0x5025c02d59c58239], - [0xde1369676ccc5a71, 0xfa2563959674ee15], - [0x5886ca5d2e2f31d7, 0x7e0af1fa27cf73c3], - [0x749c47ab18501dda, 0xe2757e4f7401905a], - [0xcafaaae3e4d59b34, 0x9adf6acebd10190d], - [0xfe4890d1e6188d0b, 0x046df344706c631e], - ], - ); -} diff --git a/aes/src/ni/ctr.rs b/aes/src/ni/ctr.rs deleted file mode 100644 index 49efd7d3..00000000 --- a/aes/src/ni/ctr.rs +++ /dev/null @@ -1,232 +0,0 @@ -//! AES in counter mode (a.k.a. AES-CTR) - -// TODO(tarcieri): support generic CTR API - -#![allow(clippy::unreadable_literal)] - -use super::arch::*; -use core::mem; - -use super::{Aes128, Aes192, Aes256}; -use crate::BLOCK_SIZE; -use cipher::{ - consts::U16, - errors::{LoopError, OverflowError}, - generic_array::GenericArray, - BlockCipher, FromBlockCipher, SeekNum, StreamCipher, StreamCipherSeek, -}; - -const PAR_BLOCKS: usize = 8; -const PAR_BLOCKS_SIZE: usize = PAR_BLOCKS * BLOCK_SIZE; - -#[inline(always)] -pub fn xor(buf: &mut [u8], key: &[u8]) { - debug_assert_eq!(buf.len(), key.len()); - for (a, b) in buf.iter_mut().zip(key) { - *a ^= *b; - } -} - -#[inline(always)] -fn xor_block8(buf: &mut [u8], ctr: [__m128i; 8]) { - debug_assert_eq!(buf.len(), PAR_BLOCKS_SIZE); - - // Safety: `loadu` and `storeu` support unaligned access - #[allow(clippy::cast_ptr_alignment)] - unsafe { - // compiler should unroll this loop - for i in 0..8 { - let ptr = buf.as_mut_ptr().offset(16 * i) as *mut __m128i; - let data = _mm_loadu_si128(ptr); - let data = _mm_xor_si128(data, ctr[i as usize]); - _mm_storeu_si128(ptr, data); - } - } -} - -#[inline(always)] -fn swap_bytes(v: __m128i) -> __m128i { - unsafe { - let mask = _mm_set_epi64x(0x08090a0b0c0d0e0f, 0x0001020304050607); - _mm_shuffle_epi8(v, mask) - } -} - -#[inline(always)] -fn inc_be(v: __m128i) -> __m128i { - unsafe { _mm_add_epi64(v, _mm_set_epi64x(1, 0)) } -} - -#[inline(always)] -fn load(val: &GenericArray) -> __m128i { - // Safety: `loadu` supports unaligned loads - #[allow(clippy::cast_ptr_alignment)] - unsafe { - _mm_loadu_si128(val.as_ptr() as *const __m128i) - } -} - -macro_rules! impl_ctr { - ($name:ident, $cipher:ty, $doc:expr) => { - #[doc=$doc] - #[derive(Clone)] - #[cfg_attr(docsrs, doc(cfg(feature = "ctr")))] - pub struct $name { - nonce: __m128i, - ctr: __m128i, - cipher: $cipher, - block: [u8; BLOCK_SIZE], - pos: u8, - } - - impl $name { - #[inline(always)] - fn gen_block(&mut self) { - let block = self.cipher.encrypt(swap_bytes(self.ctr)); - // SAFETY: All three expansions of this macro have a `$cipher` whose - // `encrypt(...)` method returns an `__m128i`, and `BLOCK_SIZE == 16`. - self.block = unsafe { mem::transmute(block) } - } - - #[inline(always)] - fn next_block(&mut self) -> __m128i { - let block = swap_bytes(self.ctr); - self.ctr = inc_be(self.ctr); - self.cipher.encrypt(block) - } - - #[inline(always)] - fn next_block8(&mut self) -> [__m128i; 8] { - let mut ctr = self.ctr; - // SAFETY: `[__m128i; 8]` can be initialized with all zeroes. - let mut block8: [__m128i; 8] = unsafe { mem::zeroed() }; - for i in 0..8 { - block8[i] = swap_bytes(ctr); - ctr = inc_be(ctr); - } - self.ctr = ctr; - - self.cipher.encrypt8(block8) - } - - #[inline(always)] - fn get_u64_ctr(&self) -> u64 { - let (ctr, nonce) = unsafe { - ( - mem::transmute::<__m128i, [u64; 2]>(self.ctr)[1], - mem::transmute::<__m128i, [u64; 2]>(self.nonce)[1], - ) - }; - ctr.wrapping_sub(nonce) - } - - /// Check if provided data will not overflow counter - #[inline(always)] - fn check_data_len(&self, data: &[u8]) -> Result<(), LoopError> { - let bs = BLOCK_SIZE; - let leftover_bytes = bs - self.pos as usize; - if data.len() < leftover_bytes { - return Ok(()); - } - let blocks = 1 + (data.len() - leftover_bytes) / bs; - self.get_u64_ctr() - .checked_add(blocks as u64) - .ok_or(LoopError) - .map(|_| ()) - } - } - - impl FromBlockCipher for $name { - type BlockCipher = $cipher; - type NonceSize = <$cipher as BlockCipher>::BlockSize; - - fn from_block_cipher( - cipher: $cipher, - nonce: &GenericArray, - ) -> Self { - let nonce = swap_bytes(load(nonce)); - Self { - nonce, - ctr: nonce, - cipher, - block: [0u8; BLOCK_SIZE], - pos: 0, - } - } - } - - impl StreamCipher for $name { - #[inline] - fn try_apply_keystream(&mut self, mut data: &mut [u8]) -> Result<(), LoopError> { - self.check_data_len(data)?; - let bs = BLOCK_SIZE; - let pos = self.pos as usize; - debug_assert!(bs > pos); - - if pos != 0 { - if data.len() < bs - pos { - let n = pos + data.len(); - xor(data, &self.block[pos..n]); - self.pos = n as u8; - return Ok(()); - } else { - let (l, r) = data.split_at_mut(bs - pos); - data = r; - xor(l, &self.block[pos..]); - self.ctr = inc_be(self.ctr); - } - } - - let mut chunks = data.chunks_exact_mut(PAR_BLOCKS_SIZE); - for chunk in &mut chunks { - xor_block8(chunk, self.next_block8()); - } - data = chunks.into_remainder(); - - let mut chunks = data.chunks_exact_mut(bs); - for chunk in &mut chunks { - let block = self.next_block(); - - unsafe { - let t = _mm_loadu_si128(chunk.as_ptr() as *const __m128i); - let res = _mm_xor_si128(block, t); - _mm_storeu_si128(chunk.as_mut_ptr() as *mut __m128i, res); - } - } - - let rem = chunks.into_remainder(); - self.pos = rem.len() as u8; - if !rem.is_empty() { - self.gen_block(); - for (a, b) in rem.iter_mut().zip(&self.block) { - *a ^= *b; - } - } - - Ok(()) - } - } - - impl StreamCipherSeek for $name { - fn try_current_pos(&self) -> Result { - T::from_block_byte(self.get_u64_ctr(), self.pos, BLOCK_SIZE as u8) - } - - fn try_seek(&mut self, pos: T) -> Result<(), LoopError> { - let res: (u64, u8) = pos.to_block_byte(BLOCK_SIZE as u8)?; - self.ctr = unsafe { _mm_add_epi64(self.nonce, _mm_set_epi64x(res.0 as i64, 0)) }; - self.pos = res.1; - if self.pos != 0 { - self.gen_block() - } - Ok(()) - } - } - - opaque_debug::implement!($name); - }; -} - -impl_ctr!(Aes128Ctr, Aes128, "AES-128 in CTR mode"); -impl_ctr!(Aes192Ctr, Aes192, "AES-192 in CTR mode"); -impl_ctr!(Aes256Ctr, Aes256, "AES-256 in CTR mode"); diff --git a/aes/src/ni/hazmat.rs b/aes/src/ni/hazmat.rs index 5188ad75..a2a735a3 100644 --- a/aes/src/ni/hazmat.rs +++ b/aes/src/ni/hazmat.rs @@ -8,10 +8,9 @@ use super::{ arch::*, utils::{load8, store8}, }; -use crate::{Block, ParBlocks}; +use crate::{Block, Block8}; /// AES cipher (encrypt) round function. -#[allow(clippy::cast_ptr_alignment)] #[target_feature(enable = "aes")] pub(crate) unsafe fn cipher_round(block: &mut Block, round_key: &Block) { // Safety: `loadu` and `storeu` support unaligned access @@ -22,9 +21,8 @@ pub(crate) unsafe fn cipher_round(block: &mut Block, round_key: &Block) { } /// AES cipher (encrypt) round function: parallel version. -#[allow(clippy::cast_ptr_alignment)] #[target_feature(enable = "aes")] -pub(crate) unsafe fn cipher_round_par(blocks: &mut ParBlocks, round_keys: &ParBlocks) { +pub(crate) unsafe fn cipher_round_par(blocks: &mut Block8, round_keys: &Block8) { let xmm_keys = load8(round_keys); let mut xmm_blocks = load8(blocks); @@ -36,7 +34,6 @@ pub(crate) unsafe fn cipher_round_par(blocks: &mut ParBlocks, round_keys: &ParBl } /// AES cipher (encrypt) round function. -#[allow(clippy::cast_ptr_alignment)] #[target_feature(enable = "aes")] pub(crate) unsafe fn equiv_inv_cipher_round(block: &mut Block, round_key: &Block) { // Safety: `loadu` and `storeu` support unaligned access @@ -47,9 +44,8 @@ pub(crate) unsafe fn equiv_inv_cipher_round(block: &mut Block, round_key: &Block } /// AES cipher (encrypt) round function: parallel version. -#[allow(clippy::cast_ptr_alignment)] #[target_feature(enable = "aes")] -pub(crate) unsafe fn equiv_inv_cipher_round_par(blocks: &mut ParBlocks, round_keys: &ParBlocks) { +pub(crate) unsafe fn equiv_inv_cipher_round_par(blocks: &mut Block8, round_keys: &Block8) { let xmm_keys = load8(round_keys); let mut xmm_blocks = load8(blocks); @@ -61,7 +57,6 @@ pub(crate) unsafe fn equiv_inv_cipher_round_par(blocks: &mut ParBlocks, round_ke } /// AES mix columns function. -#[allow(clippy::cast_ptr_alignment)] #[target_feature(enable = "aes")] pub(crate) unsafe fn mix_columns(block: &mut Block) { // Safety: `loadu` and `storeu` support unaligned access @@ -76,7 +71,6 @@ pub(crate) unsafe fn mix_columns(block: &mut Block) { } /// AES inverse mix columns function. -#[allow(clippy::cast_ptr_alignment)] #[target_feature(enable = "aes")] pub(crate) unsafe fn inv_mix_columns(block: &mut Block) { // Safety: `loadu` and `storeu` support unaligned access diff --git a/aes/src/ni/test_expand.rs b/aes/src/ni/test_expand.rs new file mode 100644 index 00000000..6ab87c5e --- /dev/null +++ b/aes/src/ni/test_expand.rs @@ -0,0 +1,275 @@ +use super::utils::check; +use hex_literal::hex; + +#[test] +fn aes128_expand_key_test() { + use super::aes128::expand_key; + + let keys = [0x00; 16]; + check( + unsafe { &expand_key(&keys) }, + &[ + [0x0000000000000000, 0x0000000000000000], + [0x6263636362636363, 0x6263636362636363], + [0x9b9898c9f9fbfbaa, 0x9b9898c9f9fbfbaa], + [0x90973450696ccffa, 0xf2f457330b0fac99], + [0xee06da7b876a1581, 0x759e42b27e91ee2b], + [0x7f2e2b88f8443e09, 0x8dda7cbbf34b9290], + [0xec614b851425758c, 0x99ff09376ab49ba7], + [0x217517873550620b, 0xacaf6b3cc61bf09b], + [0x0ef903333ba96138, 0x97060a04511dfa9f], + [0xb1d4d8e28a7db9da, 0x1d7bb3de4c664941], + [0xb4ef5bcb3e92e211, 0x23e951cf6f8f188e], + ], + ); + + let keys = [0xff; 16]; + check( + unsafe { &expand_key(&keys) }, + &[ + [0xffffffffffffffff, 0xffffffffffffffff], + [0xe8e9e9e917161616, 0xe8e9e9e917161616], + [0xadaeae19bab8b80f, 0x525151e6454747f0], + [0x090e2277b3b69a78, 0xe1e7cb9ea4a08c6e], + [0xe16abd3e52dc2746, 0xb33becd8179b60b6], + [0xe5baf3ceb766d488, 0x045d385013c658e6], + [0x71d07db3c6b6a93b, 0xc2eb916bd12dc98d], + [0xe90d208d2fbb89b6, 0xed5018dd3c7dd150], + [0x96337366b988fad0, 0x54d8e20d68a5335d], + [0x8bf03f233278c5f3, 0x66a027fe0e0514a3], + [0xd60a3588e472f07b, 0x82d2d7858cd7c326], + ], + ); + + let keys = hex!("000102030405060708090a0b0c0d0e0f"); + check( + unsafe { &expand_key(&keys) }, + &[ + [0x0001020304050607, 0x08090a0b0c0d0e0f], + [0xd6aa74fdd2af72fa, 0xdaa678f1d6ab76fe], + [0xb692cf0b643dbdf1, 0xbe9bc5006830b3fe], + [0xb6ff744ed2c2c9bf, 0x6c590cbf0469bf41], + [0x47f7f7bc95353e03, 0xf96c32bcfd058dfd], + [0x3caaa3e8a99f9deb, 0x50f3af57adf622aa], + [0x5e390f7df7a69296, 0xa7553dc10aa31f6b], + [0x14f9701ae35fe28c, 0x440adf4d4ea9c026], + [0x47438735a41c65b9, 0xe016baf4aebf7ad2], + [0x549932d1f0855768, 0x1093ed9cbe2c974e], + [0x13111d7fe3944a17, 0xf307a78b4d2b30c5], + ], + ); + + let keys = hex!("6920e299a5202a6d656e636869746f2a"); + check( + unsafe { &expand_key(&keys) }, + &[ + [0x6920e299a5202a6d, 0x656e636869746f2a], + [0xfa8807605fa82d0d, 0x3ac64e6553b2214f], + [0xcf75838d90ddae80, 0xaa1be0e5f9a9c1aa], + [0x180d2f1488d08194, 0x22cb6171db62a0db], + [0xbaed96ad323d1739, 0x10f67648cb94d693], + [0x881b4ab2ba265d8b, 0xaad02bc36144fd50], + [0xb34f195d096944d6, 0xa3b96f15c2fd9245], + [0xa7007778ae6933ae, 0x0dd05cbbcf2dcefe], + [0xff8bccf251e2ff5c, 0x5c32a3e7931f6d19], + [0x24b7182e7555e772, 0x29674495ba78298c], + [0xae127cdadb479ba8, 0xf220df3d4858f6b1], + ], + ); + + let keys = hex!("2b7e151628aed2a6abf7158809cf4f3c"); + check( + unsafe { &expand_key(&keys) }, + &[ + [0x2b7e151628aed2a6, 0xabf7158809cf4f3c], + [0xa0fafe1788542cb1, 0x23a339392a6c7605], + [0xf2c295f27a96b943, 0x5935807a7359f67f], + [0x3d80477d4716fe3e, 0x1e237e446d7a883b], + [0xef44a541a8525b7f, 0xb671253bdb0bad00], + [0xd4d1c6f87c839d87, 0xcaf2b8bc11f915bc], + [0x6d88a37a110b3efd, 0xdbf98641ca0093fd], + [0x4e54f70e5f5fc9f3, 0x84a64fb24ea6dc4f], + [0xead27321b58dbad2, 0x312bf5607f8d292f], + [0xac7766f319fadc21, 0x28d12941575c006e], + [0xd014f9a8c9ee2589, 0xe13f0cc8b6630ca6], + ], + ); +} + +#[test] +fn aes192_expand_key_test() { + use super::aes192::expand_key; + + let keys = [0x00; 24]; + check( + unsafe { &expand_key(&keys) }, + &[ + [0x0000000000000000, 0x0000000000000000], + [0x0000000000000000, 0x6263636362636363], + [0x6263636362636363, 0x6263636362636363], + [0x9b9898c9f9fbfbaa, 0x9b9898c9f9fbfbaa], + [0x9b9898c9f9fbfbaa, 0x90973450696ccffa], + [0xf2f457330b0fac99, 0x90973450696ccffa], + [0xc81d19a9a171d653, 0x53858160588a2df9], + [0xc81d19a9a171d653, 0x7bebf49bda9a22c8], + [0x891fa3a8d1958e51, 0x198897f8b8f941ab], + [0xc26896f718f2b43f, 0x91ed1797407899c6], + [0x59f00e3ee1094f95, 0x83ecbc0f9b1e0830], + [0x0af31fa74a8b8661, 0x137b885ff272c7ca], + [0x432ac886d834c0b6, 0xd2c7df11984c5970], + ], + ); + + let keys = [0xff; 24]; + check( + unsafe { &expand_key(&keys) }, + &[ + [0xffffffffffffffff, 0xffffffffffffffff], + [0xffffffffffffffff, 0xe8e9e9e917161616], + [0xe8e9e9e917161616, 0xe8e9e9e917161616], + [0xadaeae19bab8b80f, 0x525151e6454747f0], + [0xadaeae19bab8b80f, 0xc5c2d8ed7f7a60e2], + [0x2d2b3104686c76f4, 0xc5c2d8ed7f7a60e2], + [0x1712403f686820dd, 0x454311d92d2f672d], + [0xe8edbfc09797df22, 0x8f8cd3b7e7e4f36a], + [0xa2a7e2b38f88859e, 0x67653a5ef0f2e57c], + [0x2655c33bc1b13051, 0x6316d2e2ec9e577c], + [0x8bfb6d227b09885e, 0x67919b1aa620ab4b], + [0xc53679a929a82ed5, 0xa25343f7d95acba9], + [0x598e482fffaee364, 0x3a989acd1330b418], + ], + ); + + let keys = hex!("000102030405060708090a0b0c0d0e0f1011121314151617"); + check( + unsafe { &expand_key(&keys) }, + &[ + [0x0001020304050607, 0x08090a0b0c0d0e0f], + [0x1011121314151617, 0x5846f2f95c43f4fe], + [0x544afef55847f0fa, 0x4856e2e95c43f4fe], + [0x40f949b31cbabd4d, 0x48f043b810b7b342], + [0x58e151ab04a2a555, 0x7effb5416245080c], + [0x2ab54bb43a02f8f6, 0x62e3a95d66410c08], + [0xf501857297448d7e, 0xbdf1c6ca87f33e3c], + [0xe510976183519b69, 0x34157c9ea351f1e0], + [0x1ea0372a99530916, 0x7c439e77ff12051e], + [0xdd7e0e887e2fff68, 0x608fc842f9dcc154], + [0x859f5f237a8d5a3d, 0xc0c02952beefd63a], + [0xde601e7827bcdf2c, 0xa223800fd8aeda32], + [0xa4970a331a78dc09, 0xc418c271e3a41d5d], + ], + ); + + let keys = hex!("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"); + check( + unsafe { &expand_key(&keys) }, + &[ + [0x8e73b0f7da0e6452, 0xc810f32b809079e5], + [0x62f8ead2522c6b7b, 0xfe0c91f72402f5a5], + [0xec12068e6c827f6b, 0x0e7a95b95c56fec2], + [0x4db7b4bd69b54118, 0x85a74796e92538fd], + [0xe75fad44bb095386, 0x485af05721efb14f], + [0xa448f6d94d6dce24, 0xaa326360113b30e6], + [0xa25e7ed583b1cf9a, 0x27f939436a94f767], + [0xc0a69407d19da4e1, 0xec1786eb6fa64971], + [0x485f703222cb8755, 0xe26d135233f0b7b3], + [0x40beeb282f18a259, 0x6747d26b458c553e], + [0xa7e1466c9411f1df, 0x821f750aad07d753], + [0xca4005388fcc5006, 0x282d166abc3ce7b5], + [0xe98ba06f448c773c, 0x8ecc720401002202], + ], + ); +} + +#[test] +fn aes256_expand_key_test() { + use super::aes256::expand_key; + + let keys = [0x00; 32]; + check( + unsafe { &expand_key(&keys) }, + &[ + [0x0000000000000000, 0x0000000000000000], + [0x0000000000000000, 0x0000000000000000], + [0x6263636362636363, 0x6263636362636363], + [0xaafbfbfbaafbfbfb, 0xaafbfbfbaafbfbfb], + [0x6f6c6ccf0d0f0fac, 0x6f6c6ccf0d0f0fac], + [0x7d8d8d6ad7767691, 0x7d8d8d6ad7767691], + [0x5354edc15e5be26d, 0x31378ea23c38810e], + [0x968a81c141fcf750, 0x3c717a3aeb070cab], + [0x9eaa8f28c0f16d45, 0xf1c6e3e7cdfe62e9], + [0x2b312bdf6acddc8f, 0x56bca6b5bdbbaa1e], + [0x6406fd52a4f79017, 0x553173f098cf1119], + [0x6dbba90b07767584, 0x51cad331ec71792f], + [0xe7b0e89c4347788b, 0x16760b7b8eb91a62], + [0x74ed0ba1739b7e25, 0x2251ad14ce20d43b], + [0x10f80a1753bf729c, 0x45c979e7cb706385], + ], + ); + + let keys = [0xff; 32]; + check( + unsafe { &expand_key(&keys) }, + &[ + [0xffffffffffffffff, 0xffffffffffffffff], + [0xffffffffffffffff, 0xffffffffffffffff], + [0xe8e9e9e917161616, 0xe8e9e9e917161616], + [0x0fb8b8b8f0474747, 0x0fb8b8b8f0474747], + [0x4a4949655d5f5f73, 0xb5b6b69aa2a0a08c], + [0x355858dcc51f1f9b, 0xcaa7a7233ae0e064], + [0xafa80ae5f2f75596, 0x4741e30ce5e14380], + [0xeca0421129bf5d8a, 0xe318faa9d9f81acd], + [0xe60ab7d014fde246, 0x53bc014ab65d42ca], + [0xa2ec6e658b5333ef, 0x684bc946b1b3d38b], + [0x9b6c8a188f91685e, 0xdc2d69146a702bde], + [0xa0bd9f782beeac97, 0x43a565d1f216b65a], + [0xfc22349173b35ccf, 0xaf9e35dbc5ee1e05], + [0x0695ed132d7b4184, 0x6ede24559cc8920f], + [0x546d424f27de1e80, 0x88402b5b4dae355e], + ], + ); + + let keys = hex!("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"); + check( + unsafe { &expand_key(&keys) }, + &[ + [0x0001020304050607, 0x08090a0b0c0d0e0f], + [0x1011121314151617, 0x18191a1b1c1d1e1f], + [0xa573c29fa176c498, 0xa97fce93a572c09c], + [0x1651a8cd0244beda, 0x1a5da4c10640bade], + [0xae87dff00ff11b68, 0xa68ed5fb03fc1567], + [0x6de1f1486fa54f92, 0x75f8eb5373b8518d], + [0xc656827fc9a79917, 0x6f294cec6cd5598b], + [0x3de23a75524775e7, 0x27bf9eb45407cf39], + [0x0bdc905fc27b0948, 0xad5245a4c1871c2f], + [0x45f5a66017b2d387, 0x300d4d33640a820a], + [0x7ccff71cbeb4fe54, 0x13e6bbf0d261a7df], + [0xf01afafee7a82979, 0xd7a5644ab3afe640], + [0x2541fe719bf50025, 0x8813bbd55a721c0a], + [0x4e5a6699a9f24fe0, 0x7e572baacdf8cdea], + [0x24fc79ccbf0979e9, 0x371ac23c6d68de36], + ], + ); + + let keys = hex!("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"); + check( + unsafe { &expand_key(&keys) }, + &[ + [0x603deb1015ca71be, 0x2b73aef0857d7781], + [0x1f352c073b6108d7, 0x2d9810a30914dff4], + [0x9ba354118e6925af, 0xa51a8b5f2067fcde], + [0xa8b09c1a93d194cd, 0xbe49846eb75d5b9a], + [0xd59aecb85bf3c917, 0xfee94248de8ebe96], + [0xb5a9328a2678a647, 0x983122292f6c79b3], + [0x812c81addadf48ba, 0x24360af2fab8b464], + [0x98c5bfc9bebd198e, 0x268c3ba709e04214], + [0x68007bacb2df3316, 0x96e939e46c518d80], + [0xc814e20476a9fb8a, 0x5025c02d59c58239], + [0xde1369676ccc5a71, 0xfa2563959674ee15], + [0x5886ca5d2e2f31d7, 0x7e0af1fa27cf73c3], + [0x749c47ab18501dda, 0xe2757e4f7401905a], + [0xcafaaae3e4d59b34, 0x9adf6acebd10190d], + [0xfe4890d1e6188d0b, 0x046df344706c631e], + ], + ); +} diff --git a/aes/src/ni/utils.rs b/aes/src/ni/utils.rs index 1fc3403d..1bd6522d 100644 --- a/aes/src/ni/utils.rs +++ b/aes/src/ni/utils.rs @@ -4,7 +4,7 @@ #![allow(clippy::needless_range_loop)] use super::arch::*; -use crate::ParBlocks; +use crate::{Block, Block8}; pub type U128x8 = [__m128i; 8]; @@ -18,32 +18,34 @@ pub(crate) fn check(a: &[__m128i], b: &[[u64; 2]]) { } #[inline(always)] -pub(crate) fn load8(blocks: &ParBlocks) -> U128x8 { +pub(crate) fn load8(blocks: *const Block8) -> U128x8 { unsafe { + let p = blocks as *const Block; [ - _mm_loadu_si128(blocks[0].as_ptr() as *const __m128i), - _mm_loadu_si128(blocks[1].as_ptr() as *const __m128i), - _mm_loadu_si128(blocks[2].as_ptr() as *const __m128i), - _mm_loadu_si128(blocks[3].as_ptr() as *const __m128i), - _mm_loadu_si128(blocks[4].as_ptr() as *const __m128i), - _mm_loadu_si128(blocks[5].as_ptr() as *const __m128i), - _mm_loadu_si128(blocks[6].as_ptr() as *const __m128i), - _mm_loadu_si128(blocks[7].as_ptr() as *const __m128i), + _mm_loadu_si128(p.add(0) as *const __m128i), + _mm_loadu_si128(p.add(1) as *const __m128i), + _mm_loadu_si128(p.add(2) as *const __m128i), + _mm_loadu_si128(p.add(3) as *const __m128i), + _mm_loadu_si128(p.add(4) as *const __m128i), + _mm_loadu_si128(p.add(5) as *const __m128i), + _mm_loadu_si128(p.add(6) as *const __m128i), + _mm_loadu_si128(p.add(7) as *const __m128i), ] } } #[inline(always)] -pub(crate) fn store8(blocks: &mut ParBlocks, b: U128x8) { +pub(crate) fn store8(blocks: *mut Block8, b: U128x8) { unsafe { - _mm_storeu_si128(blocks[0].as_mut_ptr() as *mut __m128i, b[0]); - _mm_storeu_si128(blocks[1].as_mut_ptr() as *mut __m128i, b[1]); - _mm_storeu_si128(blocks[2].as_mut_ptr() as *mut __m128i, b[2]); - _mm_storeu_si128(blocks[3].as_mut_ptr() as *mut __m128i, b[3]); - _mm_storeu_si128(blocks[4].as_mut_ptr() as *mut __m128i, b[4]); - _mm_storeu_si128(blocks[5].as_mut_ptr() as *mut __m128i, b[5]); - _mm_storeu_si128(blocks[6].as_mut_ptr() as *mut __m128i, b[6]); - _mm_storeu_si128(blocks[7].as_mut_ptr() as *mut __m128i, b[7]); + let p = blocks as *mut Block; + _mm_storeu_si128(p.add(0) as *mut __m128i, b[0]); + _mm_storeu_si128(p.add(1) as *mut __m128i, b[1]); + _mm_storeu_si128(p.add(2) as *mut __m128i, b[2]); + _mm_storeu_si128(p.add(3) as *mut __m128i, b[3]); + _mm_storeu_si128(p.add(4) as *mut __m128i, b[4]); + _mm_storeu_si128(p.add(5) as *mut __m128i, b[5]); + _mm_storeu_si128(p.add(6) as *mut __m128i, b[6]); + _mm_storeu_si128(p.add(7) as *mut __m128i, b[7]); } } diff --git a/aes/src/soft.rs b/aes/src/soft.rs index 1b51d223..054bbd51 100644 --- a/aes/src/soft.rs +++ b/aes/src/soft.rs @@ -12,116 +12,314 @@ #[cfg_attr(target_pointer_width = "64", path = "soft/fixslice64.rs")] pub(crate) mod fixslice; -#[cfg(feature = "ctr")] -mod ctr; - -#[cfg(feature = "ctr")] -pub use self::ctr::{Aes128Ctr, Aes192Ctr, Aes256Ctr}; - -use crate::{Block, ParBlocks}; +use crate::Block; use cipher::{ - consts::{U16, U24, U32, U8}, - generic_array::GenericArray, - BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher, + consts::{U16, U24, U32}, + inout::InOut, + AlgorithmName, BlockBackend, BlockCipher, BlockClosure, BlockDecrypt, BlockEncrypt, + BlockSizeUser, Key, KeyInit, KeySizeUser, ParBlocksSizeUser, }; -use fixslice::{FixsliceKeys128, FixsliceKeys192, FixsliceKeys256, FIXSLICE_BLOCKS}; +use core::fmt; +use fixslice::{BatchBlocks, FixsliceBlocks, FixsliceKeys128, FixsliceKeys192, FixsliceKeys256}; macro_rules! define_aes_impl { ( - $name:ident, + $name:tt, + $name_enc:ident, + $name_dec:ident, + $name_back_enc:ident, + $name_back_dec:ident, $key_size:ty, $fixslice_keys:ty, $fixslice_key_schedule:path, $fixslice_decrypt:path, $fixslice_encrypt:path, - $doc:expr + $doc:expr $(,)? ) => { #[doc=$doc] + #[doc = "block cipher"] #[derive(Clone)] pub struct $name { keys: $fixslice_keys, } - impl NewBlockCipher for $name { + impl $name { + #[inline(always)] + pub(crate) fn get_enc_backend(&self) -> $name_back_enc<'_> { + $name_back_enc(self) + } + + #[inline(always)] + pub(crate) fn get_dec_backend(&self) -> $name_back_dec<'_> { + $name_back_dec(self) + } + } + + impl KeySizeUser for $name { type KeySize = $key_size; + } + impl KeyInit for $name { #[inline] - fn new(key: &GenericArray) -> Self { + fn new(key: &Key) -> Self { Self { - keys: $fixslice_key_schedule(key), + keys: $fixslice_key_schedule(key.as_ref()), } } } - impl BlockCipher for $name { + impl BlockSizeUser for $name { type BlockSize = U16; - type ParBlocks = U8; } + impl BlockCipher for $name {} + impl BlockEncrypt for $name { + fn encrypt_with_backend(&self, f: impl BlockClosure) { + f.call(&mut self.get_enc_backend()) + } + } + + impl BlockDecrypt for $name { + fn decrypt_with_backend(&self, f: impl BlockClosure) { + f.call(&mut self.get_dec_backend()) + } + } + + impl From<$name_enc> for $name { #[inline] - fn encrypt_block(&self, block: &mut Block) { - let mut blocks = [Block::default(); FIXSLICE_BLOCKS]; - blocks[0].copy_from_slice(block); - $fixslice_encrypt(&self.keys, &mut blocks); - block.copy_from_slice(&blocks[0]); + fn from(enc: $name_enc) -> $name { + enc.inner } + } + impl From<&$name_enc> for $name { #[inline] - fn encrypt_par_blocks(&self, blocks: &mut ParBlocks) { - for chunk in blocks.chunks_mut(FIXSLICE_BLOCKS) { - $fixslice_encrypt(&self.keys, chunk); - } + fn from(enc: &$name_enc) -> $name { + enc.inner.clone() } } - impl BlockDecrypt for $name { + impl fmt::Debug for $name { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str(concat!(stringify!($name), " { .. }")) + } + } + + impl AlgorithmName for $name { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(stringify!($name)) + } + } + + #[doc=$doc] + #[doc = "block cipher (encrypt-only)"] + #[derive(Clone)] + pub struct $name_enc { + inner: $name, + } + + impl $name_enc { + #[inline(always)] + pub(crate) fn get_enc_backend(&self) -> $name_back_enc<'_> { + self.inner.get_enc_backend() + } + } + + impl BlockCipher for $name_enc {} + + impl KeySizeUser for $name_enc { + type KeySize = $key_size; + } + + impl KeyInit for $name_enc { + #[inline(always)] + fn new(key: &Key) -> Self { + let inner = $name::new(key); + Self { inner } + } + } + + impl BlockSizeUser for $name_enc { + type BlockSize = U16; + } + + impl BlockEncrypt for $name_enc { + fn encrypt_with_backend(&self, f: impl BlockClosure) { + f.call(&mut self.get_enc_backend()) + } + } + + impl fmt::Debug for $name_enc { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str(concat!(stringify!($name_enc), " { .. }")) + } + } + + impl AlgorithmName for $name_enc { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(stringify!($name_enc)) + } + } + + #[doc=$doc] + #[doc = "block cipher (decrypt-only)"] + #[derive(Clone)] + pub struct $name_dec { + inner: $name, + } + + impl $name_dec { + #[inline(always)] + pub(crate) fn get_dec_backend(&self) -> $name_back_dec<'_> { + self.inner.get_dec_backend() + } + } + + impl BlockCipher for $name_dec {} + + impl KeySizeUser for $name_dec { + type KeySize = $key_size; + } + + impl KeyInit for $name_dec { + #[inline(always)] + fn new(key: &Key) -> Self { + let inner = $name::new(key); + Self { inner } + } + } + + impl From<$name_enc> for $name_dec { #[inline] - fn decrypt_block(&self, block: &mut Block) { - let mut blocks = [Block::default(); FIXSLICE_BLOCKS]; - blocks[0].copy_from_slice(block); - $fixslice_decrypt(&self.keys, &mut blocks); - block.copy_from_slice(&blocks[0]); + fn from(enc: $name_enc) -> $name_dec { + Self { inner: enc.inner } } + } + impl From<&$name_enc> for $name_dec { #[inline] - fn decrypt_par_blocks(&self, blocks: &mut ParBlocks) { - for chunk in blocks.chunks_mut(FIXSLICE_BLOCKS) { - $fixslice_decrypt(&self.keys, chunk); + fn from(enc: &$name_enc) -> $name_dec { + Self { + inner: enc.inner.clone(), } } } - opaque_debug::implement!($name); + impl BlockSizeUser for $name_dec { + type BlockSize = U16; + } + + impl BlockDecrypt for $name_dec { + fn decrypt_with_backend(&self, f: impl BlockClosure) { + f.call(&mut self.get_dec_backend()); + } + } + + impl fmt::Debug for $name_dec { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str(concat!(stringify!($name_dec), " { .. }")) + } + } + + impl AlgorithmName for $name_dec { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(stringify!($name_dec)) + } + } + + pub(crate) struct $name_back_enc<'a>(&'a $name); + + impl<'a> BlockSizeUser for $name_back_enc<'a> { + type BlockSize = U16; + } + + impl<'a> ParBlocksSizeUser for $name_back_enc<'a> { + type ParBlocksSize = FixsliceBlocks; + } + + impl<'a> BlockBackend for $name_back_enc<'a> { + #[inline(always)] + fn proc_block(&mut self, mut block: InOut<'_, '_, Block>) { + let mut blocks = BatchBlocks::default(); + blocks[0] = block.clone_in().into(); + let res = $fixslice_encrypt(&self.0.keys, &blocks); + *block.get_out() = res[0].into(); + } + + #[inline(always)] + fn proc_par_blocks(&mut self, mut blocks: InOut<'_, '_, BatchBlocks>) { + let res = $fixslice_encrypt(&self.0.keys, blocks.get_in()); + *blocks.get_out() = res; + } + } + + pub(crate) struct $name_back_dec<'a>(&'a $name); + + impl<'a> BlockSizeUser for $name_back_dec<'a> { + type BlockSize = U16; + } + + impl<'a> ParBlocksSizeUser for $name_back_dec<'a> { + type ParBlocksSize = FixsliceBlocks; + } + + impl<'a> BlockBackend for $name_back_dec<'a> { + #[inline(always)] + fn proc_block(&mut self, mut block: InOut<'_, '_, Block>) { + let mut blocks = BatchBlocks::default(); + blocks[0] = block.clone_in(); + let res = $fixslice_decrypt(&self.0.keys, &blocks); + *block.get_out() = res[0]; + } + + #[inline(always)] + fn proc_par_blocks(&mut self, mut blocks: InOut<'_, '_, BatchBlocks>) { + let res = $fixslice_decrypt(&self.0.keys, blocks.get_in()); + *blocks.get_out() = res; + } + } }; } define_aes_impl!( Aes128, + Aes128Enc, + Aes128Dec, + Aes128BackEnc, + Aes128BackDec, U16, FixsliceKeys128, fixslice::aes128_key_schedule, fixslice::aes128_decrypt, fixslice::aes128_encrypt, - "AES-128 block cipher instance" + "AES-128", ); define_aes_impl!( Aes192, + Aes192Enc, + Aes192Dec, + Aes192BackEnc, + Aes192BackDec, U24, FixsliceKeys192, fixslice::aes192_key_schedule, fixslice::aes192_decrypt, fixslice::aes192_encrypt, - "AES-192 block cipher instance" + "AES-192", ); define_aes_impl!( Aes256, + Aes256Enc, + Aes256Dec, + Aes256BackEnc, + Aes256BackDec, U32, FixsliceKeys256, fixslice::aes256_key_schedule, fixslice::aes256_decrypt, fixslice::aes256_encrypt, - "AES-256 block cipher instance" + "AES-256", ); diff --git a/aes/src/soft/ctr.rs b/aes/src/soft/ctr.rs deleted file mode 100644 index a288ab11..00000000 --- a/aes/src/soft/ctr.rs +++ /dev/null @@ -1,17 +0,0 @@ -//! AES in counter mode (a.k.a. AES-CTR) - -// TODO(tarcieri): support generic CTR API - -use super::{Aes128, Aes192, Aes256}; - -/// AES-128 in CTR mode -#[cfg_attr(docsrs, doc(cfg(feature = "ctr")))] -pub type Aes128Ctr = ::ctr::Ctr64BE; - -/// AES-192 in CTR mode -#[cfg_attr(docsrs, doc(cfg(feature = "ctr")))] -pub type Aes192Ctr = ::ctr::Ctr64BE; - -/// AES-256 in CTR mode -#[cfg_attr(docsrs, doc(cfg(feature = "ctr")))] -pub type Aes256Ctr = ::ctr::Ctr64BE; diff --git a/aes/src/soft/fixslice32.rs b/aes/src/soft/fixslice32.rs index 5dc4834b..45b674d6 100644 --- a/aes/src/soft/fixslice32.rs +++ b/aes/src/soft/fixslice32.rs @@ -16,14 +16,12 @@ #![allow(clippy::unreadable_literal)] use crate::Block; -use cipher::{ - consts::{U16, U24, U32}, - generic_array::GenericArray, -}; -use core::convert::TryInto; +use cipher::{consts::U2, generic_array::GenericArray}; /// AES block batch size for this implementation -pub(crate) const FIXSLICE_BLOCKS: usize = 2; +pub(crate) type FixsliceBlocks = U2; + +pub(crate) type BatchBlocks = GenericArray; /// AES-128 round keys pub(crate) type FixsliceKeys128 = [u32; 88]; @@ -38,7 +36,7 @@ pub(crate) type FixsliceKeys256 = [u32; 120]; pub(crate) type State = [u32; 8]; /// Fully bitsliced AES-128 key schedule to match the fully-fixsliced representation. -pub(crate) fn aes128_key_schedule(key: &GenericArray) -> FixsliceKeys128 { +pub(crate) fn aes128_key_schedule(key: &[u8; 16]) -> FixsliceKeys128 { let mut rkeys = [0u32; 88]; bitslice(&mut rkeys[..8], key, key); @@ -64,13 +62,13 @@ pub(crate) fn aes128_key_schedule(key: &GenericArray) -> FixsliceKeys12 } // Adjust to match fixslicing format - #[cfg(feature = "compact")] + #[cfg(aes_compact)] { for i in (8..88).step_by(16) { inv_shift_rows_1(&mut rkeys[i..(i + 8)]); } } - #[cfg(not(feature = "compact"))] + #[cfg(not(aes_compact))] { for i in (8..72).step_by(32) { inv_shift_rows_1(&mut rkeys[i..(i + 8)]); @@ -89,7 +87,7 @@ pub(crate) fn aes128_key_schedule(key: &GenericArray) -> FixsliceKeys12 } /// Fully bitsliced AES-192 key schedule to match the fully-fixsliced representation. -pub(crate) fn aes192_key_schedule(key: &GenericArray) -> FixsliceKeys192 { +pub(crate) fn aes192_key_schedule(key: &[u8; 24]) -> FixsliceKeys192 { let mut rkeys = [0u32; 104]; let mut tmp = [0u32; 8]; @@ -159,13 +157,13 @@ pub(crate) fn aes192_key_schedule(key: &GenericArray) -> FixsliceKeys19 } // Adjust to match fixslicing format - #[cfg(feature = "compact")] + #[cfg(aes_compact)] { for i in (8..104).step_by(16) { inv_shift_rows_1(&mut rkeys[i..(i + 8)]); } } - #[cfg(not(feature = "compact"))] + #[cfg(not(aes_compact))] { for i in (0..96).step_by(32) { inv_shift_rows_1(&mut rkeys[(i + 8)..(i + 16)]); @@ -183,7 +181,7 @@ pub(crate) fn aes192_key_schedule(key: &GenericArray) -> FixsliceKeys19 } /// Fully bitsliced AES-256 key schedule to match the fully-fixsliced representation. -pub(crate) fn aes256_key_schedule(key: &GenericArray) -> FixsliceKeys256 { +pub(crate) fn aes256_key_schedule(key: &[u8; 32]) -> FixsliceKeys256 { let mut rkeys = [0u32; 120]; bitslice(&mut rkeys[..8], &key[..16], &key[..16]); @@ -217,13 +215,13 @@ pub(crate) fn aes256_key_schedule(key: &GenericArray) -> FixsliceKeys25 } // Adjust to match fixslicing format - #[cfg(feature = "compact")] + #[cfg(aes_compact)] { for i in (8..120).step_by(16) { inv_shift_rows_1(&mut rkeys[i..(i + 8)]); } } - #[cfg(not(feature = "compact"))] + #[cfg(not(aes_compact))] { for i in (8..104).step_by(32) { inv_shift_rows_1(&mut rkeys[i..(i + 8)]); @@ -244,8 +242,7 @@ pub(crate) fn aes256_key_schedule(key: &GenericArray) -> FixsliceKeys25 /// Fully-fixsliced AES-128 decryption (the InvShiftRows is completely omitted). /// /// Decrypts four blocks in-place and in parallel. -pub(crate) fn aes128_decrypt(rkeys: &FixsliceKeys128, blocks: &mut [Block]) { - debug_assert_eq!(blocks.len(), FIXSLICE_BLOCKS); +pub(crate) fn aes128_decrypt(rkeys: &FixsliceKeys128, blocks: &BatchBlocks) -> BatchBlocks { let mut state = State::default(); bitslice(&mut state, &blocks[0], &blocks[1]); @@ -253,14 +250,14 @@ pub(crate) fn aes128_decrypt(rkeys: &FixsliceKeys128, blocks: &mut [Block]) { add_round_key(&mut state, &rkeys[80..]); inv_sub_bytes(&mut state); - #[cfg(not(feature = "compact"))] + #[cfg(not(aes_compact))] { inv_shift_rows_2(&mut state); } let mut rk_off = 72; loop { - #[cfg(feature = "compact")] + #[cfg(aes_compact)] { inv_shift_rows_2(&mut state); } @@ -279,7 +276,7 @@ pub(crate) fn aes128_decrypt(rkeys: &FixsliceKeys128, blocks: &mut [Block]) { inv_sub_bytes(&mut state); rk_off -= 8; - #[cfg(not(feature = "compact"))] + #[cfg(not(aes_compact))] { add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); inv_mix_columns_3(&mut state); @@ -295,14 +292,13 @@ pub(crate) fn aes128_decrypt(rkeys: &FixsliceKeys128, blocks: &mut [Block]) { add_round_key(&mut state, &rkeys[..8]); - inv_bitslice(&state, blocks); + inv_bitslice(&state) } /// Fully-fixsliced AES-128 encryption (the ShiftRows is completely omitted). /// /// Encrypts four blocks in-place and in parallel. -pub(crate) fn aes128_encrypt(rkeys: &FixsliceKeys128, blocks: &mut [Block]) { - debug_assert_eq!(blocks.len(), FIXSLICE_BLOCKS); +pub(crate) fn aes128_encrypt(rkeys: &FixsliceKeys128, blocks: &BatchBlocks) -> BatchBlocks { let mut state = State::default(); bitslice(&mut state, &blocks[0], &blocks[1]); @@ -316,7 +312,7 @@ pub(crate) fn aes128_encrypt(rkeys: &FixsliceKeys128, blocks: &mut [Block]) { add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); rk_off += 8; - #[cfg(feature = "compact")] + #[cfg(aes_compact)] { shift_rows_2(&mut state); } @@ -325,7 +321,7 @@ pub(crate) fn aes128_encrypt(rkeys: &FixsliceKeys128, blocks: &mut [Block]) { break; } - #[cfg(not(feature = "compact"))] + #[cfg(not(aes_compact))] { sub_bytes(&mut state); mix_columns_2(&mut state); @@ -344,7 +340,7 @@ pub(crate) fn aes128_encrypt(rkeys: &FixsliceKeys128, blocks: &mut [Block]) { rk_off += 8; } - #[cfg(not(feature = "compact"))] + #[cfg(not(aes_compact))] { shift_rows_2(&mut state); } @@ -352,14 +348,13 @@ pub(crate) fn aes128_encrypt(rkeys: &FixsliceKeys128, blocks: &mut [Block]) { sub_bytes(&mut state); add_round_key(&mut state, &rkeys[80..]); - inv_bitslice(&state, blocks); + inv_bitslice(&state) } /// Fully-fixsliced AES-192 decryption (the InvShiftRows is completely omitted). /// /// Decrypts four blocks in-place and in parallel. -pub(crate) fn aes192_decrypt(rkeys: &FixsliceKeys192, blocks: &mut [Block]) { - debug_assert_eq!(blocks.len(), FIXSLICE_BLOCKS); +pub(crate) fn aes192_decrypt(rkeys: &FixsliceKeys192, blocks: &BatchBlocks) -> BatchBlocks { let mut state = State::default(); bitslice(&mut state, &blocks[0], &blocks[1]); @@ -369,11 +364,11 @@ pub(crate) fn aes192_decrypt(rkeys: &FixsliceKeys192, blocks: &mut [Block]) { let mut rk_off = 88; loop { - #[cfg(feature = "compact")] + #[cfg(aes_compact)] { inv_shift_rows_2(&mut state); } - #[cfg(not(feature = "compact"))] + #[cfg(not(aes_compact))] { add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); inv_mix_columns_3(&mut state); @@ -403,14 +398,13 @@ pub(crate) fn aes192_decrypt(rkeys: &FixsliceKeys192, blocks: &mut [Block]) { add_round_key(&mut state, &rkeys[..8]); - inv_bitslice(&state, blocks); + inv_bitslice(&state) } /// Fully-fixsliced AES-192 encryption (the ShiftRows is completely omitted). /// /// Encrypts four blocks in-place and in parallel. -pub(crate) fn aes192_encrypt(rkeys: &FixsliceKeys192, blocks: &mut [Block]) { - debug_assert_eq!(blocks.len(), FIXSLICE_BLOCKS); +pub(crate) fn aes192_encrypt(rkeys: &FixsliceKeys192, blocks: &BatchBlocks) -> BatchBlocks { let mut state = State::default(); bitslice(&mut state, &blocks[0], &blocks[1]); @@ -424,11 +418,11 @@ pub(crate) fn aes192_encrypt(rkeys: &FixsliceKeys192, blocks: &mut [Block]) { add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); rk_off += 8; - #[cfg(feature = "compact")] + #[cfg(aes_compact)] { shift_rows_2(&mut state); } - #[cfg(not(feature = "compact"))] + #[cfg(not(aes_compact))] { sub_bytes(&mut state); mix_columns_2(&mut state); @@ -454,14 +448,13 @@ pub(crate) fn aes192_encrypt(rkeys: &FixsliceKeys192, blocks: &mut [Block]) { sub_bytes(&mut state); add_round_key(&mut state, &rkeys[96..]); - inv_bitslice(&state, blocks); + inv_bitslice(&state) } /// Fully-fixsliced AES-256 decryption (the InvShiftRows is completely omitted). /// /// Decrypts four blocks in-place and in parallel. -pub(crate) fn aes256_decrypt(rkeys: &FixsliceKeys256, blocks: &mut [Block]) { - debug_assert_eq!(blocks.len(), FIXSLICE_BLOCKS); +pub(crate) fn aes256_decrypt(rkeys: &FixsliceKeys256, blocks: &BatchBlocks) -> BatchBlocks { let mut state = State::default(); bitslice(&mut state, &blocks[0], &blocks[1]); @@ -469,14 +462,14 @@ pub(crate) fn aes256_decrypt(rkeys: &FixsliceKeys256, blocks: &mut [Block]) { add_round_key(&mut state, &rkeys[112..]); inv_sub_bytes(&mut state); - #[cfg(not(feature = "compact"))] + #[cfg(not(aes_compact))] { inv_shift_rows_2(&mut state); } let mut rk_off = 104; loop { - #[cfg(feature = "compact")] + #[cfg(aes_compact)] { inv_shift_rows_2(&mut state); } @@ -495,7 +488,7 @@ pub(crate) fn aes256_decrypt(rkeys: &FixsliceKeys256, blocks: &mut [Block]) { inv_sub_bytes(&mut state); rk_off -= 8; - #[cfg(not(feature = "compact"))] + #[cfg(not(aes_compact))] { add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); inv_mix_columns_3(&mut state); @@ -511,14 +504,13 @@ pub(crate) fn aes256_decrypt(rkeys: &FixsliceKeys256, blocks: &mut [Block]) { add_round_key(&mut state, &rkeys[..8]); - inv_bitslice(&state, blocks); + inv_bitslice(&state) } /// Fully-fixsliced AES-256 encryption (the ShiftRows is completely omitted). /// /// Encrypts four blocks in-place and in parallel. -pub(crate) fn aes256_encrypt(rkeys: &FixsliceKeys256, blocks: &mut [Block]) { - debug_assert_eq!(blocks.len(), FIXSLICE_BLOCKS); +pub(crate) fn aes256_encrypt(rkeys: &FixsliceKeys256, blocks: &BatchBlocks) -> BatchBlocks { let mut state = State::default(); bitslice(&mut state, &blocks[0], &blocks[1]); @@ -532,7 +524,7 @@ pub(crate) fn aes256_encrypt(rkeys: &FixsliceKeys256, blocks: &mut [Block]) { add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); rk_off += 8; - #[cfg(feature = "compact")] + #[cfg(aes_compact)] { shift_rows_2(&mut state); } @@ -541,7 +533,7 @@ pub(crate) fn aes256_encrypt(rkeys: &FixsliceKeys256, blocks: &mut [Block]) { break; } - #[cfg(not(feature = "compact"))] + #[cfg(not(aes_compact))] { sub_bytes(&mut state); mix_columns_2(&mut state); @@ -560,7 +552,7 @@ pub(crate) fn aes256_encrypt(rkeys: &FixsliceKeys256, blocks: &mut [Block]) { rk_off += 8; } - #[cfg(not(feature = "compact"))] + #[cfg(not(aes_compact))] { shift_rows_2(&mut state); } @@ -568,7 +560,7 @@ pub(crate) fn aes256_encrypt(rkeys: &FixsliceKeys256, blocks: &mut [Block]) { sub_bytes(&mut state); add_round_key(&mut state, &rkeys[112..]); - inv_bitslice(&state, blocks); + inv_bitslice(&state) } /// Note that the 4 bitwise NOT (^= 0xffffffff) are accounted for here so that it is a true @@ -1080,7 +1072,7 @@ define_mix_columns!( rotate_rows_and_columns_2_2 ); -#[cfg(not(feature = "compact"))] +#[cfg(not(aes_compact))] define_mix_columns!( mix_columns_2, inv_mix_columns_2, @@ -1088,7 +1080,7 @@ define_mix_columns!( rotate_rows_2 ); -#[cfg(not(feature = "compact"))] +#[cfg(not(aes_compact))] define_mix_columns!( mix_columns_3, inv_mix_columns_3, @@ -1110,7 +1102,7 @@ fn delta_swap_2(a: &mut u32, b: &mut u32, shift: u32, mask: u32) { } /// Applies ShiftRows once on an AES state (or key). -#[cfg(any(not(feature = "compact"), feature = "hazmat"))] +#[cfg(any(not(aes_compact), feature = "hazmat"))] #[inline] fn shift_rows_1(state: &mut [u32]) { debug_assert_eq!(state.len(), 8); @@ -1149,7 +1141,7 @@ fn inv_shift_rows_2(state: &mut [u32]) { shift_rows_2(state); } -#[cfg(not(feature = "compact"))] +#[cfg(not(aes_compact))] #[inline(always)] fn inv_shift_rows_3(state: &mut [u32]) { shift_rows_1(state); @@ -1234,9 +1226,8 @@ fn bitslice(output: &mut [u32], input0: &[u8], input1: &[u8]) { } /// Un-bitslice a 256-bit internal state into two 128-bit blocks of output. -fn inv_bitslice(input: &[u32], output: &mut [Block]) { +fn inv_bitslice(input: &[u32]) -> BatchBlocks { debug_assert_eq!(input.len(), 8); - debug_assert_eq!(output.len(), 2); // Unbitslicing is a bit index manipulation. 256 bits of data means each bit is positioned at // an 8-bit index. AES data is 2 blocks, each one a 4x4 column-major matrix of bytes, so the @@ -1281,6 +1272,7 @@ fn inv_bitslice(input: &[u32], output: &mut [Block]) { delta_swap_2(&mut t6, &mut t2, 4, m2); delta_swap_2(&mut t7, &mut t3, 4, m2); + let mut output = BatchBlocks::default(); // De-interleave the columns on output (note the order of output) // c1 c0 b0 __ __ __ __ __ => b0 c1 c0 __ __ __ __ __ output[0][0x00..0x04].copy_from_slice(&t0.to_le_bytes()); @@ -1294,6 +1286,7 @@ fn inv_bitslice(input: &[u32], output: &mut [Block]) { // Final AES bit index, as desired: // b0 c1 c0 r1 r0 p2 p1 p0 + output } /// Copy 32-bytes within the provided slice to an 8-byte offset @@ -1350,7 +1343,7 @@ fn rotate_rows_and_columns_1_1(x: u32) -> u32 { (ror(x, ror_distance(0, 1)) & 0xc0c0c0c0) } -#[cfg(not(feature = "compact"))] +#[cfg(not(aes_compact))] #[inline(always)] #[rustfmt::skip] fn rotate_rows_and_columns_1_2(x: u32) -> u32 { @@ -1358,7 +1351,7 @@ fn rotate_rows_and_columns_1_2(x: u32) -> u32 { (ror(x, ror_distance(0, 2)) & 0xf0f0f0f0) } -#[cfg(not(feature = "compact"))] +#[cfg(not(aes_compact))] #[inline(always)] #[rustfmt::skip] fn rotate_rows_and_columns_1_3(x: u32) -> u32 { @@ -1384,7 +1377,7 @@ pub(crate) mod hazmat { bitslice, inv_bitslice, inv_mix_columns_0, inv_shift_rows_1, inv_sub_bytes, mix_columns_0, shift_rows_1, sub_bytes, sub_bytes_nots, State, }; - use crate::{Block, ParBlocks}; + use crate::{Block, Block8}; /// XOR the `src` block into the `dst` block in-place. fn xor_in_place(dst: &mut Block, src: &Block) { @@ -1402,8 +1395,7 @@ pub(crate) mod hazmat { /// Perform an inverse bitslice operation, extracting a single block. fn inv_bitslice_block(block: &mut Block, state: &State) { - let mut out = [Block::default(); 2]; - inv_bitslice(state, &mut out); + let out = inv_bitslice(state); block.copy_from_slice(&out[0]); } @@ -1421,7 +1413,7 @@ pub(crate) mod hazmat { /// AES cipher (encrypt) round function: parallel version. #[inline] - pub(crate) fn cipher_round_par(blocks: &mut ParBlocks, round_keys: &ParBlocks) { + pub(crate) fn cipher_round_par(blocks: &mut Block8, round_keys: &Block8) { for (chunk, keys) in blocks.chunks_exact_mut(2).zip(round_keys.chunks_exact(2)) { let mut state = State::default(); bitslice(&mut state, &chunk[0], &chunk[1]); @@ -1429,9 +1421,10 @@ pub(crate) mod hazmat { sub_bytes_nots(&mut state); shift_rows_1(&mut state); mix_columns_0(&mut state); - inv_bitslice(&state, chunk); + let res = inv_bitslice(&state); for i in 0..2 { + chunk[i] = res[i]; xor_in_place(&mut chunk[i], &keys[i]); } } @@ -1451,7 +1444,7 @@ pub(crate) mod hazmat { /// AES cipher (encrypt) round function: parallel version. #[inline] - pub(crate) fn equiv_inv_cipher_round_par(blocks: &mut ParBlocks, round_keys: &ParBlocks) { + pub(crate) fn equiv_inv_cipher_round_par(blocks: &mut Block8, round_keys: &Block8) { for (chunk, keys) in blocks.chunks_exact_mut(2).zip(round_keys.chunks_exact(2)) { let mut state = State::default(); bitslice(&mut state, &chunk[0], &chunk[1]); @@ -1459,9 +1452,10 @@ pub(crate) mod hazmat { inv_sub_bytes(&mut state); inv_shift_rows_1(&mut state); inv_mix_columns_0(&mut state); - inv_bitslice(&state, chunk); + let res = inv_bitslice(&state); for i in 0..2 { + chunk[i] = res[i]; xor_in_place(&mut chunk[i], &keys[i]); } } diff --git a/aes/src/soft/fixslice64.rs b/aes/src/soft/fixslice64.rs index 18315b77..09dbcbe9 100644 --- a/aes/src/soft/fixslice64.rs +++ b/aes/src/soft/fixslice64.rs @@ -16,13 +16,12 @@ #![allow(clippy::unreadable_literal)] use crate::Block; -use cipher::{ - consts::{U16, U24, U32}, - generic_array::GenericArray, -}; +use cipher::{consts::U4, generic_array::GenericArray}; /// AES block batch size for this implementation -pub(crate) const FIXSLICE_BLOCKS: usize = 4; +pub(crate) type FixsliceBlocks = U4; + +pub(crate) type BatchBlocks = GenericArray; /// AES-128 round keys pub(crate) type FixsliceKeys128 = [u64; 88]; @@ -37,7 +36,7 @@ pub(crate) type FixsliceKeys256 = [u64; 120]; pub(crate) type State = [u64; 8]; /// Fully bitsliced AES-128 key schedule to match the fully-fixsliced representation. -pub(crate) fn aes128_key_schedule(key: &GenericArray) -> FixsliceKeys128 { +pub(crate) fn aes128_key_schedule(key: &[u8; 16]) -> FixsliceKeys128 { let mut rkeys = [0u64; 88]; bitslice(&mut rkeys[..8], key, key, key, key); @@ -63,13 +62,13 @@ pub(crate) fn aes128_key_schedule(key: &GenericArray) -> FixsliceKeys12 } // Adjust to match fixslicing format - #[cfg(feature = "compact")] + #[cfg(aes_compact)] { for i in (8..88).step_by(16) { inv_shift_rows_1(&mut rkeys[i..(i + 8)]); } } - #[cfg(not(feature = "compact"))] + #[cfg(not(aes_compact))] { for i in (8..72).step_by(32) { inv_shift_rows_1(&mut rkeys[i..(i + 8)]); @@ -88,7 +87,7 @@ pub(crate) fn aes128_key_schedule(key: &GenericArray) -> FixsliceKeys12 } /// Fully bitsliced AES-192 key schedule to match the fully-fixsliced representation. -pub(crate) fn aes192_key_schedule(key: &GenericArray) -> FixsliceKeys192 { +pub(crate) fn aes192_key_schedule(key: &[u8; 24]) -> FixsliceKeys192 { let mut rkeys = [0u64; 104]; let mut tmp = [0u64; 8]; @@ -169,13 +168,13 @@ pub(crate) fn aes192_key_schedule(key: &GenericArray) -> FixsliceKeys19 } // Adjust to match fixslicing format - #[cfg(feature = "compact")] + #[cfg(aes_compact)] { for i in (8..104).step_by(16) { inv_shift_rows_1(&mut rkeys[i..(i + 8)]); } } - #[cfg(not(feature = "compact"))] + #[cfg(not(aes_compact))] { for i in (0..96).step_by(32) { inv_shift_rows_1(&mut rkeys[(i + 8)..(i + 16)]); @@ -193,7 +192,7 @@ pub(crate) fn aes192_key_schedule(key: &GenericArray) -> FixsliceKeys19 } /// Fully bitsliced AES-256 key schedule to match the fully-fixsliced representation. -pub(crate) fn aes256_key_schedule(key: &GenericArray) -> FixsliceKeys256 { +pub(crate) fn aes256_key_schedule(key: &[u8; 32]) -> FixsliceKeys256 { let mut rkeys = [0u64; 120]; bitslice( @@ -239,13 +238,13 @@ pub(crate) fn aes256_key_schedule(key: &GenericArray) -> FixsliceKeys25 } // Adjust to match fixslicing format - #[cfg(feature = "compact")] + #[cfg(aes_compact)] { for i in (8..120).step_by(16) { inv_shift_rows_1(&mut rkeys[i..(i + 8)]); } } - #[cfg(not(feature = "compact"))] + #[cfg(not(aes_compact))] { for i in (8..104).step_by(32) { inv_shift_rows_1(&mut rkeys[i..(i + 8)]); @@ -266,8 +265,7 @@ pub(crate) fn aes256_key_schedule(key: &GenericArray) -> FixsliceKeys25 /// Fully-fixsliced AES-128 decryption (the InvShiftRows is completely omitted). /// /// Decrypts four blocks in-place and in parallel. -pub(crate) fn aes128_decrypt(rkeys: &FixsliceKeys128, blocks: &mut [Block]) { - debug_assert_eq!(blocks.len(), FIXSLICE_BLOCKS); +pub(crate) fn aes128_decrypt(rkeys: &FixsliceKeys128, blocks: &BatchBlocks) -> BatchBlocks { let mut state = State::default(); bitslice(&mut state, &blocks[0], &blocks[1], &blocks[2], &blocks[3]); @@ -275,14 +273,14 @@ pub(crate) fn aes128_decrypt(rkeys: &FixsliceKeys128, blocks: &mut [Block]) { add_round_key(&mut state, &rkeys[80..]); inv_sub_bytes(&mut state); - #[cfg(not(feature = "compact"))] + #[cfg(not(aes_compact))] { inv_shift_rows_2(&mut state); } let mut rk_off = 72; loop { - #[cfg(feature = "compact")] + #[cfg(aes_compact)] { inv_shift_rows_2(&mut state); } @@ -301,7 +299,7 @@ pub(crate) fn aes128_decrypt(rkeys: &FixsliceKeys128, blocks: &mut [Block]) { inv_sub_bytes(&mut state); rk_off -= 8; - #[cfg(not(feature = "compact"))] + #[cfg(not(aes_compact))] { add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); inv_mix_columns_3(&mut state); @@ -317,14 +315,13 @@ pub(crate) fn aes128_decrypt(rkeys: &FixsliceKeys128, blocks: &mut [Block]) { add_round_key(&mut state, &rkeys[..8]); - inv_bitslice(&state, blocks); + inv_bitslice(&state) } /// Fully-fixsliced AES-128 encryption (the ShiftRows is completely omitted). /// /// Encrypts four blocks in-place and in parallel. -pub(crate) fn aes128_encrypt(rkeys: &FixsliceKeys128, blocks: &mut [Block]) { - debug_assert_eq!(blocks.len(), FIXSLICE_BLOCKS); +pub(crate) fn aes128_encrypt(rkeys: &FixsliceKeys128, blocks: &BatchBlocks) -> BatchBlocks { let mut state = State::default(); bitslice(&mut state, &blocks[0], &blocks[1], &blocks[2], &blocks[3]); @@ -338,7 +335,7 @@ pub(crate) fn aes128_encrypt(rkeys: &FixsliceKeys128, blocks: &mut [Block]) { add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); rk_off += 8; - #[cfg(feature = "compact")] + #[cfg(aes_compact)] { shift_rows_2(&mut state); } @@ -347,7 +344,7 @@ pub(crate) fn aes128_encrypt(rkeys: &FixsliceKeys128, blocks: &mut [Block]) { break; } - #[cfg(not(feature = "compact"))] + #[cfg(not(aes_compact))] { sub_bytes(&mut state); mix_columns_2(&mut state); @@ -366,7 +363,7 @@ pub(crate) fn aes128_encrypt(rkeys: &FixsliceKeys128, blocks: &mut [Block]) { rk_off += 8; } - #[cfg(not(feature = "compact"))] + #[cfg(not(aes_compact))] { shift_rows_2(&mut state); } @@ -374,14 +371,13 @@ pub(crate) fn aes128_encrypt(rkeys: &FixsliceKeys128, blocks: &mut [Block]) { sub_bytes(&mut state); add_round_key(&mut state, &rkeys[80..]); - inv_bitslice(&state, blocks); + inv_bitslice(&state) } /// Fully-fixsliced AES-192 decryption (the InvShiftRows is completely omitted). /// /// Decrypts four blocks in-place and in parallel. -pub(crate) fn aes192_decrypt(rkeys: &FixsliceKeys192, blocks: &mut [Block]) { - debug_assert_eq!(blocks.len(), FIXSLICE_BLOCKS); +pub(crate) fn aes192_decrypt(rkeys: &FixsliceKeys192, blocks: &BatchBlocks) -> BatchBlocks { let mut state = State::default(); bitslice(&mut state, &blocks[0], &blocks[1], &blocks[2], &blocks[3]); @@ -391,11 +387,11 @@ pub(crate) fn aes192_decrypt(rkeys: &FixsliceKeys192, blocks: &mut [Block]) { let mut rk_off = 88; loop { - #[cfg(feature = "compact")] + #[cfg(aes_compact)] { inv_shift_rows_2(&mut state); } - #[cfg(not(feature = "compact"))] + #[cfg(not(aes_compact))] { add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); inv_mix_columns_3(&mut state); @@ -425,14 +421,13 @@ pub(crate) fn aes192_decrypt(rkeys: &FixsliceKeys192, blocks: &mut [Block]) { add_round_key(&mut state, &rkeys[..8]); - inv_bitslice(&state, blocks); + inv_bitslice(&state) } /// Fully-fixsliced AES-192 encryption (the ShiftRows is completely omitted). /// /// Encrypts four blocks in-place and in parallel. -pub(crate) fn aes192_encrypt(rkeys: &FixsliceKeys192, blocks: &mut [Block]) { - debug_assert_eq!(blocks.len(), FIXSLICE_BLOCKS); +pub(crate) fn aes192_encrypt(rkeys: &FixsliceKeys192, blocks: &BatchBlocks) -> BatchBlocks { let mut state = State::default(); bitslice(&mut state, &blocks[0], &blocks[1], &blocks[2], &blocks[3]); @@ -446,11 +441,11 @@ pub(crate) fn aes192_encrypt(rkeys: &FixsliceKeys192, blocks: &mut [Block]) { add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); rk_off += 8; - #[cfg(feature = "compact")] + #[cfg(aes_compact)] { shift_rows_2(&mut state); } - #[cfg(not(feature = "compact"))] + #[cfg(not(aes_compact))] { sub_bytes(&mut state); mix_columns_2(&mut state); @@ -476,14 +471,13 @@ pub(crate) fn aes192_encrypt(rkeys: &FixsliceKeys192, blocks: &mut [Block]) { sub_bytes(&mut state); add_round_key(&mut state, &rkeys[96..]); - inv_bitslice(&state, blocks); + inv_bitslice(&state) } /// Fully-fixsliced AES-256 decryption (the InvShiftRows is completely omitted). /// /// Decrypts four blocks in-place and in parallel. -pub(crate) fn aes256_decrypt(rkeys: &FixsliceKeys256, blocks: &mut [Block]) { - debug_assert_eq!(blocks.len(), FIXSLICE_BLOCKS); +pub(crate) fn aes256_decrypt(rkeys: &FixsliceKeys256, blocks: &BatchBlocks) -> BatchBlocks { let mut state = State::default(); bitslice(&mut state, &blocks[0], &blocks[1], &blocks[2], &blocks[3]); @@ -491,14 +485,14 @@ pub(crate) fn aes256_decrypt(rkeys: &FixsliceKeys256, blocks: &mut [Block]) { add_round_key(&mut state, &rkeys[112..]); inv_sub_bytes(&mut state); - #[cfg(not(feature = "compact"))] + #[cfg(not(aes_compact))] { inv_shift_rows_2(&mut state); } let mut rk_off = 104; loop { - #[cfg(feature = "compact")] + #[cfg(aes_compact)] { inv_shift_rows_2(&mut state); } @@ -517,7 +511,7 @@ pub(crate) fn aes256_decrypt(rkeys: &FixsliceKeys256, blocks: &mut [Block]) { inv_sub_bytes(&mut state); rk_off -= 8; - #[cfg(not(feature = "compact"))] + #[cfg(not(aes_compact))] { add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); inv_mix_columns_3(&mut state); @@ -533,14 +527,13 @@ pub(crate) fn aes256_decrypt(rkeys: &FixsliceKeys256, blocks: &mut [Block]) { add_round_key(&mut state, &rkeys[..8]); - inv_bitslice(&state, blocks); + inv_bitslice(&state) } /// Fully-fixsliced AES-256 encryption (the ShiftRows is completely omitted). /// /// Encrypts four blocks in-place and in parallel. -pub(crate) fn aes256_encrypt(rkeys: &FixsliceKeys256, blocks: &mut [Block]) { - debug_assert_eq!(blocks.len(), FIXSLICE_BLOCKS); +pub(crate) fn aes256_encrypt(rkeys: &FixsliceKeys256, blocks: &BatchBlocks) -> BatchBlocks { let mut state = State::default(); bitslice(&mut state, &blocks[0], &blocks[1], &blocks[2], &blocks[3]); @@ -554,7 +547,7 @@ pub(crate) fn aes256_encrypt(rkeys: &FixsliceKeys256, blocks: &mut [Block]) { add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); rk_off += 8; - #[cfg(feature = "compact")] + #[cfg(aes_compact)] { shift_rows_2(&mut state); } @@ -563,7 +556,7 @@ pub(crate) fn aes256_encrypt(rkeys: &FixsliceKeys256, blocks: &mut [Block]) { break; } - #[cfg(not(feature = "compact"))] + #[cfg(not(aes_compact))] { sub_bytes(&mut state); mix_columns_2(&mut state); @@ -582,7 +575,7 @@ pub(crate) fn aes256_encrypt(rkeys: &FixsliceKeys256, blocks: &mut [Block]) { rk_off += 8; } - #[cfg(not(feature = "compact"))] + #[cfg(not(aes_compact))] { shift_rows_2(&mut state); } @@ -590,7 +583,7 @@ pub(crate) fn aes256_encrypt(rkeys: &FixsliceKeys256, blocks: &mut [Block]) { sub_bytes(&mut state); add_round_key(&mut state, &rkeys[112..]); - inv_bitslice(&state, blocks); + inv_bitslice(&state) } /// Note that the 4 bitwise NOT (^= 0xffffffffffffffff) are accounted for here so that it is a true @@ -1102,7 +1095,7 @@ define_mix_columns!( rotate_rows_and_columns_2_2 ); -#[cfg(not(feature = "compact"))] +#[cfg(not(aes_compact))] define_mix_columns!( mix_columns_2, inv_mix_columns_2, @@ -1110,7 +1103,7 @@ define_mix_columns!( rotate_rows_2 ); -#[cfg(not(feature = "compact"))] +#[cfg(not(aes_compact))] define_mix_columns!( mix_columns_3, inv_mix_columns_3, @@ -1132,7 +1125,7 @@ fn delta_swap_2(a: &mut u64, b: &mut u64, shift: u32, mask: u64) { } /// Applies ShiftRows once on an AES state (or key). -#[cfg(any(not(feature = "compact"), feature = "hazmat"))] +#[cfg(any(not(aes_compact), feature = "hazmat"))] #[inline] fn shift_rows_1(state: &mut [u64]) { debug_assert_eq!(state.len(), 8); @@ -1171,7 +1164,7 @@ fn inv_shift_rows_2(state: &mut [u64]) { shift_rows_2(state); } -#[cfg(not(feature = "compact"))] +#[cfg(not(aes_compact))] #[inline(always)] fn inv_shift_rows_3(state: &mut [u64]) { shift_rows_1(state); @@ -1274,9 +1267,8 @@ fn bitslice(output: &mut [u64], input0: &[u8], input1: &[u8], input2: &[u8], inp } /// Un-bitslice a 512-bit internal state into four 128-bit blocks of output. -fn inv_bitslice(input: &[u64], output: &mut [Block]) { +fn inv_bitslice(input: &[u64]) -> BatchBlocks { debug_assert_eq!(input.len(), 8); - debug_assert_eq!(output.len(), 4); // Unbitslicing is a bit index manipulation. 512 bits of data means each bit is positioned at // a 9-bit index. AES data is 4 blocks, each one a 4x4 column-major matrix of bytes, so the @@ -1333,6 +1325,7 @@ fn inv_bitslice(input: &[u64], output: &mut [Block]) { output[0xb] = (columns >> 0x38) as u8; } + let mut output = BatchBlocks::default(); // Reorder by relabeling (note the order of output) // c0 b1 b0 __ __ __ __ __ __ => b1 b0 c0 __ __ __ __ __ __ // Reorder each block's bytes on output @@ -1348,6 +1341,7 @@ fn inv_bitslice(input: &[u64], output: &mut [Block]) { // Final AES bit index, as desired: // b1 b0 c1 c0 r1 r0 p2 p1 p0 + output } /// Copy 32-bytes within the provided slice to an 8-byte offset @@ -1404,7 +1398,7 @@ fn rotate_rows_and_columns_1_1(x: u64) -> u64 { (ror(x, ror_distance(0, 1)) & 0xf000f000f000f000) } -#[cfg(not(feature = "compact"))] +#[cfg(not(aes_compact))] #[inline(always)] #[rustfmt::skip] fn rotate_rows_and_columns_1_2(x: u64) -> u64 { @@ -1412,7 +1406,7 @@ fn rotate_rows_and_columns_1_2(x: u64) -> u64 { (ror(x, ror_distance(0, 2)) & 0xff00ff00ff00ff00) } -#[cfg(not(feature = "compact"))] +#[cfg(not(aes_compact))] #[inline(always)] #[rustfmt::skip] fn rotate_rows_and_columns_1_3(x: u64) -> u64 { @@ -1438,7 +1432,7 @@ pub(crate) mod hazmat { bitslice, inv_bitslice, inv_mix_columns_0, inv_shift_rows_1, inv_sub_bytes, mix_columns_0, shift_rows_1, sub_bytes, sub_bytes_nots, State, }; - use crate::{Block, ParBlocks}; + use crate::{Block, Block8}; /// XOR the `src` block into the `dst` block in-place. fn xor_in_place(dst: &mut Block, src: &Block) { @@ -1456,9 +1450,7 @@ pub(crate) mod hazmat { /// Perform an inverse bitslice operation, extracting a single block. fn inv_bitslice_block(block: &mut Block, state: &State) { - let mut out = [Block::default(); 4]; - inv_bitslice(state, &mut out); - block.copy_from_slice(&out[0]); + block.copy_from_slice(&inv_bitslice(state)[0]); } /// AES cipher (encrypt) round function. @@ -1475,7 +1467,7 @@ pub(crate) mod hazmat { /// AES cipher (encrypt) round function: parallel version. #[inline] - pub(crate) fn cipher_round_par(blocks: &mut ParBlocks, round_keys: &ParBlocks) { + pub(crate) fn cipher_round_par(blocks: &mut Block8, round_keys: &Block8) { for (chunk, keys) in blocks.chunks_exact_mut(4).zip(round_keys.chunks_exact(4)) { let mut state = State::default(); bitslice(&mut state, &chunk[0], &chunk[1], &chunk[2], &chunk[3]); @@ -1483,9 +1475,10 @@ pub(crate) mod hazmat { sub_bytes_nots(&mut state); shift_rows_1(&mut state); mix_columns_0(&mut state); - inv_bitslice(&state, chunk); + let res = inv_bitslice(&state); for i in 0..4 { + chunk[i] = res[i]; xor_in_place(&mut chunk[i], &keys[i]); } } @@ -1495,7 +1488,7 @@ pub(crate) mod hazmat { #[inline] pub(crate) fn equiv_inv_cipher_round(block: &mut Block, round_key: &Block) { let mut state = State::default(); - bitslice(&mut state, &block, &block, &block, &block); + bitslice(&mut state, block, block, block, block); sub_bytes_nots(&mut state); inv_sub_bytes(&mut state); inv_shift_rows_1(&mut state); @@ -1506,7 +1499,7 @@ pub(crate) mod hazmat { /// AES cipher (encrypt) round function: parallel version. #[inline] - pub(crate) fn equiv_inv_cipher_round_par(blocks: &mut ParBlocks, round_keys: &ParBlocks) { + pub(crate) fn equiv_inv_cipher_round_par(blocks: &mut Block8, round_keys: &Block8) { for (chunk, keys) in blocks.chunks_exact_mut(4).zip(round_keys.chunks_exact(4)) { let mut state = State::default(); bitslice(&mut state, &chunk[0], &chunk[1], &chunk[2], &chunk[3]); @@ -1514,9 +1507,10 @@ pub(crate) mod hazmat { inv_sub_bytes(&mut state); inv_shift_rows_1(&mut state); inv_mix_columns_0(&mut state); - inv_bitslice(&state, chunk); + let res = inv_bitslice(&state); for i in 0..4 { + chunk[i] = res[i]; xor_in_place(&mut chunk[i], &keys[i]); } } diff --git a/aes/tests/ctr.rs b/aes/tests/ctr.rs deleted file mode 100644 index 3fd3c9ef..00000000 --- a/aes/tests/ctr.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![cfg(feature = "ctr")] - -use aes::{Aes128Ctr, Aes256Ctr}; - -// Random tests generated by OpenSSL -cipher::stream_cipher_test!(aes128_ctr_core, Aes128Ctr, "aes128-ctr"); -cipher::stream_cipher_test!(aes256_ctr_core, Aes256Ctr, "aes256-ctr"); -cipher::stream_cipher_seek_test!(aes128_ctr_seek, Aes128Ctr); -cipher::stream_cipher_seek_test!(aes256_ctr_seek, Aes256Ctr); diff --git a/aes/tests/data/aes128-ctr.blb b/aes/tests/data/aes128-ctr.blb deleted file mode 100644 index d721e4ec446b1b483a24b8d09cf2f5fbab81ce22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2039 zcmVH?%aNi8yBGE*I`MX`=^z^J|NF@kJUiIX=f(q8%1gUF{hWzy^!-5oQY^tuW<U?m#sZovnrI(**apt@qOP*f4v(mR;ceUOHo>@f7=FA3RgxlzRub}+@p2SE z0uenRz+gp=VKPP zvdnETAeRe(uJ=O*0=z=k)U}c9nP|@p*zhK%NuM2u z7EpLz6#s!+94J1}_>mn8-({Ms`vs9!UkWn7E$2mzP#m`txEX-4+AiN%8UnZ^0Qc!< zMNvmTX^74|oMbb1 zN;2LiQ3u`lso$7dK*|0T6`eqNM0T<-zmL}>&^Q$pcGCNl$63Om01TYPFq&}{VY2~U zoc2D^l7OlxF9+BfcB{bo71!uf_|wzZOK}=8yF}^I8@WfjXcN4NOD-<|n8c=aIw0#L zs4Mh7>BE@PU?)-PM9{7B6oTM79ENRR50qTl4*T$&S;VyVTxin>9w~DHY^I~Be0t>* za0$Jm1DJQalt6y#0E4i?`n*yt{ECVs0y*^Ea%Dk=t4)5N-+kHa2vJ9F{pGTN9CL^Q zr{yjrus&>UH!_ME6_=-Tv>)MD>pa=X)(&72g}Nfn9zQ<-%>jZvqiH4L?6(ElSj%uOc|?^gTWK#4cV}!9N#uO*(+z zDYjqEyPO;lV`*#~x^;^`VWuTtn0R>wJ~92RJwk=9fQ`&%)3JiU&f6yXbY|!!6kjd= zBVa&XIR_ln_$Hl@QDpk2fp~=Lg<F8Ov=5OD_Y$SJTicl=>+Uu?%$;$UIR709UZ0X)N+!th^a+R@30cThRdK=jTxE6j zx|IeDuZA$*(s&miYRP}^mOvfs_Davc(=tV4@!gt%@b(DRSwgW`rn8ED=Ci6_f9F|) z678#Iyh(wGU{2VoXq7(Q|6yr&fVZ__EP9J=bLfk_$$-GYIvvZgi-*{#QaBa!=lsc+ zDPC&T;o!q0{G$c0Z>KRH1;>ilI2o?LSLr_?`Rl{iozGqq0``I7ZVTIyCjTJ}7%$n$ zYbcO*riRuX8e}>nzly%X@iigB5z=1k)&9-lV^EXZwoR!AGWPptgPrmVmSw@3?dGPJ z-9ySuW_-O0Qq4%HkbVz6ZblP$rKHZGP8}orD`fc$n%TUj4zLeD0gI)owLXxfSZH6} zwoi3`BInXV_BL3ifM;;GFm>rNZ@+|Yt=YTEQ$=)tSjqgbhs@&}XsQ~QD8;S*~OoV3rygG{dU{aG^Wa4`2%$GKz$Iu6cz z9q?DNOb7L*f%%Z;s7jv6e9NTvrB6<&1od^Au9w~cyQpWnM_WhM=z}^ z16Pg0_r&YPS%5;q*hzA{P;vEFK!bH(0T)~>k{LM$x3c+Lj?iHp;>kaX_q zfT~L-@$g;{@C!gqvX8m^IaIylJJjSZhCGRA{5oW!ap{C+>6(8%e(KkqxnyjevE=7< VYVN$AuMsq5Y*Li)97ec1(!p2h`XB%R diff --git a/aes/tests/data/aes256-ctr.blb b/aes/tests/data/aes256-ctr.blb deleted file mode 100644 index 47daaf84de9a0c16a03f2ad5c386108d2f241b62..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2055 zcmV+i2>AB^K!E|&noS)YQo+U;QkV3>&EDlaF@Zr9!lb7W61EdBf*_5O)*U?$3!~rD z@+OvSk--Ys_KU}Z@{#X$a2V%NZ8IrjqwW&=HOc`LFHiEx@4+e?}MBA0+YFA zKqA)c5fRVn!(EDcZ(i|4#LuChX82Fubg`$8i`UjI9iA?X4;RKu^d3$!0PLXdq8d!22;*tgN2RyRC z{)dnXr_W%Q`;G6~6LRn)MzdhUq4J$MIxoaqO&t4TS_DO{7`~v$$*nk_fe^^B#C_LH z#-wobS>Jjk$FOsLi?N6#QoP4R=k9#8Hxdx9v7C`V08;8W$(OBNwfSJDbf&ng;wR=@ z2Kf7yBdlY2EovSk+AT8cG0kjCK>r4;vu zbwoRJCxI;8~y40+ZAq|Z~lr*)qLLjUy4GybsI2touX({J*NcnZzDd# z9}E90$o5;gKU&fnBP~Mf7Tczul4EUU7s2c3w8vHMA_3$t#C9YzTE?YWY(&wKJ1F;% z>0c}EH&fc>)7H_IOk#^ndHjkqTgqgZq^lj7fY#J26rQ`m*Iwrn$K>o1r;#WBW zg$?oiDqRBt5kkR(f3pM05Xbr6skkiN8snYLo+D!+Ez4gESWd~Y&9P`>KU;4U>uShd zG9#ZuijqN;tcE}@-ZHOk-gy}P_5ny#sBJ0Hp{EsHhmy=1M^ozRno1J8bT`NEy{xp~ zB4NLv%RfI5sE#-LM+MZn;<5Lpj!?2T5@kjYzY-?W=yWhKE|3Ik(bL{J=xsCG0TdqU zKBQIs1jp}GtoboN-3QnfkpI*x`euPFvC_)AaS@Cq+!gEUOY|e&Rq5U97#Tb4`9@p~ zN6C>#cEx}Yt_E~kT~`^9+P*tS&;npOIKd?|4NofQneHhXrrH#qqFT9I#Aa!Xf!{ic zX}hB0nthLBf`qbCzn{_UCC~Uy!M$MDpOb zRnl>jS#I1H2VrFGMpM$>yU|XcCwkC7-Eq-dgu+rd*UMk+wath-vxh24!3)x7!@6{p z2vis=i{^|w;GMwBR9&+Gt4@J;GP{8 z;p6a`eALC*tu{g>xT4SOXJ(mLp*Y*Jbdg9)y~JMj`_CmNMq{!j#n8tk}Kd@55}f=RipoI53OdD52-(OS}Eq!%pnU zfwAs|^eMJmFa2KLgOY*FTiv;NcFV{rA4Y`+Iksp~9Wurivh_toMTk_4LZ{v04Z2GF z%nO>;nAeu`%lmiN*eAt%p;)4*$|X!`s|oxqt7!SLRffE#luZZ+H)UjL`dB&6BMf@u zQ#Rv6Cay!h=h}_W^BiNVV?B36q}`}=sU4l|Z61-J4M6;0+a-~&IEa^uF)WW6&2;;i zWj0Qa*cN-k6g^8zmC$z1E!_3gZ3=~~M|Ls$v3bYpLhQ0HHHH&`wd)m#h7`4;*O_FS z69S{A7sz!?D-&y@{)rv>I9CkdVGul6N1!&x#y8o)7G@LBf`kPZtE8Mf0fKS~H3p<# zKlFU>=zUQ*eRkGwMJi@SFB{mrILlJd^DyhW@`cDjNQqqjZx;~15q#z=A~3jY8A diff --git a/aes/tests/hazmat.rs b/aes/tests/hazmat.rs index 16b98e63..ce0e8f82 100644 --- a/aes/tests/hazmat.rs +++ b/aes/tests/hazmat.rs @@ -3,7 +3,7 @@ // TODO(tarcieri): support for using the hazmat functions with the `soft` backend #![cfg(feature = "hazmat")] -use aes::{Block, ParBlocks}; +use aes::{Block, Block8}; use hex_literal::hex; /// Round function tests vectors. @@ -85,8 +85,8 @@ fn cipher_round_fips197_vectors() { #[test] fn cipher_round_par_fips197_vectors() { - let mut blocks = ParBlocks::default(); - let mut round_keys = ParBlocks::default(); + let mut blocks = Block8::default(); + let mut round_keys = Block8::default(); for i in 0..4 { let vector = &CIPHER_ROUND_TEST_VECTORS[i]; @@ -118,8 +118,8 @@ fn equiv_inv_cipher_round_fips197_vectors() { #[test] fn equiv_inv_cipher_round_par_fips197_vectors() { - let mut blocks = ParBlocks::default(); - let mut round_keys = ParBlocks::default(); + let mut blocks = Block8::default(); + let mut round_keys = Block8::default(); for i in 0..4 { let vector = &EQUIV_INV_CIPHER_ROUND_TEST_VECTORS[i]; diff --git a/aes/tests/lib.rs b/aes/tests/mod.rs similarity index 100% rename from aes/tests/lib.rs rename to aes/tests/mod.rs diff --git a/block-modes/CHANGELOG.md b/block-modes/CHANGELOG.md deleted file mode 100644 index b83ff6f9..00000000 --- a/block-modes/CHANGELOG.md +++ /dev/null @@ -1,69 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## 0.8.1 (2021-04-30) -### Changed -- Remove unnecessary `NewBlockCipher` bounds ([#240]) - -[#240]: https://github.com/RustCrypto/block-ciphers/pull/240 - -## 0.8.0 (2021-04-29) -### Added -- `IvState` trait ([#227]) - -### Changed -- Upgrade to `cipher v0.3` ([#202]) - -### Added -- Infinite Garble Extension (IGE) block mode ([#211]) - -[#202]: https://github.com/RustCrypto/block-ciphers/pull/202 -[#211]: https://github.com/RustCrypto/block-ciphers/pull/211 -[#227]: https://github.com/RustCrypto/block-ciphers/pull/227 - -## 0.7.0 (2020-10-16) -### Changed -- Replace `block-cipher`/`stream-cipher` with `cipher` crate ([#167]) - -[#167]: https://github.com/RustCrypto/block-ciphers/pull/167 - -## 0.6.1 (2020-08-14) -### Added -- `Clone` trait implementations ([#145]) - -[#145]: https://github.com/RustCrypto/block-ciphers/pull/145 - -## 0.6.0 (2020-08-07) -### Changed -- Bump `block-cipher` dependency to v0.8 and `block-padding` to v0.2 ([#138]) - -[#138]: https://github.com/RustCrypto/block-ciphers/pull/138 - -## 0.5.0 (2020-07-03) -### Changed -- Add `IvSize` associated type to the `BlockMode` trait ([#134]) - -[#134]: https://github.com/RustCrypto/block-ciphers/pull/134 - -## 0.4.0 (2020-06-07) -### Changed -- Upgrade to Rust 2018 edition ([#87]) -- Bump `block-cipher` dependency to v0.7 ([#87]) - -[#87]: https://github.com/RustCrypto/block-ciphers/pull/87 - -## 0.3.3 (2019-04-28) - -## 0.3.2 (2019-02-04) - -## 0.3.1 (2018-12-27) - -## 0.3.0 (2018-12-27) - -## 0.2.0 (2018-10-04) - -## 0.1.0 (2018-03-04) diff --git a/block-modes/Cargo.toml b/block-modes/Cargo.toml deleted file mode 100644 index b449e88e..00000000 --- a/block-modes/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "block-modes" -version = "0.8.1" -description = "Block cipher modes of operation" -authors = ["RustCrypto Developers"] -license = "MIT OR Apache-2.0" -readme = "README.md" -edition = "2018" -documentation = "https://docs.rs/block-modes" -repository = "https://github.com/RustCrypto/block-ciphers" -keywords = ["crypto", "block-cipher", "ciphers"] - -[dependencies] -block-padding = "0.2" -cipher = "0.3" - -[dev-dependencies] -aes = { version = "0.7", path = "../aes", features = ["force-soft"] } -hex-literal = "0.2" - -[features] -default = ["std"] -alloc = [] -std = ["alloc"] diff --git a/block-modes/LICENSE-APACHE b/block-modes/LICENSE-APACHE deleted file mode 100644 index 78173fa2..00000000 --- a/block-modes/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/block-modes/LICENSE-MIT b/block-modes/LICENSE-MIT deleted file mode 100644 index b76974da..00000000 --- a/block-modes/LICENSE-MIT +++ /dev/null @@ -1,26 +0,0 @@ -Copyright (c) 2018 The RustCrypto Project Developers -Copyright (c) 2018 Artyom Pavlov - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/block-modes/README.md b/block-modes/README.md deleted file mode 100644 index d2dd12c1..00000000 --- a/block-modes/README.md +++ /dev/null @@ -1,64 +0,0 @@ -# RustCrypto: Block Modes - -[![crate][crate-image]][crate-link] -[![Docs][docs-image]][docs-link] -![Apache2/MIT licensed][license-image] -![Rust Version][rustc-image] -[![Project Chat][chat-image]][chat-link] -[![Build Status][build-image]][build-link] - -Generic implementation of [block cipher modes of operation][1], including -CBC and ECB modes. - -Note that this crate implements only modes which require padding. For CTR, -CFB and OFB modes (i.e. modes which transform block ciphers into stream -ciphers) see crates in the [RustCrypto/stream-ciphers][2] repository. - - - -[Documentation][docs-link] - -## Minimum Supported Rust Version - -Rust **1.41** or higher. - -Minimum supported Rust version can be changed in the future, but it will be -done with a minor version bump. - -## SemVer Policy - -- All on-by-default features of this library are covered by SemVer -- MSRV is considered exempt from SemVer as noted above - -## License - -Licensed under either of: - - * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) - * [MIT license](http://opensource.org/licenses/MIT) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in the work by you, as defined in the Apache-2.0 license, shall be -dual licensed as above, without any additional terms or conditions. - -[//]: # (badges) - -[crate-image]: https://img.shields.io/crates/v/block-modes.svg -[crate-link]: https://crates.io/crates/block-modes -[docs-image]: https://docs.rs/block-modes/badge.svg -[docs-link]: https://docs.rs/block-modes/ -[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg -[rustc-image]: https://img.shields.io/badge/rustc-1.41+-blue.svg -[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg -[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260039-block-ciphers -[build-image]: https://github.com/RustCrypto/block-ciphers/workflows/block-modes/badge.svg?branch=master&event=push -[build-link]: https://github.com/RustCrypto/block-ciphers/actions?query=workflow%3Ablock-modes - -[//]: # (general links) - -[1]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation -[2]: https://github.com/RustCrypto/stream-ciphers diff --git a/block-modes/src/cbc.rs b/block-modes/src/cbc.rs deleted file mode 100644 index ed9e6630..00000000 --- a/block-modes/src/cbc.rs +++ /dev/null @@ -1,94 +0,0 @@ -use crate::traits::{BlockMode, IvState}; -use crate::utils::{get_par_blocks, xor, Block, ParBlocks}; -use block_padding::Padding; -use cipher::generic_array::{typenum::Unsigned, GenericArray}; -use cipher::{BlockCipher, BlockDecrypt, BlockEncrypt}; -use core::marker::PhantomData; - -/// [Cipher Block Chaining][1] (CBC) block cipher mode instance. -/// -/// [1]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#CBC -#[derive(Clone)] -pub struct Cbc { - cipher: C, - iv: GenericArray, - _p: PhantomData

, -} - -impl Cbc -where - C: BlockCipher + BlockEncrypt + BlockDecrypt, - P: Padding, -{ - #[inline(always)] - fn single_blocks_decrypt(&mut self, blocks: &mut [Block]) { - let mut iv = self.iv.clone(); - for block in blocks { - let block_copy = block.clone(); - self.cipher.decrypt_block(block); - xor(block, iv.as_slice()); - iv = block_copy; - } - self.iv = iv; - } -} - -impl BlockMode for Cbc -where - C: BlockCipher + BlockEncrypt + BlockDecrypt, - P: Padding, -{ - type IvSize = C::BlockSize; - - fn new(cipher: C, iv: &Block) -> Self { - Self { - cipher, - iv: iv.clone(), - _p: Default::default(), - } - } - - fn encrypt_blocks(&mut self, blocks: &mut [Block]) { - self.iv = { - let mut iv = &self.iv; - for block in blocks { - xor(block, &iv); - self.cipher.encrypt_block(block); - iv = block; - } - iv.clone() - }; - } - - fn decrypt_blocks(&mut self, blocks: &mut [Block]) { - let pbn = C::ParBlocks::to_usize(); - if pbn != 1 { - let (par_blocks, leftover) = get_par_blocks::(blocks); - let mut iv_buf = ParBlocks::::default(); - iv_buf[0] = self.iv.clone(); - for pb in par_blocks { - iv_buf[1..].clone_from_slice(&pb[..pbn - 1]); - let next_iv = pb[pbn - 1].clone(); - self.cipher.decrypt_blocks(pb); - pb.iter_mut() - .zip(iv_buf.iter()) - .for_each(|(a, b)| xor(a, b)); - iv_buf[0] = next_iv; - } - self.iv = iv_buf[0].clone(); - self.single_blocks_decrypt(leftover); - } else { - self.single_blocks_decrypt(blocks); - } - } -} - -impl IvState for Cbc -where - C: BlockCipher + BlockEncrypt + BlockDecrypt, - P: Padding, -{ - fn iv_state(&self) -> GenericArray>::IvSize> { - self.iv.clone() - } -} diff --git a/block-modes/src/cfb.rs b/block-modes/src/cfb.rs deleted file mode 100644 index e88f58af..00000000 --- a/block-modes/src/cfb.rs +++ /dev/null @@ -1,124 +0,0 @@ -use crate::{ - traits::{BlockMode, IvState}, - utils::{xor, Block, ParBlocks}, -}; -use block_padding::Padding; -use cipher::{ - generic_array::{typenum::Unsigned, GenericArray}, - BlockCipher, BlockEncrypt, -}; -use core::{marker::PhantomData, ptr}; - -/// [Cipher feedback][1] (CFB) block mode instance with a full block feedback. -/// -/// [1]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_feedback_(CFB) -#[derive(Clone)] -pub struct Cfb { - cipher: C, - iv: GenericArray, - _p: PhantomData

, -} - -impl BlockMode for Cfb -where - C: BlockCipher + BlockEncrypt, - P: Padding, -{ - type IvSize = C::BlockSize; - - fn new(cipher: C, iv: &Block) -> Self { - Self { - cipher, - iv: iv.clone(), - _p: Default::default(), - } - } - - fn encrypt_blocks(&mut self, blocks: &mut [Block]) { - for block in blocks { - self.cipher.encrypt_block(&mut self.iv); - xor_set1(block, self.iv.as_mut_slice()); - } - } - - fn decrypt_blocks(&mut self, mut blocks: &mut [Block]) { - let pb = C::ParBlocks::to_usize(); - - if blocks.len() > pb { - // SAFETY: we have checked that `blocks` has enough elements - #[allow(unsafe_code)] - let mut par_iv = read_par_block::(&blocks[..pb]); - - let (b, r) = { blocks }.split_at_mut(1); - blocks = r; - self.cipher.encrypt_block(&mut self.iv); - xor(&mut b[0], &self.iv); - - // Remember IV for trailing blocks - self.iv = blocks[blocks.len() - (blocks.len() % pb) - 1].clone(); - - while blocks.len() >= 2 * pb { - let next_par_iv = read_par_block::(&blocks[pb - 1..2 * pb - 1]); - self.cipher.encrypt_blocks(&mut par_iv); - let (par_block, r) = { blocks }.split_at_mut(pb); - blocks = r; - - for (a, b) in par_block.iter_mut().zip(par_iv.iter()) { - xor(a, b) - } - par_iv = next_par_iv; - } - - self.cipher.encrypt_blocks(&mut par_iv); - let (par_block, r) = { blocks }.split_at_mut(pb); - blocks = r; - - for (a, b) in par_block.iter_mut().zip(par_iv[..pb].iter()) { - xor(a, b) - } - } - - for block in blocks { - self.cipher.encrypt_block(&mut self.iv); - xor_set2(block, self.iv.as_mut_slice()); - } - } -} - -impl IvState for Cfb -where - C: BlockCipher + BlockEncrypt, - P: Padding, -{ - fn iv_state(&self) -> GenericArray { - self.iv.clone() - } -} - -#[inline(always)] -fn read_par_block(blocks: &[Block]) -> ParBlocks { - assert!(blocks.len() >= C::ParBlocks::to_usize()); - // SAFETY: assert checks that `blocks` is long enough - #[allow(unsafe_code)] - unsafe { - ptr::read(blocks.as_ptr() as *const ParBlocks) - } -} - -#[inline(always)] -fn xor_set1(buf1: &mut [u8], buf2: &mut [u8]) { - for (a, b) in buf1.iter_mut().zip(buf2) { - let t = *a ^ *b; - *a = t; - *b = t; - } -} - -#[inline(always)] -fn xor_set2(buf1: &mut [u8], buf2: &mut [u8]) { - for (a, b) in buf1.iter_mut().zip(buf2) { - let t = *a; - *a ^= *b; - *b = t; - } -} diff --git a/block-modes/src/cfb8.rs b/block-modes/src/cfb8.rs deleted file mode 100644 index 145fdbec..00000000 --- a/block-modes/src/cfb8.rs +++ /dev/null @@ -1,74 +0,0 @@ -use crate::{ - traits::{BlockMode, IvState}, - utils::Block, -}; -use block_padding::Padding; -use cipher::{generic_array::GenericArray, BlockCipher, BlockEncrypt}; -use core::marker::PhantomData; - -/// [Cipher feedback][1] (CFB) block mode instance with a full block feedback. -/// -/// [1]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_feedback_(CFB) -#[derive(Clone)] -pub struct Cfb8 { - cipher: C, - iv: GenericArray, - _p: PhantomData

, -} - -impl BlockMode for Cfb8 -where - C: BlockCipher + BlockEncrypt, - P: Padding, -{ - type IvSize = C::BlockSize; - - fn new(cipher: C, iv: &Block) -> Self { - Self { - cipher, - iv: iv.clone(), - _p: Default::default(), - } - } - - fn encrypt_blocks(&mut self, blocks: &mut [Block]) { - let mut iv = self.iv.clone(); - let n = iv.len(); - for block in blocks.iter_mut() { - for b in block.iter_mut() { - let iv_copy = iv.clone(); - self.cipher.encrypt_block(&mut iv); - *b ^= iv[0]; - iv[..n - 1].clone_from_slice(&iv_copy[1..]); - iv[n - 1] = *b; - } - } - self.iv = iv; - } - - fn decrypt_blocks(&mut self, blocks: &mut [Block]) { - let mut iv = self.iv.clone(); - let n = iv.len(); - for block in blocks.iter_mut() { - for b in block.iter_mut() { - let iv_copy = iv.clone(); - self.cipher.encrypt_block(&mut iv); - let t = *b; - *b ^= iv[0]; - iv[..n - 1].clone_from_slice(&iv_copy[1..]); - iv[n - 1] = t; - } - } - self.iv = iv; - } -} - -impl IvState for Cfb8 -where - C: BlockCipher + BlockEncrypt, - P: Padding, -{ - fn iv_state(&self) -> GenericArray { - self.iv.clone() - } -} diff --git a/block-modes/src/ecb.rs b/block-modes/src/ecb.rs deleted file mode 100644 index 2e98759c..00000000 --- a/block-modes/src/ecb.rs +++ /dev/null @@ -1,84 +0,0 @@ -use crate::{ - errors::InvalidKeyIvLength, - traits::BlockMode, - utils::{get_par_blocks, Block}, -}; -use block_padding::Padding; -use cipher::{ - generic_array::{ - typenum::{Unsigned, U0}, - GenericArray, - }, - BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher, -}; -use core::marker::PhantomData; - -/// [Electronic Codebook][1] (ECB) block cipher mode instance. -/// -/// Note that `new` method ignores IV, so during initialization you can -/// just pass `Default::default()` instead. -/// -/// [1]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#ECB -#[derive(Clone)] -pub struct Ecb { - cipher: C, - _p: PhantomData

, -} - -impl BlockMode for Ecb -where - C: BlockCipher + BlockEncrypt + BlockDecrypt, - P: Padding, -{ - type IvSize = U0; - - fn new(cipher: C, _iv: &GenericArray) -> Self { - Self { - cipher, - _p: Default::default(), - } - } - - fn new_from_slices(key: &[u8], _iv: &[u8]) -> Result - where - C: NewBlockCipher, - { - let cipher = C::new_from_slice(key).map_err(|_| InvalidKeyIvLength)?; - Ok(Self { - cipher, - _p: Default::default(), - }) - } - - fn encrypt_blocks(&mut self, blocks: &mut [Block]) { - if C::ParBlocks::to_usize() != 1 { - let (par_blocks, blocks) = get_par_blocks::(blocks); - par_blocks - .iter_mut() - .for_each(|pb| self.cipher.encrypt_blocks(pb)); - blocks - .iter_mut() - .for_each(|pb| self.cipher.encrypt_block(pb)); - } else { - blocks - .iter_mut() - .for_each(|pb| self.cipher.encrypt_block(pb)); - } - } - - fn decrypt_blocks(&mut self, blocks: &mut [Block]) { - if C::ParBlocks::to_usize() != 1 { - let (par_blocks, blocks) = get_par_blocks::(blocks); - par_blocks - .iter_mut() - .for_each(|pb| self.cipher.decrypt_blocks(pb)); - blocks - .iter_mut() - .for_each(|pb| self.cipher.decrypt_block(pb)); - } else { - blocks - .iter_mut() - .for_each(|pb| self.cipher.decrypt_block(pb)); - } - } -} diff --git a/block-modes/src/errors.rs b/block-modes/src/errors.rs deleted file mode 100644 index 476beddc..00000000 --- a/block-modes/src/errors.rs +++ /dev/null @@ -1,33 +0,0 @@ -use core::fmt; -#[cfg(feature = "std")] -use std::error; - -/// Block mode error. -#[derive(Clone, Copy, Debug)] -pub struct BlockModeError; - -/// Invalid key or IV length error. -#[derive(Clone, Copy, Debug)] -pub struct InvalidKeyIvLength; - -impl fmt::Display for BlockModeError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - f.write_str("BlockModeError") - } -} - -#[cfg(feature = "std")] -impl error::Error for BlockModeError { - fn description(&self) -> &str { - "block mode error" - } -} - -impl fmt::Display for InvalidKeyIvLength { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - f.write_str("InvalidKeyIvLength") - } -} - -#[cfg(feature = "std")] -impl error::Error for InvalidKeyIvLength {} diff --git a/block-modes/src/ige.rs b/block-modes/src/ige.rs deleted file mode 100644 index cd52a527..00000000 --- a/block-modes/src/ige.rs +++ /dev/null @@ -1,86 +0,0 @@ -use crate::{ - traits::{BlockMode, IvState}, - utils::{xor, Block}, -}; -use block_padding::Padding; -use cipher::{ - generic_array::{ - sequence::Concat, - typenum::{Sum, Unsigned}, - ArrayLength, GenericArray, - }, - BlockCipher, BlockDecrypt, BlockEncrypt, -}; -use core::{marker::PhantomData, ops::Add}; - -type IgeIvBlockSize = Sum<::BlockSize, ::BlockSize>; - -/// [Infinite Garble Extension][1] (IGE) block cipher mode instance. -/// -/// [1]: https://www.links.org/files/openssl-ige.pdf -pub struct Ige -where - C: BlockCipher + BlockEncrypt + BlockDecrypt, - P: Padding, - C::BlockSize: Add, - IgeIvBlockSize: ArrayLength, -{ - cipher: C, - x: GenericArray, - y: GenericArray, - _p: PhantomData

, -} - -impl BlockMode for Ige -where - C: BlockCipher + BlockEncrypt + BlockDecrypt, - P: Padding, - C::BlockSize: Add, - IgeIvBlockSize: ArrayLength, -{ - type IvSize = IgeIvBlockSize; - - fn new(cipher: C, iv: &GenericArray) -> Self { - let (y, x) = iv.split_at(C::BlockSize::to_usize()); - Ige { - cipher, - x: GenericArray::clone_from_slice(x), - y: GenericArray::clone_from_slice(y), - _p: Default::default(), - } - } - - fn encrypt_blocks(&mut self, blocks: &mut [Block]) { - for block in blocks { - let t = block.clone(); - xor(block, &self.y); - self.cipher.encrypt_block(block); - xor(block, &self.x); - self.x = t; - self.y = block.clone(); - } - } - - fn decrypt_blocks(&mut self, blocks: &mut [Block]) { - for block in blocks { - let t = block.clone(); - xor(block, &self.x); - self.cipher.decrypt_block(block); - xor(block, &self.y); - self.y = t; - self.x = block.clone(); - } - } -} - -impl IvState for Ige -where - C: BlockCipher + BlockEncrypt + BlockDecrypt, - P: Padding, - C::BlockSize: Add, - IgeIvBlockSize: ArrayLength, -{ - fn iv_state(&self) -> GenericArray { - self.y.clone().concat(self.x.clone()) - } -} diff --git a/block-modes/src/lib.rs b/block-modes/src/lib.rs deleted file mode 100644 index 8d7b429c..00000000 --- a/block-modes/src/lib.rs +++ /dev/null @@ -1,111 +0,0 @@ -//! This crate contains generic implementation of [block cipher modes of -//! operation][1]. -//! -//! Note that some block modes (such as CTR, CFB, and OFB) transform block ciphers -//! into stream ciphers. Implementations in this crate require padding, so if you -//! want use those modes as stream ciphers (i.e. without padding), then check out -//! crates in the [RustCrypto/stream-ciphers][2] repository. -//! -//! # Usage example -//! ``` -//! use aes::Aes128; -//! use block_modes::{BlockMode, Cbc}; -//! use block_modes::block_padding::Pkcs7; -//! use hex_literal::hex; -//! -//! // create an alias for convenience -//! type Aes128Cbc = Cbc; -//! -//! # fn main() { -//! let key = hex!("000102030405060708090a0b0c0d0e0f"); -//! let iv = hex!("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"); -//! let plaintext = b"Hello world!"; -//! let cipher = Aes128Cbc::new_from_slices(&key, &iv).unwrap(); -//! -//! // buffer must have enough space for message+padding -//! let mut buffer = [0u8; 32]; -//! // copy message to the buffer -//! let pos = plaintext.len(); -//! buffer[..pos].copy_from_slice(plaintext); -//! let ciphertext = cipher.encrypt(&mut buffer, pos).unwrap(); -//! -//! assert_eq!(ciphertext, hex!("1b7a4c403124ae2fb52bedc534d82fa8")); -//! -//! // re-create cipher mode instance -//! let cipher = Aes128Cbc::new_from_slices(&key, &iv).unwrap(); -//! let mut buf = ciphertext.to_vec(); -//! let decrypted_ciphertext = cipher.decrypt(&mut buf).unwrap(); -//! -//! assert_eq!(decrypted_ciphertext, plaintext); -//! # } -//! ``` -//! -//! With an enabled `alloc` feature (which is enabled by default) you can use -//! `encrypt_vec` and `decrypt_vec` methods: -//! ``` -//! # use aes::Aes128; -//! # use block_modes::{BlockMode, Cbc}; -//! # use block_modes::block_padding::Pkcs7; -//! # use hex_literal::hex; -//! # -//! # // create an alias for convenience -//! # type Aes128Cbc = Cbc; -//! # -//! # fn main() { -//! # let key = hex!("000102030405060708090a0b0c0d0e0f"); -//! # let iv = hex!("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"); -//! # let plaintext = b"Hello world!"; -//! let cipher = Aes128Cbc::new_from_slices(&key, &iv).unwrap(); -//! let ciphertext = cipher.encrypt_vec(plaintext); -//! -//! assert_eq!(ciphertext, hex!("1b7a4c403124ae2fb52bedc534d82fa8")); -//! -//! let cipher = Aes128Cbc::new_from_slices(&key, &iv).unwrap(); -//! let decrypted_ciphertext = cipher.decrypt_vec(&ciphertext).unwrap(); -//! -//! assert_eq!(decrypted_ciphertext, plaintext); -//! # } -//! ``` -//! -//! [1]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation -//! [2]: https://github.com/RustCrypto/stream-ciphers - -#![no_std] -#![doc( - html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg", - html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg" -)] -#![deny(unsafe_code)] -#![warn(missing_docs, rust_2018_idioms)] - -#[cfg(feature = "alloc")] -extern crate alloc; -#[cfg(feature = "std")] -extern crate std; - -mod errors; -mod traits; -mod utils; - -mod cbc; -mod cfb; -mod cfb8; -mod ecb; -mod ige; -mod ofb; -mod pcbc; - -pub use block_padding; -pub use cipher; - -pub use crate::{ - cbc::Cbc, - cfb::Cfb, - cfb8::Cfb8, - ecb::Ecb, - errors::{BlockModeError, InvalidKeyIvLength}, - ige::Ige, - ofb::Ofb, - pcbc::Pcbc, - traits::{BlockMode, IvState}, -}; diff --git a/block-modes/src/ofb.rs b/block-modes/src/ofb.rs deleted file mode 100644 index bc67775c..00000000 --- a/block-modes/src/ofb.rs +++ /dev/null @@ -1,54 +0,0 @@ -use crate::{ - traits::{BlockMode, IvState}, - utils::{xor, Block}, -}; -use block_padding::Padding; -use cipher::{generic_array::GenericArray, BlockCipher, BlockEncrypt}; -use core::marker::PhantomData; - -/// [Output feedback][1] (OFB) block mode instance with a full block feedback. -/// -/// [1]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_feedback_(CFB) -#[derive(Clone)] -pub struct Ofb { - cipher: C, - iv: GenericArray, - _p: PhantomData

, -} - -impl BlockMode for Ofb -where - C: BlockCipher + BlockEncrypt, - P: Padding, -{ - type IvSize = C::BlockSize; - - fn new(cipher: C, iv: &Block) -> Self { - Self { - cipher, - iv: iv.clone(), - _p: Default::default(), - } - } - - fn encrypt_blocks(&mut self, blocks: &mut [Block]) { - for block in blocks.iter_mut() { - self.cipher.encrypt_block(&mut self.iv); - xor(block, &self.iv); - } - } - - fn decrypt_blocks(&mut self, blocks: &mut [Block]) { - self.encrypt_blocks(blocks) - } -} - -impl IvState for Ofb -where - C: BlockCipher + BlockEncrypt, - P: Padding, -{ - fn iv_state(&self) -> GenericArray>::IvSize> { - self.iv.clone() - } -} diff --git a/block-modes/src/pcbc.rs b/block-modes/src/pcbc.rs deleted file mode 100644 index 2f66e026..00000000 --- a/block-modes/src/pcbc.rs +++ /dev/null @@ -1,78 +0,0 @@ -use crate::{ - traits::{BlockMode, IvState}, - utils::{xor, Block}, -}; -use block_padding::Padding; -use cipher::{generic_array::GenericArray, BlockCipher, BlockDecrypt, BlockEncrypt}; -use core::marker::PhantomData; - -/// [Propagating Cipher Block Chaining][1] (PCBC) mode instance. -/// -/// [1]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#PCBC -#[derive(Clone)] -pub struct Pcbc { - cipher: C, - iv: GenericArray, - _p: PhantomData

, -} - -impl Pcbc -where - C: BlockCipher + BlockEncrypt + BlockDecrypt, - P: Padding, -{ - /// Initialize PCBC - pub fn new(cipher: C, iv: &Block) -> Self { - Self { - cipher, - iv: iv.clone(), - _p: Default::default(), - } - } -} - -impl BlockMode for Pcbc -where - C: BlockCipher + BlockEncrypt + BlockDecrypt, - P: Padding, -{ - type IvSize = C::BlockSize; - - fn new(cipher: C, iv: &GenericArray) -> Self { - Self { - cipher, - iv: iv.clone(), - _p: Default::default(), - } - } - - fn encrypt_blocks(&mut self, blocks: &mut [Block]) { - for block in blocks { - let plaintext = block.clone(); - xor(block, &self.iv); - self.cipher.encrypt_block(block); - self.iv = plaintext; - xor(&mut self.iv, block); - } - } - - fn decrypt_blocks(&mut self, blocks: &mut [Block]) { - for block in blocks { - let ciphertext = block.clone(); - self.cipher.decrypt_block(block); - xor(block, &self.iv); - self.iv = ciphertext; - xor(&mut self.iv, block); - } - } -} - -impl IvState for Pcbc -where - C: BlockCipher + BlockEncrypt + BlockDecrypt, - P: Padding, -{ - fn iv_state(&self) -> GenericArray { - self.iv.clone() - } -} diff --git a/block-modes/src/traits.rs b/block-modes/src/traits.rs deleted file mode 100644 index c2276c22..00000000 --- a/block-modes/src/traits.rs +++ /dev/null @@ -1,128 +0,0 @@ -#[cfg(feature = "alloc")] -pub use alloc::vec::Vec; - -use crate::{ - errors::{BlockModeError, InvalidKeyIvLength}, - utils::{to_blocks, Block, Key}, -}; -use block_padding::Padding; -use cipher::{ - generic_array::{typenum::Unsigned, ArrayLength, GenericArray}, - BlockCipher, NewBlockCipher, -}; - -/// Trait for a block cipher mode of operation that is used to apply a block cipher -/// operation to input data to transform it into a variable-length output message. -pub trait BlockMode: Sized { - /// Initialization Vector size. - type IvSize: ArrayLength; - - /// Create a new block mode instance from initialized block cipher and IV. - fn new(cipher: C, iv: &GenericArray) -> Self; - - /// Create a new block mode instance from fixed sized key and IV. - fn new_fix(key: &Key, iv: &GenericArray) -> Self - where - C: NewBlockCipher, - { - Self::new(C::new(key), iv) - } - - /// Create a new block mode instance from variable size key and IV. - /// - /// Returns an error if key or IV have unsupported length. - fn new_from_slices(key: &[u8], iv: &[u8]) -> Result - where - C: NewBlockCipher, - { - if iv.len() != Self::IvSize::USIZE { - return Err(InvalidKeyIvLength); - } - let iv = GenericArray::from_slice(iv); - let cipher = C::new_from_slice(key).map_err(|_| InvalidKeyIvLength)?; - Ok(Self::new(cipher, iv)) - } - - /// Encrypt blocks of data - fn encrypt_blocks(&mut self, blocks: &mut [Block]); - - /// Decrypt blocks of data - fn decrypt_blocks(&mut self, blocks: &mut [Block]); - - /// Encrypt message in-place. - /// - /// `&buffer[..pos]` is used as a message and `&buffer[pos..]` as a reserved - /// space for padding. The padding space should be big enough for padding, - /// otherwise method will return `Err(BlockModeError)`. - fn encrypt(mut self, buffer: &mut [u8], pos: usize) -> Result<&[u8], BlockModeError> { - let bs = C::BlockSize::to_usize(); - let buf = P::pad(buffer, pos, bs).map_err(|_| BlockModeError)?; - self.encrypt_blocks(to_blocks(buf)); - Ok(buf) - } - - /// Decrypt message in-place. - /// - /// Returns an error if `buffer` length is not multiple of block size and - /// if after decoding message has malformed padding. - fn decrypt(mut self, buffer: &mut [u8]) -> Result<&[u8], BlockModeError> { - let bs = C::BlockSize::to_usize(); - if buffer.len() % bs != 0 { - return Err(BlockModeError); - } - self.decrypt_blocks(to_blocks(buffer)); - P::unpad(buffer).map_err(|_| BlockModeError) - } - - /// Encrypt message and store result in vector. - #[cfg(feature = "alloc")] - fn encrypt_vec(mut self, plaintext: &[u8]) -> Vec { - let bs = C::BlockSize::to_usize(); - let pos = plaintext.len(); - let n = pos + bs; - let mut buf = Vec::with_capacity(n); - buf.extend_from_slice(plaintext); - // prepare space for padding - let block: Block = Default::default(); - buf.extend_from_slice(&block[..n - pos]); - - let n = P::pad(&mut buf, pos, bs) - .expect("enough space for padding is allocated") - .len(); - buf.truncate(n); - self.encrypt_blocks(to_blocks(&mut buf)); - buf - } - - /// Encrypt message and store result in vector. - #[cfg(feature = "alloc")] - fn decrypt_vec(mut self, ciphertext: &[u8]) -> Result, BlockModeError> { - let bs = C::BlockSize::to_usize(); - if ciphertext.len() % bs != 0 { - return Err(BlockModeError); - } - let mut buf = ciphertext.to_vec(); - self.decrypt_blocks(to_blocks(&mut buf)); - let n = P::unpad(&buf).map_err(|_| BlockModeError)?.len(); - buf.truncate(n); - Ok(buf) - } -} - -/// Trait for a BlockMode, used to obtain the current state in the form of an IV -/// that can initialize a BlockMode later and resume the original operation. -/// -/// The IV value SHOULD be used for resuming operations only and MUST NOT be -/// exposed to attackers. Failing to comply with this requirement breaks -/// unpredictability and opens attack venues (see e.g. [1], sec. 3.6.2). -/// -/// [1]: https://www.cs.umd.edu/~jkatz/imc.html -pub trait IvState: BlockMode -where - C: BlockCipher, - P: Padding, -{ - /// Returns the IV needed to process the following block. This value MUST - /// NOT be exposed to attackers. - fn iv_state(&self) -> GenericArray; -} diff --git a/block-modes/src/utils.rs b/block-modes/src/utils.rs deleted file mode 100644 index a16d2908..00000000 --- a/block-modes/src/utils.rs +++ /dev/null @@ -1,43 +0,0 @@ -use cipher::{ - generic_array::{typenum::Unsigned, ArrayLength, GenericArray}, - BlockCipher, NewBlockCipher, -}; -use core::slice; - -#[inline(always)] -pub fn xor(buf: &mut [u8], key: &[u8]) { - debug_assert_eq!(buf.len(), key.len()); - for (a, b) in buf.iter_mut().zip(key) { - *a ^= *b; - } -} - -pub(crate) type Key = GenericArray::KeySize>; -pub(crate) type Block = GenericArray::BlockSize>; -pub(crate) type ParBlocks = GenericArray, ::ParBlocks>; - -pub(crate) fn to_blocks(data: &mut [u8]) -> &mut [GenericArray] -where - N: ArrayLength, -{ - let n = N::to_usize(); - debug_assert!(data.len() % n == 0); - - #[allow(unsafe_code)] - unsafe { - slice::from_raw_parts_mut(data.as_ptr() as *mut GenericArray, data.len() / n) - } -} - -pub(crate) fn get_par_blocks( - blocks: &mut [Block], -) -> (&mut [ParBlocks], &mut [Block]) { - let pb = C::ParBlocks::to_usize(); - let n_par = blocks.len() / pb; - - let (par, single) = blocks.split_at_mut(n_par * pb); - - #[allow(unsafe_code)] - let par = unsafe { slice::from_raw_parts_mut(par.as_ptr() as *mut ParBlocks, n_par) }; - (par, single) -} diff --git a/block-modes/tests/data/aes128.iv.bin b/block-modes/tests/data/aes128.iv.bin deleted file mode 100644 index e92d9c9f4bff337b1144a79c298f6bf192321452..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16 ScmZQzWMXDvWn=#j0e=7`9S9Nt diff --git a/block-modes/tests/data/aes128.key.bin b/block-modes/tests/data/aes128.key.bin deleted file mode 100644 index efb78194..00000000 --- a/block-modes/tests/data/aes128.key.bin +++ /dev/null @@ -1 +0,0 @@ -+~(Ҧ O< \ No newline at end of file diff --git a/block-modes/tests/data/aes128.plaintext.bin b/block-modes/tests/data/aes128.plaintext.bin deleted file mode 100644 index 11f2f934be86480211881e16bcf8434d658ddfdb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 288 zcmV+*0pI>z|356y4)Hgsefc9(faCAbUsIWm0A5nv&(bRKIa-mx_%_wPVvFR$CziHh zP^Y1m`H<5W(YiLr52QR}EK^$9`#IaQ10)SWL#{KEF3Mggdcc>p2U+LDU#NU(#V1UT zuA}|UaoF$D3aTITuenokFVg=;3CEAhH;yDv3uHUf{Yj^9Z^?{Yw;%2sroScX<7< mb9JJ1&2(vsh>#RZV4FG@dzUDKd@@lH6^~;S4?KlTL}PAha*Nsk diff --git a/block-modes/tests/data/cbc-aes128.ciphertext.bin b/block-modes/tests/data/cbc-aes128.ciphertext.bin deleted file mode 100644 index ef290c77ced03396ba64f12cc4ccd1bc96c4e850..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 288 zcmV+*0pI@G2IVj_<)*LGQ}l-RFBGQ~vMfui8nYl}MpLPPYCf1Th$W+{z6U=O9@K07 z)twJP8f#3?#fkBZ1Y~-eYW9N+H}>ceHQ60`E^DP_>xh|YgJnp{03^ph=D^w!+Gz4# zY8~l#@#gFcnJAhSP3Q2rR8Z;YqbWQ>e9m$S%mr=qcq7BufZZR`dZT0s3v#S$j5TU@ zSw5xaeI3|Q3eQl=sB-6ntTzpuIwOtwA;c)0qN2d4gc64It8{`fOS2R{)(2}$5W;tF z62T)|-X&1%SZ#8(;9*k%?tvwscb`08Le!K4KY&^kjBFu{H9o>KmILTEi_r8JKeeA7 mX|0_OIi8r6v3vn-&93pr%D*W%)Vh8^7q2ZbnvVmI0p3R!A&8Cu diff --git a/block-modes/tests/data/cfb-aes128-2.ciphertext.bin b/block-modes/tests/data/cfb-aes128-2.ciphertext.bin deleted file mode 100644 index beecb88b2ab18b5d3f9a97557045e85a37f48cbb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 480 zcmV<60U!P}M$g1rNNpIhD)_qdWoE7{HmN#v|Il^R3p&63$s4{J6UW2u-IN>ki4tRv z4M~VK9=_Z}*{P11?u|Bt{&uw45m8dDeVAW~aPf7_^~M)rpOBiaEKkypwR5oS0D?r; z8tOfCPSr7jojJc}=tn1kn>>>!vPBSZl<$Q9{VoG^=~RZ|sRM;lM`PdeB^tf8UUX|? z1YK3o`@cf4?sQFekG{sD->ExuSw8A$COCZptJ+?O3r#f_S7hFM`?zGR){>m+waawd zGeeS2wg&*7Z0zn}Ys*%Am8%G+TeY+wDN`({CPP6VMxb6jXm|%#6d$jzBNb5fPyOn6 z8vRIu$mudYwElzj&rq6y1La&@{yz9xzb;98KaTIw;YY#JfWC#e+@CoN<7;D67L!oC z>y5aT=S=A>L=>3HB4%$u`vzj*Z7;Ks)|6uWdeLG^>Hr%9{vbV)&h*#5m149CLm7l= zvAbcBfGUm+_PK?zqfNeH%1$z16i!*%y{Pyj3Fr;i^eMjSyP=_&tQ7;JW7+gLN;OIm zMSA`~WxELA{$VkK(4{n1wNwG)h7R$)-+8n!@DNcP%h3t^)-l8Rwc04BaL$VL3-jhZ zV5S#c&zkFGlF-9lMdr0RGX?y|%+(KZ_d4VPKS>4xII8?j#K_;7+|rpUNSURqzcy`5XPrFDxpcMa#7F?@q3mlk+^nO)m$ui)B^ zdW{J3%Ij$&`Qwzzaq;=EoJzwC^&WKT1Ftpm5Y@HetZ33=IfK6>ax5U!acjWT9bPu( WMLB6kodbC<`cEj*wHStBW-Ud-HTARr diff --git a/block-modes/tests/data/cfb-aes128.ciphertext.bin b/block-modes/tests/data/cfb-aes128.ciphertext.bin deleted file mode 100644 index a5a5e1d9347c3ff4ac8f46777d5788e0a1e4ae06..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 288 zcmV+*0pI=>1Ntm&`yi}KpB!0?)gY)p#2NT5x@c>@?_YCm!PkZRO#;I5oj9LFdcH4 zmo~CJADU06%XGw}5QI7a0K#A?>mg3!7r)(2W?O)7Z^g2B3n^2bT4?4J;7M_pvbpi9Qaspe>(0G9+98I+j}%n* zX*Nk$(eB}BT@dr7sS;d>8##`oENr&(QB>01x#w?$~e m1@aRvbwRvlbDJWDJM;355uUb9;K#_#EY{b~N3^J$kZ^ZprO}4J=TO}U1M#?eFtKHf8 z{OtK+-{B5p&^(ct{&VxNN`F)6r~FM;*RMJl6fYMh0I5Q2fMY%n*1p+3-OraRDN?Ib zs`0;Z=xKw5D8-_>1pYbL+D1>@fYw#$PIpzXra;ow(4G_7AvnA2P;};Ede3aV7T-Ho zMb!4Wm?nGfFf@-+xFOnmC1vJ`xtN9;h_P0)9cS|i&L(&5gDb9=xA}N$f!adu$TB0{ zrPFlJ_Wxai`SwFLB`c{fp&rz-j&8pRy(4H;DtmesB%=P$q8v#HZerMMC+6cQE@6%&_`l#-T_m6Hbm6>tIZ diff --git a/block-modes/tests/data/ige-aes128-1.key.bin b/block-modes/tests/data/ige-aes128-1.key.bin deleted file mode 100644 index b66efb8adab7795606f4ebbc70be4c0a1d047a52..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16 XcmZQzWMXDvWn<^yLnc0=NKq diff --git a/block-modes/tests/data/ige-aes128-1.plaintext.bin b/block-modes/tests/data/ige-aes128-1.plaintext.bin deleted file mode 100644 index 4e4e4935707a596987ec1cc32e3d0d587dbe4f04..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32 KcmZQzzz+ZbAOHaX diff --git a/block-modes/tests/data/ige-aes128-2.ciphertext.bin b/block-modes/tests/data/ige-aes128-2.ciphertext.bin deleted file mode 100644 index 98a9103a..00000000 --- a/block-modes/tests/data/ige-aes128-2.ciphertext.bin +++ /dev/null @@ -1 +0,0 @@ -L. Let's hope Ben got it right! diff --git a/block-modes/tests/data/ige-aes128-2.iv.bin b/block-modes/tests/data/ige-aes128-2.iv.bin deleted file mode 100644 index b2bbd02f..00000000 --- a/block-modes/tests/data/ige-aes128-2.iv.bin +++ /dev/null @@ -1 +0,0 @@ -mentation of IGE mode for OpenSS \ No newline at end of file diff --git a/block-modes/tests/data/ige-aes128-2.key.bin b/block-modes/tests/data/ige-aes128-2.key.bin deleted file mode 100644 index 4133881b..00000000 --- a/block-modes/tests/data/ige-aes128-2.key.bin +++ /dev/null @@ -1 +0,0 @@ -This is an imple \ No newline at end of file diff --git a/block-modes/tests/data/ige-aes128-2.plaintext.bin b/block-modes/tests/data/ige-aes128-2.plaintext.bin deleted file mode 100644 index a5d96df4..00000000 --- a/block-modes/tests/data/ige-aes128-2.plaintext.bin +++ /dev/null @@ -1 +0,0 @@ -pdmKzHȹ@>4gؓ@; \ No newline at end of file diff --git a/block-modes/tests/data/ofb-aes128.ciphertext.bin b/block-modes/tests/data/ofb-aes128.ciphertext.bin deleted file mode 100644 index 0d1e9266e665377b279a6c68a2f5b4e3acf8b7aa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 288 zcmV+*0pI=>1Ntm&`yi}KpB!0?)gY+XkX};mQBnx2-)g9PTt4XZq}D&P#nw`k3|;de zhblx*%M}C3{0T^!!Sb#Q2*)=;+drZ#c32l~ThYfEUI)FKwqghq6$xZF>G`QfB}L9BGTg-NTyOlh{MM>9T-&A3Gc=NB58sT#2|>a3oRDh7_o zx1s(s%H^9fZWD##gDcSy^HdAPG@<`A!QUQWz{K~JVLib9t}8S6G{j(=MZnMrKO^_A mHTWp)R_a+3AOKWvBzS{4EYF(RRz8B diff --git a/block-modes/tests/lib.rs b/block-modes/tests/lib.rs deleted file mode 100644 index 73b5de9b..00000000 --- a/block-modes/tests/lib.rs +++ /dev/null @@ -1,380 +0,0 @@ -//! Test vectors generated with OpenSSL - -use aes::{Aes128, BlockCipher, NewBlockCipher}; -use block_modes::block_padding::NoPadding; -use block_modes::{BlockMode, IvState}; -use block_modes::{Cbc, Cfb, Ecb, Ige, Ofb}; -use cipher::generic_array::{ArrayLength, GenericArray}; - -#[test] -fn ecb_aes128() { - let key = include_bytes!("data/aes128.key.bin"); - let plaintext = include_bytes!("data/aes128.plaintext.bin"); - let ciphertext = include_bytes!("data/ecb-aes128.ciphertext.bin"); - // ECB mode ignores IV - let iv = Default::default(); - - let mode = Ecb::::new_from_slices(key, iv).unwrap(); - assert_eq!(mode.encrypt_vec(plaintext), &ciphertext[..]); - - let mode = Ecb::::new_from_slices(key, iv).unwrap(); - assert_eq!(mode.decrypt_vec(ciphertext).unwrap(), &plaintext[..]); -} - -#[test] -fn cbc_aes128() { - let key = include_bytes!("data/aes128.key.bin"); - let iv = include_bytes!("data/aes128.iv.bin"); - let plaintext = include_bytes!("data/aes128.plaintext.bin"); - let ciphertext = include_bytes!("data/cbc-aes128.ciphertext.bin"); - - let mode = Cbc::::new_from_slices(key, iv).unwrap(); - assert_eq!(mode.encrypt_vec(plaintext), &ciphertext[..]); - - let mode = Cbc::::new_from_slices(key, iv).unwrap(); - assert_eq!(mode.decrypt_vec(ciphertext).unwrap(), &plaintext[..]); -} - -#[test] -fn cbc_aes128_continued() { - type BlockSize = ::BlockSize; - - let key = GenericArray::from_slice(include_bytes!("data/aes128.key.bin")); - let iv = GenericArray::from_slice(include_bytes!("data/aes128.iv.bin")); - let mut ciphertext = *include_bytes!("data/cbc-aes128.ciphertext.bin"); - let mut plaintext = *include_bytes!("data/aes128.plaintext.bin"); - let plaintext_blocks = to_blocks::(&mut plaintext[..]); - let ciphertext_blocks = to_blocks::(&mut ciphertext[..]); - - for i in 0..ciphertext_blocks.len() { - let mut plaintext = *include_bytes!("data/aes128.plaintext.bin"); - let blocks = to_blocks::(&mut plaintext[..]); - - // Encrypt `i` blocks - let cipher = Aes128::new(key); - let mut mode = block_modes::Cbc::::new(cipher, iv); - mode.encrypt_blocks(&mut blocks[..i]); - - // Interrupt, reinitialize mode, encrypt remaining blocks - let cipher = Aes128::new(key); - let mut mode = block_modes::Cbc::::new(cipher, &mode.iv_state()); - mode.encrypt_blocks(&mut blocks[i..]); - - assert_eq!(blocks, ciphertext_blocks); - - // Decrypt likewise - let cipher = Aes128::new(key); - let mut mode = block_modes::Cbc::::new(cipher, iv); - mode.decrypt_blocks(&mut blocks[..i]); - let cipher = Aes128::new(key); - let mut mode = block_modes::Cbc::::new(cipher, &mode.iv_state()); - mode.decrypt_blocks(&mut blocks[i..]); - - assert_eq!(blocks, plaintext_blocks); - } -} - -#[test] -fn cfb_aes128() { - let key = include_bytes!("data/aes128.key.bin"); - let iv = include_bytes!("data/aes128.iv.bin"); - let plaintext = include_bytes!("data/aes128.plaintext.bin"); - let ciphertext = include_bytes!("data/cfb-aes128.ciphertext.bin"); - - let mode = Cfb::::new_from_slices(key, iv).unwrap(); - assert_eq!(mode.encrypt_vec(plaintext), &ciphertext[..]); - - let mode = Cfb::::new_from_slices(key, iv).unwrap(); - assert_eq!(mode.decrypt_vec(ciphertext).unwrap(), &plaintext[..]); -} - -#[test] -fn cfb_aes128_continued() { - type BlockSize = ::BlockSize; - - let key = GenericArray::from_slice(include_bytes!("data/aes128.key.bin")); - let iv = GenericArray::from_slice(include_bytes!("data/aes128.iv.bin")); - let mut ciphertext = *include_bytes!("data/cfb-aes128.ciphertext.bin"); - let mut plaintext = *include_bytes!("data/aes128.plaintext.bin"); - let plaintext_blocks = to_blocks::(&mut plaintext[..]); - let ciphertext_blocks = to_blocks::(&mut ciphertext[..]); - - for i in 0..ciphertext_blocks.len() { - let mut plaintext = *include_bytes!("data/aes128.plaintext.bin"); - let blocks = to_blocks::(&mut plaintext[..]); - - // Encrypt `i` blocks - let cipher = Aes128::new(key); - let mut mode = block_modes::Cfb::::new(cipher, iv); - mode.encrypt_blocks(&mut blocks[..i]); - - // Interrupt, reinitialize mode, encrypt remaining blocks - let cipher = Aes128::new(key); - let mut mode = block_modes::Cfb::::new(cipher, &mode.iv_state()); - mode.encrypt_blocks(&mut blocks[i..]); - - assert_eq!(blocks, ciphertext_blocks); - - // Decrypt likewise - let cipher = Aes128::new(key); - let mut mode = block_modes::Cfb::::new(cipher, iv); - mode.decrypt_blocks(&mut blocks[..i]); - let cipher = Aes128::new(key); - let mut mode = block_modes::Cfb::::new(cipher, &mode.iv_state()); - mode.decrypt_blocks(&mut blocks[i..]); - - assert_eq!(blocks, plaintext_blocks); - } -} - -#[test] -fn cfb_aes128_2() { - let key = include_bytes!("data/aes128.key.bin"); - let iv = include_bytes!("data/aes128.iv.bin"); - let plaintext = include_bytes!("data/cfb-aes128-2.plaintext.bin"); - let ciphertext = include_bytes!("data/cfb-aes128-2.ciphertext.bin"); - - let mode = Cfb::::new_from_slices(key, iv).unwrap(); - assert_eq!(mode.encrypt_vec(plaintext), &ciphertext[..]); - - let mode = Cfb::::new_from_slices(key, iv).unwrap(); - assert_eq!(mode.decrypt_vec(ciphertext).unwrap(), &plaintext[..]); -} - -#[test] -fn cfb_aes128_2_continued() { - type BlockSize = ::BlockSize; - - let key = GenericArray::from_slice(include_bytes!("data/aes128.key.bin")); - let iv = GenericArray::from_slice(include_bytes!("data/aes128.iv.bin")); - let mut ciphertext = *include_bytes!("data/cfb-aes128-2.ciphertext.bin"); - let mut plaintext = *include_bytes!("data/cfb-aes128-2.plaintext.bin"); - let plaintext_blocks = to_blocks::(&mut plaintext[..]); - let ciphertext_blocks = to_blocks::(&mut ciphertext[..]); - - for i in 0..ciphertext_blocks.len() { - let mut plaintext = *include_bytes!("data/cfb-aes128-2.plaintext.bin"); - let blocks = to_blocks::(&mut plaintext[..]); - - // Encrypt `i` blocks - let cipher = Aes128::new(key); - let mut mode = block_modes::Cfb::::new(cipher, iv); - mode.encrypt_blocks(&mut blocks[..i]); - - // Interrupt, reinitialize mode, encrypt remaining blocks - let cipher = Aes128::new(key); - let mut mode = block_modes::Cfb::::new(cipher, &mode.iv_state()); - mode.encrypt_blocks(&mut blocks[i..]); - - assert_eq!(blocks, ciphertext_blocks); - - // Decrypt likewise - let cipher = Aes128::new(key); - let mut mode = block_modes::Cfb::::new(cipher, iv); - mode.decrypt_blocks(&mut blocks[..i]); - let cipher = Aes128::new(key); - let mut mode = block_modes::Cfb::::new(cipher, &mode.iv_state()); - mode.decrypt_blocks(&mut blocks[i..]); - - assert_eq!(blocks, plaintext_blocks); - } -} - -#[test] -fn ofb_aes128() { - let key = include_bytes!("data/aes128.key.bin"); - let iv = include_bytes!("data/aes128.iv.bin"); - let plaintext = include_bytes!("data/aes128.plaintext.bin"); - let ciphertext = include_bytes!("data/ofb-aes128.ciphertext.bin"); - - let mode = Ofb::::new_from_slices(key, iv).unwrap(); - assert_eq!(mode.encrypt_vec(plaintext), &ciphertext[..]); - - let mode = Ofb::::new_from_slices(key, iv).unwrap(); - assert_eq!(mode.decrypt_vec(ciphertext).unwrap(), &plaintext[..]); -} - -#[test] -fn ofb_aes128_continued() { - type BlockSize = ::BlockSize; - - let key = GenericArray::from_slice(include_bytes!("data/aes128.key.bin")); - let iv = GenericArray::from_slice(include_bytes!("data/aes128.iv.bin")); - let mut ciphertext = *include_bytes!("data/ofb-aes128.ciphertext.bin"); - let mut plaintext = *include_bytes!("data/aes128.plaintext.bin"); - let ciphertext_blocks = to_blocks::(&mut ciphertext[..]); - let plaintext_blocks = to_blocks::(&mut plaintext[..]); - - for i in 0..ciphertext_blocks.len() { - let mut plaintext = *include_bytes!("data/aes128.plaintext.bin"); - let blocks = to_blocks::(&mut plaintext[..]); - - // Encrypt `i` blocks - let cipher = Aes128::new(key); - let mut mode = block_modes::Ofb::::new(cipher, iv); - mode.encrypt_blocks(&mut blocks[..i]); - - // Interrupt, reinitialize mode, encrypt remaining blocks - let cipher = Aes128::new(key); - let mut mode = block_modes::Ofb::::new(cipher, &mode.iv_state()); - mode.encrypt_blocks(&mut blocks[i..]); - - assert_eq!(blocks, ciphertext_blocks); - - // Decrypt likewise - let cipher = Aes128::new(key); - let mut mode = block_modes::Ofb::::new(cipher, iv); - mode.decrypt_blocks(&mut blocks[..i]); - let cipher = Aes128::new(key); - let mut mode = block_modes::Ofb::::new(cipher, &mode.iv_state()); - mode.decrypt_blocks(&mut blocks[i..]); - - assert_eq!(blocks, plaintext_blocks); - } -} - -/// Test that parallel code works correctly -#[test] -fn par_blocks() { - use block_modes::block_padding::Pkcs7; - fn run>() { - let key: &[u8; 16] = b"secret key data."; - let iv: &[u8; 16] = b"public iv data.."; - - for i in 1..160 { - let mut buf = [128u8; 160]; - - let cipher = M::new_from_slices(key, iv).unwrap(); - let ct_len = cipher.encrypt(&mut buf, i).unwrap().len(); - let cipher = M::new_from_slices(key, iv).unwrap(); - let pt = cipher.decrypt(&mut buf[..ct_len]).unwrap(); - assert!(pt.iter().all(|&b| b == 128)); - } - } - - run::>(); - run::>(); - run::>(); - run::>(); - run::>(); -} - -#[test] -fn ige_aes256_1() { - let key = include_bytes!("data/ige-aes128-1.key.bin"); - let iv = include_bytes!("data/ige-aes128-1.iv.bin"); - let plaintext = include_bytes!("data/ige-aes128-1.plaintext.bin"); - let ciphertext = include_bytes!("data/ige-aes128-1.ciphertext.bin"); - - let mode = Ige::::new_from_slices(key, iv).unwrap(); - assert_eq!(mode.encrypt_vec(plaintext), &ciphertext[..]); - - let mode = Ige::::new_from_slices(key, iv).unwrap(); - assert_eq!(mode.decrypt_vec(ciphertext).unwrap(), &plaintext[..]); -} - -#[test] -fn ige_aes256_1_continued() { - type BlockSize = ::BlockSize; - - let key = GenericArray::from_slice(include_bytes!("data/ige-aes128-1.key.bin")); - let iv = GenericArray::from_slice(include_bytes!("data/ige-aes128-1.iv.bin")); - let mut ciphertext = *include_bytes!("data/ige-aes128-1.ciphertext.bin"); - let mut plaintext = *include_bytes!("data/ige-aes128-1.plaintext.bin"); - let plaintext_blocks = to_blocks::(&mut plaintext[..]); - let ciphertext_blocks = to_blocks::(&mut ciphertext[..]); - - for i in 0..ciphertext_blocks.len() { - let mut plaintext = *include_bytes!("data/ige-aes128-1.plaintext.bin"); - let blocks = to_blocks::(&mut plaintext[..]); - - // Encrypt `i` blocks - let cipher = Aes128::new(key); - let mut mode = block_modes::Ige::::new(cipher, iv); - mode.encrypt_blocks(&mut blocks[..i]); - - // Interrupt, reinitialize mode, encrypt remaining blocks - let cipher = Aes128::new(key); - let mut mode = block_modes::Ige::::new(cipher, &mode.iv_state()); - mode.encrypt_blocks(&mut blocks[i..]); - - assert_eq!(blocks, ciphertext_blocks); - - // Decrypt likewise - let cipher = Aes128::new(key); - let mut mode = block_modes::Ige::::new(cipher, iv); - mode.decrypt_blocks(&mut blocks[..i]); - let cipher = Aes128::new(key); - let mut mode = block_modes::Ige::::new(cipher, &mode.iv_state()); - mode.decrypt_blocks(&mut blocks[i..]); - - assert_eq!(blocks, plaintext_blocks); - } -} - -#[test] -fn ige_aes256_2() { - let key = include_bytes!("data/ige-aes128-2.key.bin"); - let iv = include_bytes!("data/ige-aes128-2.iv.bin"); - let plaintext = include_bytes!("data/ige-aes128-2.plaintext.bin"); - let ciphertext = include_bytes!("data/ige-aes128-2.ciphertext.bin"); - - let mode = Ige::::new_from_slices(key, iv).unwrap(); - assert_eq!(mode.encrypt_vec(plaintext), &ciphertext[..]); - - let mode = Ige::::new_from_slices(key, iv).unwrap(); - assert_eq!(mode.decrypt_vec(ciphertext).unwrap(), &plaintext[..]); -} - -#[test] -fn ige_aes256_2_continued() { - type BlockSize = ::BlockSize; - - let key = GenericArray::from_slice(include_bytes!("data/ige-aes128-2.key.bin")); - let iv = GenericArray::from_slice(include_bytes!("data/ige-aes128-2.iv.bin")); - let mut plaintext = *include_bytes!("data/ige-aes128-2.plaintext.bin"); - let mut ciphertext = *include_bytes!("data/ige-aes128-2.ciphertext.bin"); - let plaintext_blocks = to_blocks::(&mut plaintext[..]); - let ciphertext_blocks = to_blocks::(&mut ciphertext[..]); - - for i in 0..ciphertext_blocks.len() { - let mut plaintext = *include_bytes!("data/ige-aes128-2.plaintext.bin"); - let blocks = to_blocks::(&mut plaintext[..]); - - // Encrypt `i` blocks - let cipher = Aes128::new(key); - let mut mode = block_modes::Ige::::new(cipher, iv); - mode.encrypt_blocks(&mut blocks[..i]); - - // Interrupt, reinitialize mode, encrypt remaining blocks - let cipher = Aes128::new(key); - let mut mode = block_modes::Ige::::new(cipher, &mode.iv_state()); - mode.encrypt_blocks(&mut blocks[i..]); - - assert_eq!(blocks, ciphertext_blocks); - - // Decrypt likewise - let cipher = Aes128::new(key); - let mut mode = block_modes::Ige::::new(cipher, iv); - mode.decrypt_blocks(&mut blocks[..i]); - let cipher = Aes128::new(key); - let mut mode = block_modes::Ige::::new(cipher, &mode.iv_state()); - mode.decrypt_blocks(&mut blocks[i..]); - - assert_eq!(blocks, plaintext_blocks); - } -} - -fn to_blocks(data: &mut [u8]) -> &mut [GenericArray] -where - N: ArrayLength, -{ - use core::slice; - let n = N::to_usize(); - debug_assert!(data.len() % n == 0); - - #[allow(unsafe_code)] - unsafe { - slice::from_raw_parts_mut(data.as_ptr() as *mut GenericArray, data.len() / n) - } -} diff --git a/blowfish/CHANGELOG.md b/blowfish/CHANGELOG.md index dcdfe61b..ac28a495 100644 --- a/blowfish/CHANGELOG.md +++ b/blowfish/CHANGELOG.md @@ -5,9 +5,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 0.9.0 (2022-02-10) +### Changed +- Bump `cipher` dependency to v0.4 ([#284]) + +[#284]: https://github.com/RustCrypto/block-ciphers/pull/284 + ## 0.8.0 (2021-04-29) ### Changed -- Bump `cipher` dependency to v0.3 release ([#235]) +- Bump `cipher` dependency to v0.3 ([#235]) [#235]: https://github.com/RustCrypto/block-ciphers/pull/235 diff --git a/blowfish/Cargo.toml b/blowfish/Cargo.toml index c147e1bf..1248bed7 100644 --- a/blowfish/Cargo.toml +++ b/blowfish/Cargo.toml @@ -1,23 +1,28 @@ [package] name = "blowfish" -version = "0.8.0" +version = "0.9.0" # Also update html_root_url in lib.rs when bumping this description = "Blowfish block cipher" authors = ["RustCrypto Developers"] license = "MIT OR Apache-2.0" +edition = "2021" +rust-version = "1.56" readme = "README.md" -edition = "2018" documentation = "https://docs.rs/blowfish" repository = "https://github.com/RustCrypto/block-ciphers" keywords = ["crypto", "blowfish", "block-cipher"] categories = ["cryptography", "no-std"] [dependencies] -cipher = "0.3" -byteorder = { version = "1.1.0", default-features = false } -opaque-debug = "0.3" +cipher = "0.4" +byteorder = { version = "1.1", default-features = false } [dev-dependencies] -cipher = { version = "0.3", features = ["dev"] } +cipher = { version = "0.4", features = ["dev"] } [features] bcrypt = [] +zeroize = ["cipher/zeroize"] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] diff --git a/blowfish/README.md b/blowfish/README.md index dfed7957..00a1f2d1 100644 --- a/blowfish/README.md +++ b/blowfish/README.md @@ -26,7 +26,7 @@ USE AT YOUR OWN RISK! ## Minimum Supported Rust Version -Rust **1.41** or higher. +Rust **1.56** or higher. Minimum supported Rust version can be changed in the future, but it will be done with a minor version bump. @@ -58,7 +58,7 @@ dual licensed as above, without any additional terms or conditions. [docs-image]: https://docs.rs/blowfish/badge.svg [docs-link]: https://docs.rs/blowfish/ [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg -[rustc-image]: https://img.shields.io/badge/rustc-1.41+-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.56+-blue.svg [hazmat-image]: https://img.shields.io/badge/crypto-hazmat%E2%9A%A0-red.svg [hazmat-link]: https://github.com/RustCrypto/meta/blob/master/HAZMAT.md [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg diff --git a/blowfish/benches/lib.rs b/blowfish/benches/lib.rs deleted file mode 100644 index 20efbc48..00000000 --- a/blowfish/benches/lib.rs +++ /dev/null @@ -1,3 +0,0 @@ -#![feature(test)] - -cipher::block_cipher_bench!(blowfish::Blowfish, 16); diff --git a/blowfish/benches/mod.rs b/blowfish/benches/mod.rs new file mode 100644 index 00000000..00078c83 --- /dev/null +++ b/blowfish/benches/mod.rs @@ -0,0 +1,16 @@ +#![feature(test)] +extern crate test; + +use blowfish::Blowfish; +use cipher::{block_decryptor_bench, block_encryptor_bench}; + +block_encryptor_bench!( + Key: Blowfish, + blowfish_encrypt_block, + blowfish_encrypt_blocks, +); +block_decryptor_bench!( + Key: Blowfish, + blowfish_decrypt_block, + blowfish_decrypt_blocks, +); diff --git a/blowfish/src/lib.rs b/blowfish/src/lib.rs index 10675bc9..0b0d8d29 100644 --- a/blowfish/src/lib.rs +++ b/blowfish/src/lib.rs @@ -1,33 +1,37 @@ -//! Blowfish block cipher +//! Pure Rust implementation of the [Blowfish] block cipher. +//! +//! [Blowfish]: https://en.wikipedia.org/wiki/Blowfish_(cipher) #![no_std] #![doc( - html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg", - html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg" + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg", + html_root_url = "https://docs.rs/blowfish/0.9.0" )] -#![forbid(unsafe_code)] +#![deny(unsafe_code)] +#![cfg_attr(docsrs, feature(doc_cfg))] #![warn(missing_docs, rust_2018_idioms)] pub use cipher; use byteorder::{ByteOrder, BE, LE}; use cipher::{ - consts::{U1, U56, U8}, - errors::InvalidLength, - generic_array::GenericArray, - BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher, + consts::{U56, U8}, + AlgorithmName, BlockCipher, InvalidLength, Key, KeyInit, KeySizeUser, }; +use core::fmt; use core::marker::PhantomData; +#[cfg(feature = "zeroize")] +use cipher::zeroize::{Zeroize, ZeroizeOnDrop}; + mod consts; /// Blowfish variant which uses Little Endian byte order read/writes.s. pub type BlowfishLE = Blowfish; -type Block = GenericArray; - /// Blowfish block cipher instance. -#[derive(Clone, Copy)] +#[derive(Clone)] pub struct Blowfish { s: [[u32; 256]; 4], p: [u32; 18], @@ -60,17 +64,17 @@ impl Blowfish { for i in 0..18 { self.p[i] ^= next_u32_wrap(key, &mut key_pos); } - let mut lr = (0u32, 0u32); + let mut lr = [0u32; 2]; for i in 0..9 { - lr = self.encrypt(lr.0, lr.1); - self.p[2 * i] = lr.0; - self.p[2 * i + 1] = lr.1; + lr = self.encrypt(lr); + self.p[2 * i] = lr[0]; + self.p[2 * i + 1] = lr[1]; } for i in 0..4 { for j in 0..128 { - lr = self.encrypt(lr.0, lr.1); - self.s[i][2 * j] = lr.0; - self.s[i][2 * j + 1] = lr.1; + lr = self.encrypt(lr); + self.s[i][2 * j] = lr[0]; + self.s[i][2 * j + 1] = lr[1]; } } } @@ -84,7 +88,7 @@ impl Blowfish { (a.wrapping_add(b) ^ c).wrapping_add(d) } - fn encrypt(&self, mut l: u32, mut r: u32) -> (u32, u32) { + fn encrypt(&self, [mut l, mut r]: [u32; 2]) -> [u32; 2] { for i in 0..8 { l ^= self.p[2 * i]; r ^= self.round_function(l); @@ -93,10 +97,10 @@ impl Blowfish { } l ^= self.p[16]; r ^= self.p[17]; - (r, l) + [r, l] } - fn decrypt(&self, mut l: u32, mut r: u32) -> (u32, u32) { + fn decrypt(&self, [mut l, mut r]: [u32; 2]) -> [u32; 2] { for i in (1..9).rev() { l ^= self.p[2 * i + 1]; r ^= self.round_function(l); @@ -105,15 +109,19 @@ impl Blowfish { } l ^= self.p[1]; r ^= self.p[0]; - (r, l) + [r, l] } } -impl NewBlockCipher for Blowfish { +impl BlockCipher for Blowfish {} + +impl KeySizeUser for Blowfish { type KeySize = U56; +} - fn new(key: &GenericArray) -> Self { - Self::new_from_slice(&key).unwrap() +impl KeyInit for Blowfish { + fn new(key: &Key) -> Self { + Self::new_from_slice(&key[..]).unwrap() } fn new_from_slice(key: &[u8]) -> Result { @@ -126,33 +134,59 @@ impl NewBlockCipher for Blowfish { } } -impl BlockCipher for Blowfish { - type BlockSize = U8; - type ParBlocks = U1; +impl fmt::Debug for Blowfish { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Blowfish { ... }") + } +} + +impl AlgorithmName for Blowfish { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Blowfish") + } } -impl BlockEncrypt for Blowfish { - #[inline] - fn encrypt_block(&self, block: &mut Block) { - let l = T::read_u32(&block[..4]); - let r = T::read_u32(&block[4..]); - let (l, r) = self.encrypt(l, r); - T::write_u32(&mut block[..4], l); - T::write_u32(&mut block[4..], r); +impl fmt::Debug for Blowfish { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Blowfish { ... }") } } -impl BlockDecrypt for Blowfish { - #[inline] - fn decrypt_block(&self, block: &mut Block) { - let l = T::read_u32(&block[..4]); - let r = T::read_u32(&block[4..]); - let (l, r) = self.decrypt(l, r); - T::write_u32(&mut block[..4], l); - T::write_u32(&mut block[4..], r); +impl AlgorithmName for Blowfish { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Blowfish") } } +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl Drop for Blowfish { + fn drop(&mut self) { + self.s.zeroize(); + self.p.zeroize(); + } +} + +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl ZeroizeOnDrop for Blowfish {} + +cipher::impl_simple_block_encdec!( + Blowfish, U8, cipher, block, + encrypt: { + let mut b = [0u32; 2]; + T::read_u32_into(block.get_in(), &mut b); + b = cipher.encrypt(b); + T::write_u32_into(&b, block.get_out()); + } + decrypt: { + let mut b = [0u32; 2]; + T::read_u32_into(block.get_in(), &mut b); + b = cipher.decrypt(b); + T::write_u32_into(&b, block.get_out()); + } +); + /// Bcrypt extension of blowfish #[cfg(feature = "bcrypt")] impl Blowfish { @@ -162,31 +196,31 @@ impl Blowfish { for i in 0..18 { self.p[i] ^= next_u32_wrap(key, &mut key_pos); } - let mut lr = (0u32, 0u32); + let mut lr = [0u32; 2]; let mut salt_pos = 0; for i in 0..9 { - let lk = next_u32_wrap(salt, &mut salt_pos); - let rk = next_u32_wrap(salt, &mut salt_pos); - lr = self.encrypt(lr.0 ^ lk, lr.1 ^ rk); + lr[0] ^= next_u32_wrap(salt, &mut salt_pos); + lr[1] ^= next_u32_wrap(salt, &mut salt_pos); + lr = self.encrypt(lr); - self.p[2 * i] = lr.0; - self.p[2 * i + 1] = lr.1; + self.p[2 * i] = lr[0]; + self.p[2 * i + 1] = lr[1]; } for i in 0..4 { for j in 0..64 { - let lk = next_u32_wrap(salt, &mut salt_pos); - let rk = next_u32_wrap(salt, &mut salt_pos); - lr = self.encrypt(lr.0 ^ lk, lr.1 ^ rk); + lr[0] ^= next_u32_wrap(salt, &mut salt_pos); + lr[1] ^= next_u32_wrap(salt, &mut salt_pos); + lr = self.encrypt(lr); - self.s[i][4 * j] = lr.0; - self.s[i][4 * j + 1] = lr.1; + self.s[i][4 * j] = lr[0]; + self.s[i][4 * j + 1] = lr[1]; - let lk = next_u32_wrap(salt, &mut salt_pos); - let rk = next_u32_wrap(salt, &mut salt_pos); - lr = self.encrypt(lr.0 ^ lk, lr.1 ^ rk); + lr[0] ^= next_u32_wrap(salt, &mut salt_pos); + lr[1] ^= next_u32_wrap(salt, &mut salt_pos); + lr = self.encrypt(lr); - self.s[i][4 * j + 2] = lr.0; - self.s[i][4 * j + 3] = lr.1; + self.s[i][4 * j + 2] = lr[0]; + self.s[i][4 * j + 3] = lr[1]; } } } @@ -197,8 +231,8 @@ impl Blowfish { } /// Encrypt - pub fn bc_encrypt(&self, l: u32, r: u32) -> (u32, u32) { - self.encrypt(l, r) + pub fn bc_encrypt(&self, lr: [u32; 2]) -> [u32; 2] { + self.encrypt(lr) } /// Expand key @@ -206,5 +240,3 @@ impl Blowfish { self.expand_key(key) } } - -opaque_debug::implement!(Blowfish); diff --git a/blowfish/tests/lib.rs b/blowfish/tests/mod.rs similarity index 100% rename from blowfish/tests/lib.rs rename to blowfish/tests/mod.rs diff --git a/cast5/.gitignore b/cast5/.gitignore deleted file mode 100644 index 1de56593..00000000 --- a/cast5/.gitignore +++ /dev/null @@ -1 +0,0 @@ -target \ No newline at end of file diff --git a/cast5/CHANGELOG.md b/cast5/CHANGELOG.md index 1fda946a..defd6ab5 100644 --- a/cast5/CHANGELOG.md +++ b/cast5/CHANGELOG.md @@ -5,9 +5,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 0.11.0 (2022-02-10) +### Changed +- Bump `cipher` dependency to v0.4 ([#284]) + +[#284]: https://github.com/RustCrypto/block-ciphers/pull/284 + ## 0.10.0 (2021-04-29) ### Changed -- Bump `cipher` dependency to v0.3 release ([#235]) +- Bump `cipher` dependency to v0.3 ([#235]) [#235]: https://github.com/RustCrypto/block-ciphers/pull/235 diff --git a/cast5/Cargo.toml b/cast5/Cargo.toml index ad2a6988..e2aa7cb1 100644 --- a/cast5/Cargo.toml +++ b/cast5/Cargo.toml @@ -1,24 +1,27 @@ [package] name = "cast5" -version = "0.10.0" +version = "0.11.0" # Also update html_root_url in lib.rs when bumping this description = "CAST5 block cipher" authors = ["RustCrypto Developers"] license = "MIT OR Apache-2.0" +edition = "2021" +rust-version = "1.56" readme = "README.md" -edition = "2018" documentation = "https://docs.rs/cast5" repository = "https://github.com/RustCrypto/block-ciphers" keywords = ["crypto", "cast5", "block-cipher"] categories = ["cryptography", "no-std"] [dependencies] -cipher = "0.3" -opaque-debug = "0.3" -byteorder = { version = "1", default-features = false } +cipher = "0.4" [dev-dependencies] -cipher = { version = "0.3", features = ["dev"] } -hex-literal = "0.2" +cipher = { version = "0.4", features = ["dev"] } +hex-literal = "0.3" [features] -default = [] +zeroize = ["cipher/zeroize"] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] diff --git a/cast5/README.md b/cast5/README.md index 2a48f6c3..1a0665f6 100644 --- a/cast5/README.md +++ b/cast5/README.md @@ -28,7 +28,7 @@ USE AT YOUR OWN RISK! ## Minimum Supported Rust Version -Rust **1.41** or higher. +Rust **1.56** or higher. Minimum supported Rust version can be changed in the future, but it will be done with a minor version bump. @@ -60,7 +60,7 @@ dual licensed as above, without any additional terms or conditions. [docs-image]: https://docs.rs/cast5/badge.svg [docs-link]: https://docs.rs/cast5/ [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg -[rustc-image]: https://img.shields.io/badge/rustc-1.41+-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.56+-blue.svg [hazmat-image]: https://img.shields.io/badge/crypto-hazmat%E2%9A%A0-red.svg [hazmat-link]: https://github.com/RustCrypto/meta/blob/master/HAZMAT.md [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg diff --git a/cast5/benches/lib.rs b/cast5/benches/lib.rs deleted file mode 100644 index af35b42c..00000000 --- a/cast5/benches/lib.rs +++ /dev/null @@ -1,3 +0,0 @@ -#![feature(test)] - -cipher::block_cipher_bench!(cast5::Cast5, 16); diff --git a/cast5/benches/mod.rs b/cast5/benches/mod.rs new file mode 100644 index 00000000..6ab20fb3 --- /dev/null +++ b/cast5/benches/mod.rs @@ -0,0 +1,8 @@ +#![feature(test)] +extern crate test; + +use cast5::Cast5; +use cipher::{block_decryptor_bench, block_encryptor_bench}; + +block_encryptor_bench!(Key: Cast5, cast5_encrypt_block, cast5_encrypt_blocks); +block_decryptor_bench!(Key: Cast5, cast5_decrypt_block, cast5_decrypt_blocks); diff --git a/cast5/src/cast5.rs b/cast5/src/cast5.rs deleted file mode 100644 index 98db21a7..00000000 --- a/cast5/src/cast5.rs +++ /dev/null @@ -1,202 +0,0 @@ -use cipher::{ - consts::{U1, U16, U8}, - errors::InvalidLength, - generic_array::GenericArray, - BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher, -}; - -use byteorder::{BigEndian, ByteOrder}; - -use crate::{ - consts::{S1, S2, S3, S4}, - schedule::key_schedule, -}; - -type Block = GenericArray; - -/// The CAST5 block cipher. -#[derive(Clone, Copy)] -pub struct Cast5 { - masking: [u32; 16], - rotate: [u8; 16], - /// If this is set to true, it means a small key is used and only 12 rounds instead of 16 - /// rounds are used in the algorithm. - small_key: bool, -} - -impl Cast5 { - fn init_state(key_len: usize) -> Cast5 { - let small_key = key_len <= 10; - - Cast5 { - masking: [0u32; 16], - rotate: [0u8; 16], - small_key, - } - } - - /// Implements the key schedule according to RFC 2144 2.4. - /// https://tools.ietf.org/html/rfc2144#section-2.4 - fn key_schedule(&mut self, key: &[u8]) { - let mut x = [0; 4]; - BigEndian::read_u32_into(&key, &mut x); - - let mut z = [0u32; 4]; - let mut k = [0u32; 16]; - - key_schedule(&mut x, &mut z, &mut k); - self.masking[..].clone_from_slice(&k[..]); - - key_schedule(&mut x, &mut z, &mut k); - - for (i, ki) in k.iter().enumerate() { - self.rotate[i] = (ki & 0x1f) as u8; - } - } -} - -macro_rules! f1 { - ($D:expr, $m:expr, $r:expr) => {{ - let i = ($m.wrapping_add($D)).rotate_left(u32::from($r)); - (S1[(i >> 24) as usize] ^ S2[((i >> 16) & 0xff) as usize]) - .wrapping_sub(S3[((i >> 8) & 0xff) as usize]) - .wrapping_add(S4[(i & 0xff) as usize]) - }}; -} - -macro_rules! f2 { - ($D:expr, $m:expr, $r:expr) => {{ - let i = ($m ^ $D).rotate_left(u32::from($r)); - S1[(i >> 24) as usize] - .wrapping_sub(S2[((i >> 16) & 0xff) as usize]) - .wrapping_add(S3[((i >> 8) & 0xff) as usize]) - ^ S4[(i & 0xff) as usize] - }}; -} - -macro_rules! f3 { - ($D:expr, $m:expr, $r:expr) => {{ - let i = ($m.wrapping_sub($D)).rotate_left(u32::from($r)); - (S1[(i >> 24) as usize].wrapping_add(S2[((i >> 16) & 0xff) as usize]) - ^ S3[((i >> 8) & 0xff) as usize]) - .wrapping_sub(S4[(i & 0xff) as usize]) - }}; -} - -impl NewBlockCipher for Cast5 { - type KeySize = U16; - - fn new(key: &GenericArray) -> Self { - Self::new_from_slice(&key).unwrap() - } - - fn new_from_slice(key: &[u8]) -> Result { - // Available key sizes are 40...128 bits. - if key.len() < 5 || key.len() > 16 { - return Err(InvalidLength); - } - let mut cast5 = Cast5::init_state(key.len()); - - if key.len() < 16 { - // Pad keys that are less than 128 bits long. - let mut padded_key = [0u8; 16]; - padded_key[..key.len()].copy_from_slice(key); - cast5.key_schedule(&padded_key[..]); - } else { - cast5.key_schedule(key); - } - Ok(cast5) - } -} - -impl BlockCipher for Cast5 { - type BlockSize = U8; - type ParBlocks = U1; -} - -impl BlockEncrypt for Cast5 { - #[inline] - fn encrypt_block(&self, block: &mut Block) { - let masking = self.masking; - let rotate = self.rotate; - - // (L0,R0) <-- (m1...m64). (Split the plaintext into left and - // right 32-bit halves L0 = m1...m32 and R0 = m33...m64.) - let l = BigEndian::read_u32(&block[0..4]); - let r = BigEndian::read_u32(&block[4..8]); - // (16 rounds) for i from 1 to 16, compute Li and Ri as follows: - // Li = Ri-1; - // Ri = Li-1 ^ f(Ri-1,Kmi,Kri), where f is defined in Section 2.2 - // (f is of Type 1, Type 2, or Type 3, depending on i). - // - // Rounds 1, 4, 7, 10, 13, and 16 use f function Type 1. - // Rounds 2, 5, 8, 11, and 14 use f function Type 2. - // Rounds 3, 6, 9, 12, and 15 use f function Type 3. - - let (l, r) = (r, l ^ f1!(r, masking[0], rotate[0])); - let (l, r) = (r, l ^ f2!(r, masking[1], rotate[1])); - let (l, r) = (r, l ^ f3!(r, masking[2], rotate[2])); - let (l, r) = (r, l ^ f1!(r, masking[3], rotate[3])); - let (l, r) = (r, l ^ f2!(r, masking[4], rotate[4])); - let (l, r) = (r, l ^ f3!(r, masking[5], rotate[5])); - let (l, r) = (r, l ^ f1!(r, masking[6], rotate[6])); - let (l, r) = (r, l ^ f2!(r, masking[7], rotate[7])); - let (l, r) = (r, l ^ f3!(r, masking[8], rotate[8])); - let (l, r) = (r, l ^ f1!(r, masking[9], rotate[9])); - let (l, r) = (r, l ^ f2!(r, masking[10], rotate[10])); - let (l, r) = (r, l ^ f3!(r, masking[11], rotate[11])); - - let (l, r) = if self.small_key { - (l, r) - } else { - // Rounds 13..16 are only executed for keys > 80 bits. - let (l, r) = (r, l ^ f1!(r, masking[12], rotate[12])); - let (l, r) = (r, l ^ f2!(r, masking[13], rotate[13])); - let (l, r) = (r, l ^ f3!(r, masking[14], rotate[14])); - (r, l ^ f1!(r, masking[15], rotate[15])) - }; - - // c1...c64 <-- (R16,L16). (Exchange final blocks L16, R16 and - // concatenate to form the ciphertext.) - BigEndian::write_u32(&mut block[0..4], r); - BigEndian::write_u32(&mut block[4..8], l); - } -} - -impl BlockDecrypt for Cast5 { - #[inline] - fn decrypt_block(&self, block: &mut Block) { - let masking = self.masking; - let rotate = self.rotate; - - let l = BigEndian::read_u32(&block[0..4]); - let r = BigEndian::read_u32(&block[4..8]); - - let (l, r) = if self.small_key { - (l, r) - } else { - let (l, r) = (r, l ^ f1!(r, masking[15], rotate[15])); - let (l, r) = (r, l ^ f3!(r, masking[14], rotate[14])); - let (l, r) = (r, l ^ f2!(r, masking[13], rotate[13])); - (r, l ^ f1!(r, masking[12], rotate[12])) - }; - - let (l, r) = (r, l ^ f3!(r, masking[11], rotate[11])); - let (l, r) = (r, l ^ f2!(r, masking[10], rotate[10])); - let (l, r) = (r, l ^ f1!(r, masking[9], rotate[9])); - let (l, r) = (r, l ^ f3!(r, masking[8], rotate[8])); - let (l, r) = (r, l ^ f2!(r, masking[7], rotate[7])); - let (l, r) = (r, l ^ f1!(r, masking[6], rotate[6])); - let (l, r) = (r, l ^ f3!(r, masking[5], rotate[5])); - let (l, r) = (r, l ^ f2!(r, masking[4], rotate[4])); - let (l, r) = (r, l ^ f1!(r, masking[3], rotate[3])); - let (l, r) = (r, l ^ f3!(r, masking[2], rotate[2])); - let (l, r) = (r, l ^ f2!(r, masking[1], rotate[1])); - let (l, r) = (r, l ^ f1!(r, masking[0], rotate[0])); - - BigEndian::write_u32(&mut block[0..4], r); - BigEndian::write_u32(&mut block[4..8], l); - } -} - -opaque_debug::implement!(Cast5); diff --git a/cast5/src/lib.rs b/cast5/src/lib.rs index a96b9740..0e0773d4 100644 --- a/cast5/src/lib.rs +++ b/cast5/src/lib.rs @@ -1,15 +1,13 @@ -//! CAST5 block cipher. -//! -//! Implementation according to [RFC 2144](https://tools.ietf.org/html/rfc2144). +//! Pure Rust implementation of the [CAST5] block cipher ([RFC 2144]). //! //! # Usage example //! ``` //! use cast5::cipher::generic_array::GenericArray; -//! use cast5::cipher::{BlockCipher, BlockEncrypt, BlockDecrypt, NewBlockCipher}; +//! use cast5::cipher::{Key, Block, BlockEncrypt, BlockDecrypt, KeyInit}; //! use cast5::Cast5; //! -//! let key = GenericArray::from_slice(&[0u8; 16]); -//! let mut block = GenericArray::clone_from_slice(&[0u8; 8]); +//! let key = GenericArray::from([0u8; 16]); +//! let mut block = GenericArray::from([0u8; 8]); //! // Initialize cipher //! let cipher = Cast5::new(&key); //! @@ -20,19 +18,247 @@ //! cipher.decrypt_block(&mut block); //! assert_eq!(block, block_copy); //! ``` +//! +//! [CAST5]: https://en.wikipedia.org/wiki/CAST-128 +//! [RFC 2144]: https://tools.ietf.org/html/rfc2144 #![no_std] #![doc( - html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg", - html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg" + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg", + html_root_url = "https://docs.rs/cast5/0.11.0" )] -#![forbid(unsafe_code)] +#![deny(unsafe_code)] +#![cfg_attr(docsrs, feature(doc_cfg))] #![warn(missing_docs, rust_2018_idioms)] -pub use cipher::{self, BlockCipher}; +pub use cipher; -mod cast5; mod consts; mod schedule; -pub use crate::cast5::Cast5; +use cipher::{ + consts::{U16, U8}, + AlgorithmName, BlockCipher, InvalidLength, Key, KeyInit, KeySizeUser, +}; +use core::fmt; + +#[cfg(feature = "zeroize")] +use cipher::zeroize::{Zeroize, ZeroizeOnDrop}; + +use consts::{S1, S2, S3, S4}; +use schedule::key_schedule; + +/// The CAST5 block cipher. +#[derive(Clone)] +pub struct Cast5 { + masking: [u32; 16], + rotate: [u8; 16], + /// If this is set to true, it means a small key is used and only 12 rounds instead of 16 + /// rounds are used in the algorithm. + small_key: bool, +} + +impl Cast5 { + fn init_state(key_len: usize) -> Cast5 { + let small_key = key_len <= 10; + + Cast5 { + masking: [0u32; 16], + rotate: [0u8; 16], + small_key, + } + } + + /// Implements the key schedule according to RFC 2144 2.4. + /// https://tools.ietf.org/html/rfc2144#section-2.4 + fn key_schedule(&mut self, key: &[u8]) { + let mut x = [ + u32::from_be_bytes(key[0..4].try_into().unwrap()), + u32::from_be_bytes(key[4..8].try_into().unwrap()), + u32::from_be_bytes(key[8..12].try_into().unwrap()), + u32::from_be_bytes(key[12..16].try_into().unwrap()), + ]; + + let mut z = [0u32; 4]; + let mut k = [0u32; 16]; + + key_schedule(&mut x, &mut z, &mut k); + self.masking[..].clone_from_slice(&k[..]); + + key_schedule(&mut x, &mut z, &mut k); + + for (i, ki) in k.iter().enumerate() { + self.rotate[i] = (ki & 0x1f) as u8; + } + } +} + +macro_rules! f1 { + ($D:expr, $m:expr, $r:expr) => {{ + let i = ($m.wrapping_add($D)).rotate_left(u32::from($r)); + (S1[(i >> 24) as usize] ^ S2[((i >> 16) & 0xff) as usize]) + .wrapping_sub(S3[((i >> 8) & 0xff) as usize]) + .wrapping_add(S4[(i & 0xff) as usize]) + }}; +} + +macro_rules! f2 { + ($D:expr, $m:expr, $r:expr) => {{ + let i = ($m ^ $D).rotate_left(u32::from($r)); + S1[(i >> 24) as usize] + .wrapping_sub(S2[((i >> 16) & 0xff) as usize]) + .wrapping_add(S3[((i >> 8) & 0xff) as usize]) + ^ S4[(i & 0xff) as usize] + }}; +} + +macro_rules! f3 { + ($D:expr, $m:expr, $r:expr) => {{ + let i = ($m.wrapping_sub($D)).rotate_left(u32::from($r)); + (S1[(i >> 24) as usize].wrapping_add(S2[((i >> 16) & 0xff) as usize]) + ^ S3[((i >> 8) & 0xff) as usize]) + .wrapping_sub(S4[(i & 0xff) as usize]) + }}; +} + +impl BlockCipher for Cast5 {} + +impl KeySizeUser for Cast5 { + type KeySize = U16; +} + +impl KeyInit for Cast5 { + fn new(key: &Key) -> Self { + Self::new_from_slice(key).unwrap() + } + + fn new_from_slice(key: &[u8]) -> Result { + // Available key sizes are 40...128 bits. + if key.len() < 5 || key.len() > 16 { + return Err(InvalidLength); + } + let mut cast5 = Cast5::init_state(key.len()); + + if key.len() < 16 { + // Pad keys that are less than 128 bits long. + let mut padded_key = [0u8; 16]; + padded_key[..key.len()].copy_from_slice(key); + cast5.key_schedule(&padded_key[..]); + } else { + cast5.key_schedule(key); + } + Ok(cast5) + } +} + +impl fmt::Debug for Cast5 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Cast5 { ... }") + } +} + +impl AlgorithmName for Cast5 { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Cast5") + } +} + +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl Drop for Cast5 { + fn drop(&mut self) { + self.masking.zeroize(); + self.rotate.zeroize(); + self.small_key.zeroize(); + } +} + +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl ZeroizeOnDrop for Cast5 {} + +cipher::impl_simple_block_encdec!( + Cast5, U8, cipher, block, + encrypt: { + let masking = cipher.masking; + let rotate = cipher.rotate; + + // (L0,R0) <-- (m1...m64). (Split the plaintext into left and + // right 32-bit halves L0 = m1...m32 and R0 = m33...m64.) + let b = block.get_in(); + let l = u32::from_be_bytes(b[0..4].try_into().unwrap()); + let r = u32::from_be_bytes(b[4..8].try_into().unwrap()); + // (16 rounds) for i from 1 to 16, compute Li and Ri as follows: + // Li = Ri-1; + // Ri = Li-1 ^ f(Ri-1,Kmi,Kri), where f is defined in Section 2.2 + // (f is of Type 1, Type 2, or Type 3, depending on i). + // + // Rounds 1, 4, 7, 10, 13, and 16 use f function Type 1. + // Rounds 2, 5, 8, 11, and 14 use f function Type 2. + // Rounds 3, 6, 9, 12, and 15 use f function Type 3. + + let (l, r) = (r, l ^ f1!(r, masking[0], rotate[0])); + let (l, r) = (r, l ^ f2!(r, masking[1], rotate[1])); + let (l, r) = (r, l ^ f3!(r, masking[2], rotate[2])); + let (l, r) = (r, l ^ f1!(r, masking[3], rotate[3])); + let (l, r) = (r, l ^ f2!(r, masking[4], rotate[4])); + let (l, r) = (r, l ^ f3!(r, masking[5], rotate[5])); + let (l, r) = (r, l ^ f1!(r, masking[6], rotate[6])); + let (l, r) = (r, l ^ f2!(r, masking[7], rotate[7])); + let (l, r) = (r, l ^ f3!(r, masking[8], rotate[8])); + let (l, r) = (r, l ^ f1!(r, masking[9], rotate[9])); + let (l, r) = (r, l ^ f2!(r, masking[10], rotate[10])); + let (l, r) = (r, l ^ f3!(r, masking[11], rotate[11])); + + let (l, r) = if cipher.small_key { + (l, r) + } else { + // Rounds 13..16 are only executed for keys > 80 bits. + let (l, r) = (r, l ^ f1!(r, masking[12], rotate[12])); + let (l, r) = (r, l ^ f2!(r, masking[13], rotate[13])); + let (l, r) = (r, l ^ f3!(r, masking[14], rotate[14])); + (r, l ^ f1!(r, masking[15], rotate[15])) + }; + + // c1...c64 <-- (R16,L16). (Exchange final blocks L16, R16 and + // concatenate to form the ciphertext.) + let block = block.get_out(); + block[0..4].copy_from_slice(&r.to_be_bytes()); + block[4..8].copy_from_slice(&l.to_be_bytes()); + } + decrypt: { + let masking = cipher.masking; + let rotate = cipher.rotate; + + let b = block.get_in(); + let l = u32::from_be_bytes(b[0..4].try_into().unwrap()); + let r = u32::from_be_bytes(b[4..8].try_into().unwrap()); + + let (l, r) = if cipher.small_key { + (l, r) + } else { + let (l, r) = (r, l ^ f1!(r, masking[15], rotate[15])); + let (l, r) = (r, l ^ f3!(r, masking[14], rotate[14])); + let (l, r) = (r, l ^ f2!(r, masking[13], rotate[13])); + (r, l ^ f1!(r, masking[12], rotate[12])) + }; + + let (l, r) = (r, l ^ f3!(r, masking[11], rotate[11])); + let (l, r) = (r, l ^ f2!(r, masking[10], rotate[10])); + let (l, r) = (r, l ^ f1!(r, masking[9], rotate[9])); + let (l, r) = (r, l ^ f3!(r, masking[8], rotate[8])); + let (l, r) = (r, l ^ f2!(r, masking[7], rotate[7])); + let (l, r) = (r, l ^ f1!(r, masking[6], rotate[6])); + let (l, r) = (r, l ^ f3!(r, masking[5], rotate[5])); + let (l, r) = (r, l ^ f2!(r, masking[4], rotate[4])); + let (l, r) = (r, l ^ f1!(r, masking[3], rotate[3])); + let (l, r) = (r, l ^ f3!(r, masking[2], rotate[2])); + let (l, r) = (r, l ^ f2!(r, masking[1], rotate[1])); + let (l, r) = (r, l ^ f1!(r, masking[0], rotate[0])); + + let block = block.get_out(); + block[0..4].copy_from_slice(&r.to_be_bytes()); + block[4..8].copy_from_slice(&l.to_be_bytes()); + } +); diff --git a/cast5/tests/lib.rs b/cast5/tests/mod.rs similarity index 79% rename from cast5/tests/lib.rs rename to cast5/tests/mod.rs index 2517729a..8d0a2500 100644 --- a/cast5/tests/lib.rs +++ b/cast5/tests/mod.rs @@ -1,5 +1,5 @@ use cast5::Cast5; -use cipher::{generic_array::GenericArray, BlockDecrypt, BlockEncrypt, NewBlockCipher}; +use cipher::{generic_array::GenericArray, BlockDecrypt, BlockEncrypt, KeyInit}; use hex_literal::hex; /// Test vectors from RFC 2144 Appendix B.1 @@ -9,10 +9,10 @@ fn rfc2144_b1() { let key128 = hex!("0123456712345678234567893456789A"); let key80 = hex!("01234567123456782345"); let key40 = hex!("0123456712"); - let ct128 = GenericArray::clone_from_slice(&hex!("238B4FE5847E44B2")); - let ct80 = GenericArray::clone_from_slice(&hex!("EB6A711A2C02271B")); - let ct40 = GenericArray::clone_from_slice(&hex!("7AC816D16E9B302E")); - let pt = GenericArray::clone_from_slice(&hex!("0123456789ABCDEF")); + let ct128 = GenericArray::from(hex!("238B4FE5847E44B2")); + let ct80 = GenericArray::from(hex!("EB6A711A2C02271B")); + let ct40 = GenericArray::from(hex!("7AC816D16E9B302E")); + let pt = GenericArray::from(hex!("0123456789ABCDEF")); let mut buf = pt.clone(); @@ -57,15 +57,16 @@ fn full_maintance_test() { let mut br = GenericArray::from_mut_slice(br); for _ in 0..count { - let mut k = bl.to_vec(); - k.extend(br.to_vec()); - let c = Cast5::new(&GenericArray::from_slice(&k)); + let mut k = GenericArray::from([0u8; 16]); + k[..8].copy_from_slice(bl); + k[8..].copy_from_slice(br); + let c = Cast5::new(&k); c.encrypt_block(&mut al); c.encrypt_block(&mut ar); - let mut k = al.to_vec(); - k.extend(ar.to_vec()); - let c = Cast5::new(&GenericArray::from_slice(&k)); + k[..8].copy_from_slice(al); + k[8..].copy_from_slice(ar); + let c = Cast5::new(&k); c.encrypt_block(&mut bl); c.encrypt_block(&mut br); } diff --git a/des/CHANGELOG.md b/des/CHANGELOG.md index 8cc4e1c1..5a1ef017 100644 --- a/des/CHANGELOG.md +++ b/des/CHANGELOG.md @@ -5,9 +5,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 0.8.0 (2022-02-10) +### Changed +- Bump `cipher` dependency to v0.4 ([#284]) + +[#284]: https://github.com/RustCrypto/block-ciphers/pull/284 + ## 0.7.0 (2021-04-29) ### Changed -- Bump `cipher` dependency to v0.3 release ([#235]) +- Bump `cipher` dependency to v0.3 ([#235]) [#235]: https://github.com/RustCrypto/block-ciphers/pull/235 diff --git a/des/Cargo.toml b/des/Cargo.toml index 159099e3..89a729e3 100644 --- a/des/Cargo.toml +++ b/des/Cargo.toml @@ -1,20 +1,26 @@ [package] name = "des" -version = "0.7.0" +version = "0.8.0" # Also update html_root_url in lib.rs when bumping this description = "DES and Triple DES (3DES, TDES) block ciphers implementation" authors = ["RustCrypto Developers"] license = "MIT OR Apache-2.0" +edition = "2021" +rust-version = "1.56" readme = "README.md" -edition = "2018" documentation = "https://docs.rs/des" repository = "https://github.com/RustCrypto/block-ciphers" keywords = ["crypto", "des", "tdes", "block-cipher"] categories = ["cryptography", "no-std"] [dependencies] -cipher = "0.3" -byteorder = { version = "1", default-features = false } -opaque-debug = "0.3" +cipher = "0.4" [dev-dependencies] -cipher = { version = "0.3", features = ["dev"] } +cipher = { version = "0.4", features = ["dev"] } + +[features] +zeroize = ["cipher/zeroize"] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] diff --git a/des/README.md b/des/README.md index 45ea13fd..732c7f64 100644 --- a/des/README.md +++ b/des/README.md @@ -28,7 +28,7 @@ USE AT YOUR OWN RISK! ## Minimum Supported Rust Version -Rust **1.41** or higher. +Rust **1.56** or higher. Minimum supported Rust version can be changed in the future, but it will be done with a minor version bump. @@ -60,7 +60,7 @@ dual licensed as above, without any additional terms or conditions. [docs-image]: https://docs.rs/des/badge.svg [docs-link]: https://docs.rs/des/ [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg -[rustc-image]: https://img.shields.io/badge/rustc-1.41+-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.56+-blue.svg [hazmat-image]: https://img.shields.io/badge/crypto-hazmat%E2%9A%A0-red.svg [hazmat-link]: https://github.com/RustCrypto/meta/blob/master/HAZMAT.md [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg diff --git a/des/benches/des.rs b/des/benches/des.rs deleted file mode 100644 index b43a301a..00000000 --- a/des/benches/des.rs +++ /dev/null @@ -1,3 +0,0 @@ -#![feature(test)] - -cipher::block_cipher_bench!(des::Des, 8); diff --git a/des/benches/mod.rs b/des/benches/mod.rs new file mode 100644 index 00000000..06a70a88 --- /dev/null +++ b/des/benches/mod.rs @@ -0,0 +1,19 @@ +#![feature(test)] +extern crate test; + +use cipher::{block_decryptor_bench, block_encryptor_bench}; +use des::{Des, TdesEde3}; + +block_encryptor_bench!(Key: Des, des_encrypt_block, des_encrypt_blocks); +block_decryptor_bench!(Key: Des, des_decrypt_block, des_decrypt_blocks); + +block_encryptor_bench!( + Key: TdesEde3, + tdes_ede3_encrypt_block, + tdes_ede3_encrypt_blocks, +); +block_decryptor_bench!( + Key: TdesEde3, + tdes_ede3_decrypt_block, + tdes_ede3_decrypt_blocks, +); diff --git a/des/benches/tdes.rs b/des/benches/tdes.rs deleted file mode 100644 index bb35e9e6..00000000 --- a/des/benches/tdes.rs +++ /dev/null @@ -1,3 +0,0 @@ -#![feature(test)] - -cipher::block_cipher_bench!(des::TdesEde3, 24); diff --git a/des/src/des.rs b/des/src/des.rs index 0620839f..f4e1c933 100644 --- a/des/src/des.rs +++ b/des/src/des.rs @@ -2,17 +2,16 @@ #![allow(clippy::unreadable_literal)] -use byteorder::{ByteOrder, BE}; -use cipher::{ - consts::{U1, U8}, - generic_array::GenericArray, - BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher, -}; +use cipher::{consts::U8, AlgorithmName, BlockCipher, Key, KeyInit, KeySizeUser}; +use core::fmt; + +#[cfg(feature = "zeroize")] +use cipher::zeroize::{Zeroize, ZeroizeOnDrop}; use crate::consts::{SBOXES, SHIFTS}; /// Data Encryption Standard (DES) block cipher. -#[derive(Copy, Clone)] +#[derive(Clone)] pub struct Des { pub(crate) keys: [u64; 16], } @@ -186,33 +185,54 @@ impl Des { } } -impl NewBlockCipher for Des { +impl BlockCipher for Des {} + +impl KeySizeUser for Des { type KeySize = U8; +} - fn new(key: &GenericArray) -> Self { - Des { - keys: gen_keys(BE::read_u64(key)), - } +impl KeyInit for Des { + #[inline] + fn new(key: &Key) -> Self { + let keys = gen_keys(u64::from_be_bytes(key.clone().into())); + Self { keys } } } -impl BlockCipher for Des { - type BlockSize = U8; - type ParBlocks = U1; +impl fmt::Debug for Des { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Des { ... }") + } } -impl BlockEncrypt for Des { - fn encrypt_block(&self, block: &mut GenericArray) { - let data = BE::read_u64(block); - BE::write_u64(block, self.encrypt(data)); +impl AlgorithmName for Des { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Des") } } -impl BlockDecrypt for Des { - fn decrypt_block(&self, block: &mut GenericArray) { - let data = BE::read_u64(block); - BE::write_u64(block, self.decrypt(data)); +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl Drop for Des { + fn drop(&mut self) { + self.keys.zeroize(); } } -opaque_debug::implement!(Des); +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl ZeroizeOnDrop for Des {} + +cipher::impl_simple_block_encdec!( + Des, U8, cipher, block, + encrypt: { + let mut data = u64::from_be_bytes(block.clone_in().into()); + data = cipher.encrypt(data); + block.get_out().copy_from_slice(&data.to_be_bytes()); + } + decrypt: { + let mut data = u64::from_be_bytes(block.clone_in().into()); + data = cipher.decrypt(data); + block.get_out().copy_from_slice(&data.to_be_bytes()); + } +); diff --git a/des/src/lib.rs b/des/src/lib.rs index 73f4bfd0..955a35d9 100644 --- a/des/src/lib.rs +++ b/des/src/lib.rs @@ -1,14 +1,19 @@ -//! Pure Rust implementation of the [DES cipher][1], including triple DES (3DES). +//! Pure Rust implementation of the [Data Encryption Standard][DES] (DES), +//! including [Triple DES] (TDES, 3DES) block ciphers. //! -//! [1]: https://en.wikipedia.org/wiki/Data_Encryption_Standard +//! [DES]: https://en.wikipedia.org/wiki/Data_Encryption_Standard +//! [Triple DES]: https://en.wikipedia.org/wiki/Triple_DES #![no_std] #![doc( - html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg", - html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg" + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg", + html_root_url = "https://docs.rs/des/0.8.0" )] -#![forbid(unsafe_code)] +#![deny(unsafe_code)] +#![cfg_attr(docsrs, feature(doc_cfg))] #![warn(missing_docs, rust_2018_idioms)] +#![allow(clippy::clone_on_copy)] // TODO: remove on migration to const generics pub use cipher; diff --git a/des/src/tdes.rs b/des/src/tdes.rs index 578e11ff..ad210824 100644 --- a/des/src/tdes.rs +++ b/des/src/tdes.rs @@ -1,222 +1,249 @@ -//! Triple DES (3DES) block cipher. +//! Triple DES (3DES) block ciphers. use crate::des::{gen_keys, Des}; -use byteorder::{ByteOrder, BE}; use cipher::{ - consts::{U1, U16, U24, U8}, - generic_array::GenericArray, - BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher, + consts::{U16, U24, U8}, + AlgorithmName, BlockCipher, Key, KeyInit, KeySizeUser, }; +use core::fmt; -/// Triple DES (3DES) block cipher. -#[derive(Copy, Clone)] -pub struct TdesEde3 { - d1: Des, - d2: Des, - d3: Des, -} +#[cfg(feature = "zeroize")] +use cipher::zeroize::ZeroizeOnDrop; /// Triple DES (3DES) block cipher. -#[derive(Copy, Clone)] -pub struct TdesEee3 { +#[derive(Clone)] +pub struct TdesEde3 { d1: Des, d2: Des, d3: Des, } -/// Triple DES (3DES) block cipher. -#[derive(Copy, Clone)] -pub struct TdesEde2 { - d1: Des, - d2: Des, -} - -/// Triple DES (3DES) block cipher. -#[derive(Copy, Clone)] -pub struct TdesEee2 { - d1: Des, - d2: Des, -} +impl BlockCipher for TdesEde3 {} -impl NewBlockCipher for TdesEde3 { +impl KeySizeUser for TdesEde3 { type KeySize = U24; +} - fn new(key: &GenericArray) -> Self { - let d1 = Des { - keys: gen_keys(BE::read_u64(&key[0..8])), - }; - let d2 = Des { - keys: gen_keys(BE::read_u64(&key[8..16])), - }; - let d3 = Des { - keys: gen_keys(BE::read_u64(&key[16..24])), - }; +impl KeyInit for TdesEde3 { + #[inline] + fn new(key: &Key) -> Self { + let k1 = u64::from_be_bytes(key[0..8].try_into().unwrap()); + let k2 = u64::from_be_bytes(key[8..16].try_into().unwrap()); + let k3 = u64::from_be_bytes(key[16..24].try_into().unwrap()); + let d1 = Des { keys: gen_keys(k1) }; + let d2 = Des { keys: gen_keys(k2) }; + let d3 = Des { keys: gen_keys(k3) }; Self { d1, d2, d3 } } } -impl BlockCipher for TdesEde3 { - type BlockSize = U8; - type ParBlocks = U1; +impl fmt::Debug for TdesEde3 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("TdesEee3 { ... }") + } } -impl BlockEncrypt for TdesEde3 { - fn encrypt_block(&self, block: &mut GenericArray) { - let mut data = BE::read_u64(block); - - data = self.d1.encrypt(data); - data = self.d2.decrypt(data); - data = self.d3.encrypt(data); - - BE::write_u64(block, data); +impl AlgorithmName for TdesEde3 { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("TdesEde3") } } -impl BlockDecrypt for TdesEde3 { - fn decrypt_block(&self, block: &mut GenericArray) { - let mut data = BE::read_u64(block); - - data = self.d3.decrypt(data); - data = self.d2.encrypt(data); - data = self.d1.decrypt(data); +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl ZeroizeOnDrop for TdesEde3 {} - BE::write_u64(block, data); +cipher::impl_simple_block_encdec!( + TdesEde3, U8, cipher, block, + encrypt: { + let mut data = u64::from_be_bytes(block.clone_in().into()); + data = cipher.d1.encrypt(data); + data = cipher.d2.decrypt(data); + data = cipher.d3.encrypt(data); + block.get_out().copy_from_slice(&data.to_be_bytes()); } + decrypt: { + let mut data = u64::from_be_bytes(block.clone_in().into()); + data = cipher.d3.decrypt(data); + data = cipher.d2.encrypt(data); + data = cipher.d1.decrypt(data); + block.get_out().copy_from_slice(&data.to_be_bytes()); + } +); + +/// Triple DES (3DES) block cipher. +#[derive(Clone)] +pub struct TdesEee3 { + d1: Des, + d2: Des, + d3: Des, } -impl NewBlockCipher for TdesEee3 { +impl BlockCipher for TdesEee3 {} + +impl KeySizeUser for TdesEee3 { type KeySize = U24; +} - fn new(key: &GenericArray) -> Self { - let d1 = Des { - keys: gen_keys(BE::read_u64(&key[0..8])), - }; - let d2 = Des { - keys: gen_keys(BE::read_u64(&key[8..16])), - }; - let d3 = Des { - keys: gen_keys(BE::read_u64(&key[16..24])), - }; +impl KeyInit for TdesEee3 { + #[inline] + fn new(key: &Key) -> Self { + let k1 = u64::from_be_bytes(key[0..8].try_into().unwrap()); + let k2 = u64::from_be_bytes(key[8..16].try_into().unwrap()); + let k3 = u64::from_be_bytes(key[16..24].try_into().unwrap()); + let d1 = Des { keys: gen_keys(k1) }; + let d2 = Des { keys: gen_keys(k2) }; + let d3 = Des { keys: gen_keys(k3) }; Self { d1, d2, d3 } } } -impl BlockCipher for TdesEee3 { - type BlockSize = U8; - type ParBlocks = U1; +impl fmt::Debug for TdesEee3 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("TdesEee3 { ... }") + } } -impl BlockEncrypt for TdesEee3 { - fn encrypt_block(&self, block: &mut GenericArray) { - let mut data = BE::read_u64(block); - - data = self.d1.encrypt(data); - data = self.d2.encrypt(data); - data = self.d3.encrypt(data); - - BE::write_u64(block, data); +impl AlgorithmName for TdesEee3 { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("TdesEee3") } } -impl BlockDecrypt for TdesEee3 { - fn decrypt_block(&self, block: &mut GenericArray) { - let mut data = BE::read_u64(block); +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl ZeroizeOnDrop for TdesEee3 {} - data = self.d3.decrypt(data); - data = self.d2.decrypt(data); - data = self.d1.decrypt(data); - - BE::write_u64(block, data); +cipher::impl_simple_block_encdec!( + TdesEee3, U8, cipher, block, + encrypt: { + let mut data = u64::from_be_bytes(block.clone_in().into()); + data = cipher.d1.encrypt(data); + data = cipher.d2.encrypt(data); + data = cipher.d3.encrypt(data); + block.get_out().copy_from_slice(&data.to_be_bytes()); + } + decrypt: { + let mut data = u64::from_be_bytes(block.clone_in().into()); + data = cipher.d3.decrypt(data); + data = cipher.d2.decrypt(data); + data = cipher.d1.decrypt(data); + block.get_out().copy_from_slice(&data.to_be_bytes()); } +); + +/// Triple DES (3DES) block cipher. +#[derive(Clone)] +pub struct TdesEde2 { + d1: Des, + d2: Des, } -impl NewBlockCipher for TdesEde2 { +impl BlockCipher for TdesEde2 {} + +impl KeySizeUser for TdesEde2 { type KeySize = U16; +} - fn new(key: &GenericArray) -> Self { - let d1 = Des { - keys: gen_keys(BE::read_u64(&key[0..8])), - }; - let d2 = Des { - keys: gen_keys(BE::read_u64(&key[8..16])), - }; +impl KeyInit for TdesEde2 { + #[inline] + fn new(key: &Key) -> Self { + let k1 = u64::from_be_bytes(key[0..8].try_into().unwrap()); + let k2 = u64::from_be_bytes(key[8..16].try_into().unwrap()); + let d1 = Des { keys: gen_keys(k1) }; + let d2 = Des { keys: gen_keys(k2) }; Self { d1, d2 } } } -impl BlockCipher for TdesEde2 { - type BlockSize = U8; - type ParBlocks = U1; +impl fmt::Debug for TdesEde2 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("TdesEde2 { ... }") + } } -impl BlockEncrypt for TdesEde2 { - fn encrypt_block(&self, block: &mut GenericArray) { - let mut data = BE::read_u64(block); - - data = self.d1.encrypt(data); - data = self.d2.decrypt(data); - data = self.d1.encrypt(data); - - BE::write_u64(block, data); +impl AlgorithmName for TdesEde2 { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("TdesEde2") } } -impl BlockDecrypt for TdesEde2 { - fn decrypt_block(&self, block: &mut GenericArray) { - let mut data = BE::read_u64(block); +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl ZeroizeOnDrop for TdesEde2 {} - data = self.d1.decrypt(data); - data = self.d2.encrypt(data); - data = self.d1.decrypt(data); - - BE::write_u64(block, data); +cipher::impl_simple_block_encdec!( + TdesEde2, U8, cipher, block, + encrypt: { + let mut data = u64::from_be_bytes(block.clone_in().into()); + data = cipher.d1.encrypt(data); + data = cipher.d2.decrypt(data); + data = cipher.d1.encrypt(data); + block.get_out().copy_from_slice(&data.to_be_bytes()); + } + decrypt: { + let mut data = u64::from_be_bytes(block.clone_in().into()); + data = cipher.d1.decrypt(data); + data = cipher.d2.encrypt(data); + data = cipher.d1.decrypt(data); + block.get_out().copy_from_slice(&data.to_be_bytes()); } +); + +/// Triple DES (3DES) block cipher. +#[derive(Clone)] +pub struct TdesEee2 { + d1: Des, + d2: Des, } -impl NewBlockCipher for TdesEee2 { +impl BlockCipher for TdesEee2 {} + +impl KeySizeUser for TdesEee2 { type KeySize = U16; +} - fn new(key: &GenericArray) -> Self { - let d1 = Des { - keys: gen_keys(BE::read_u64(&key[0..8])), - }; - let d2 = Des { - keys: gen_keys(BE::read_u64(&key[8..16])), - }; +impl KeyInit for TdesEee2 { + #[inline] + fn new(key: &Key) -> Self { + let k1 = u64::from_be_bytes(key[0..8].try_into().unwrap()); + let k2 = u64::from_be_bytes(key[8..16].try_into().unwrap()); + let d1 = Des { keys: gen_keys(k1) }; + let d2 = Des { keys: gen_keys(k2) }; Self { d1, d2 } } } -impl BlockCipher for TdesEee2 { - type BlockSize = U8; - type ParBlocks = U1; +impl fmt::Debug for TdesEee2 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("TdesEee2 { ... }") + } } -impl BlockEncrypt for TdesEee2 { - fn encrypt_block(&self, block: &mut GenericArray) { - let mut data = BE::read_u64(block); - - data = self.d1.encrypt(data); - data = self.d2.encrypt(data); - data = self.d1.encrypt(data); - - BE::write_u64(block, data); +impl AlgorithmName for TdesEee2 { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("TdesEee2") } } -impl BlockDecrypt for TdesEee2 { - fn decrypt_block(&self, block: &mut GenericArray) { - let mut data = BE::read_u64(block); +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl ZeroizeOnDrop for TdesEee2 {} - data = self.d1.decrypt(data); - data = self.d2.decrypt(data); - data = self.d1.decrypt(data); - - BE::write_u64(block, data); +cipher::impl_simple_block_encdec!( + TdesEee2, U8, cipher, block, + encrypt: { + let mut data = u64::from_be_bytes(block.clone_in().into()); + data = cipher.d1.encrypt(data); + data = cipher.d2.encrypt(data); + data = cipher.d1.encrypt(data); + block.get_out().copy_from_slice(&data.to_be_bytes()); } -} - -opaque_debug::implement!(TdesEde3); -opaque_debug::implement!(TdesEee3); -opaque_debug::implement!(TdesEde2); -opaque_debug::implement!(TdesEee2); + decrypt: { + let mut data = u64::from_be_bytes(block.clone_in().into()); + data = cipher.d1.decrypt(data); + data = cipher.d2.decrypt(data); + data = cipher.d1.decrypt(data); + block.get_out().copy_from_slice(&data.to_be_bytes()); + } +); diff --git a/des/tests/lib.rs b/des/tests/mod.rs similarity index 100% rename from des/tests/lib.rs rename to des/tests/mod.rs diff --git a/gost-modes/CHANGELOG.md b/gost-modes/CHANGELOG.md deleted file mode 100644 index e7f28d75..00000000 --- a/gost-modes/CHANGELOG.md +++ /dev/null @@ -1,38 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## 0.5.0 (2021-04-29) -### Changed -- Bump `cipher` dependency to v0.3 release ([#235]) - -[#235]: https://github.com/RustCrypto/block-ciphers/pull/235 - -## 0.4.0 (2020-10-16) -### Changed -- Replace `block-cipher`/`stream-cipher` with `cipher` crate ([#167]) - -[#167]: https://github.com/RustCrypto/block-ciphers/pull/167 - -## 0.3.0 (2020-08-12) -### Changed -- Bump `stream-cipher` dependency to v0.7 ([#158]) - -[#158]: https://github.com/RustCrypto/block-ciphers/pull/158 - -## 0.2.0 (2020-08-12) -### Fixed -- CFB mode ([#144]) - -### Changed -- Split `GostCtr` into `GostCtr128` and `GostCtr64` types ([#144]) - -[#144]: https://github.com/RustCrypto/block-ciphers/pull/144 - -## 0.1.0 (2020-07-03) [YANKED] -- Initial release ([#134]) - -[#134]: https://github.com/RustCrypto/block-ciphers/pull/134 diff --git a/gost-modes/Cargo.toml b/gost-modes/Cargo.toml deleted file mode 100644 index 0894c4e3..00000000 --- a/gost-modes/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -name = "gost-modes" -version = "0.5.0" -description = "Block cipher modes of operation" -authors = ["RustCrypto Developers"] -license = "MIT OR Apache-2.0" -readme = "README.md" -edition = "2018" -documentation = "https://docs.rs/block-modes" -repository = "https://github.com/RustCrypto/block-ciphers" -keywords = ["crypto", "block-cipher", "ciphers"] - -[dependencies] -block-modes = { version = "0.8", path = "../block-modes", default-features = false } -cipher = { version = "0.3", default-features = false } -generic-array = "0.14" - -[dev-dependencies] -kuznyechik = { version = "0.7", path = "../kuznyechik" } -magma = { version = "0.7", path = "../magma" } -cipher = { version = "0.3", features = ["dev"] } -hex-literal = "0.2" - -[features] -default = ["std"] -alloc = ["block-modes/alloc"] -std = ["alloc", "block-modes/std", "cipher/std"] diff --git a/gost-modes/LICENSE-APACHE b/gost-modes/LICENSE-APACHE deleted file mode 100644 index 78173fa2..00000000 --- a/gost-modes/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/gost-modes/LICENSE-MIT b/gost-modes/LICENSE-MIT deleted file mode 100644 index 2726e14a..00000000 --- a/gost-modes/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2020 The RustCrypto Project Developers - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/gost-modes/README.md b/gost-modes/README.md deleted file mode 100644 index 017b06e0..00000000 --- a/gost-modes/README.md +++ /dev/null @@ -1,57 +0,0 @@ -# RustCrypto: GOST Modes - -[![crate][crate-image]][crate-link] -[![Docs][docs-image]][docs-link] -![Apache2/MIT licensed][license-image] -[![Project Chat][chat-image]][chat-link] -![Rust Version][rustc-image] -[![Build Status][build-image]][build-link] - -Generic implementation of [block cipher modes of operation][1], defined in -GOST R 34.13-2015. - -[Documentation][docs-link] - -## Minimum Supported Rust Version - -Rust **1.41** or higher. - -Minimum supported Rust version can be changed in the future, but it will be -done with a minor version bump. - -## SemVer Policy - -- All on-by-default features of this library are covered by SemVer -- MSRV is considered exempt from SemVer as noted above - -## License - -Licensed under either of: - - * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) - * [MIT license](http://opensource.org/licenses/MIT) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in the work by you, as defined in the Apache-2.0 license, shall be -dual licensed as above, without any additional terms or conditions. - -[//]: # (badges) - -[crate-image]: https://img.shields.io/crates/v/gost-modes.svg -[crate-link]: https://crates.io/crates/gost-modes -[docs-image]: https://docs.rs/gost-modes/badge.svg -[docs-link]: https://docs.rs/gost-modes/ -[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg -[rustc-image]: https://img.shields.io/badge/rustc-1.41+-blue.svg -[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg -[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260039-block-ciphers -[build-image]: https://github.com/RustCrypto/block-ciphers/workflows/gost-modes/badge.svg?branch=master&event=push -[build-link]: https://github.com/RustCrypto/block-ciphers/actions?query=workflow%3Agost-modes - -[//]: # (general links) - -[1]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation diff --git a/gost-modes/src/cbc.rs b/gost-modes/src/cbc.rs deleted file mode 100644 index c11678b1..00000000 --- a/gost-modes/src/cbc.rs +++ /dev/null @@ -1,81 +0,0 @@ -use crate::{utils::xor, GostPadding}; -use block_modes::{block_padding::Padding, BlockMode}; -use cipher::{Block, BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher}; -use core::{marker::PhantomData, ops::Mul}; -use generic_array::typenum::{ - type_operators::{IsGreater, IsLessOrEqual}, - Prod, Unsigned, U0, U1, U255, -}; -use generic_array::{ArrayLength, GenericArray}; - -/// Cipher Block Chaining (CBC) mode of operation as defined in GOST R 34.13-2015 -/// -/// Type parameters: -/// - `C`: block cipher. -/// - `P`: padding algorithm. Default: `GostPadding`. -/// - `Z`: nonce length in block sizes. Default: 1. -/// -/// With default parameters this mode is fully equivalent to the `Cbc` mode defined -/// in the `block-modes` crate. -#[derive(Clone)] -pub struct GostCbc -where - C: BlockCipher + NewBlockCipher, - C::BlockSize: IsLessOrEqual, - Z: ArrayLength> + Unsigned + Mul + IsGreater + IsLessOrEqual, - Prod: ArrayLength, - P: Padding, -{ - cipher: C, - state: GenericArray, Z>, - pos: u8, - _p: PhantomData

, -} - -impl BlockMode for GostCbc -where - C: BlockCipher + BlockEncrypt + BlockDecrypt + NewBlockCipher, - C::BlockSize: IsLessOrEqual, - Z: ArrayLength> + Unsigned + Mul + IsGreater + IsLessOrEqual, - Prod: ArrayLength, - P: Padding, -{ - type IvSize = Prod; - - fn new(cipher: C, iv: &GenericArray) -> Self { - let bs = C::BlockSize::USIZE; - let mut state = GenericArray::, Z>::default(); - for (block, chunk) in state.iter_mut().zip(iv.chunks_exact(bs)) { - *block = GenericArray::clone_from_slice(chunk); - } - Self { - cipher, - state, - pos: 0, - _p: Default::default(), - } - } - - fn encrypt_blocks(&mut self, blocks: &mut [Block]) { - for block in blocks { - let sb = &mut self.state[self.pos as usize]; - xor(block, sb); - self.cipher.encrypt_block(block); - *sb = block.clone(); - self.pos += 1; - self.pos %= Z::U8; - } - } - - fn decrypt_blocks(&mut self, blocks: &mut [Block]) { - for block in blocks { - let pos = self.pos as usize; - let b = self.state[pos].clone(); - self.state[pos] = block.clone(); - self.cipher.decrypt_block(block); - xor(block, &b); - self.pos += 1; - self.pos %= Z::U8; - } - } -} diff --git a/gost-modes/src/cfb.rs b/gost-modes/src/cfb.rs deleted file mode 100644 index bfadf9d7..00000000 --- a/gost-modes/src/cfb.rs +++ /dev/null @@ -1,155 +0,0 @@ -use crate::utils::{xor_set1, xor_set2}; -use cipher::{ - AsyncStreamCipher, Block, BlockCipher, BlockEncrypt, FromBlockCipher, NewBlockCipher, -}; -use core::ops::Sub; -use generic_array::{ - typenum::{ - type_operators::{IsGreater, IsGreaterOrEqual, IsLessOrEqual}, - Diff, Unsigned, U0, U255, - }, - ArrayLength, GenericArray, -}; - -type BlockSize = ::BlockSize; - -type Tail = GenericArray::BlockSize>>; - -/// Cipher feedback (CFB) mode of operation as defined in GOST R 34.13-2015 -/// -/// Type parameters: -/// - `C`: block cipher. -/// - `M`: nonce length in bytes. Default: block size. -/// - `S`: number of block bytes used for message encryption. Default: block size. -/// -/// With default parameters this mode is fully equivalent to the `Cfb` mode defined -/// in the `cfb-mode` crate. -#[derive(Clone)] -pub struct GostCfb, S = BlockSize> -where - C: BlockCipher + BlockEncrypt + NewBlockCipher, - C::BlockSize: IsLessOrEqual, - M: Unsigned + ArrayLength + IsGreaterOrEqual + Sub, - S: Unsigned + ArrayLength + IsGreater + IsLessOrEqual, - Diff: ArrayLength, -{ - cipher: C, - block: GenericArray, - tail: Tail, - pos: u8, -} - -impl GostCfb -where - C: BlockCipher + BlockEncrypt + NewBlockCipher, - C::BlockSize: IsLessOrEqual, - M: Unsigned + ArrayLength + IsGreaterOrEqual + Sub, - S: Unsigned + ArrayLength + IsGreater + IsLessOrEqual, - Diff: ArrayLength, -{ - fn gen_block(&mut self) { - let s = S::USIZE; - let ts = self.tail.len(); - let mut block: Block = Default::default(); - if ts <= s { - let d = s - ts; - block[..ts].copy_from_slice(&self.tail); - block[ts..].copy_from_slice(&self.block[..d]); - self.tail = GenericArray::clone_from_slice(&self.block[d..]); - } else { - let d = ts - s; - let mut tail: Tail = Default::default(); - tail[..d].copy_from_slice(&self.tail[s..]); - tail[d..].copy_from_slice(&self.block); - block = GenericArray::clone_from_slice(&self.tail[..s]); - self.tail = tail; - } - self.cipher.encrypt_block(&mut block); - self.block.copy_from_slice(&block[..s]); - } -} - -impl FromBlockCipher for GostCfb -where - C: BlockCipher + BlockEncrypt + NewBlockCipher, - C::BlockSize: IsLessOrEqual, - M: Unsigned + ArrayLength + IsGreaterOrEqual + Sub, - S: Unsigned + ArrayLength + IsGreater + IsLessOrEqual, - Diff: ArrayLength, -{ - type BlockCipher = C; - type NonceSize = M; - - fn from_block_cipher(cipher: C, nonce: &GenericArray) -> Self { - let bs = C::BlockSize::USIZE; - let mut full_block = Block::::clone_from_slice(&nonce[..bs]); - cipher.encrypt_block(&mut full_block); - Self { - cipher, - block: GenericArray::clone_from_slice(&full_block[..S::USIZE]), - tail: GenericArray::clone_from_slice(&nonce[bs..]), - pos: 0, - } - } -} - -impl AsyncStreamCipher for GostCfb -where - C: BlockCipher + BlockEncrypt + NewBlockCipher, - C::BlockSize: IsLessOrEqual, - M: Unsigned + ArrayLength + IsGreaterOrEqual + Sub, - S: Unsigned + ArrayLength + IsGreater + IsLessOrEqual, - Diff: ArrayLength, -{ - fn encrypt(&mut self, mut data: &mut [u8]) { - let s = S::USIZE; - let pos = self.pos as usize; - - if data.len() < s - pos { - let n = data.len(); - xor_set1(data, &mut self.block[pos..pos + n]); - self.pos += n as u8; - return; - } else if pos != 0 { - let (l, r) = { data }.split_at_mut(s - pos); - data = r; - xor_set1(l, &mut self.block[pos..s]); - self.gen_block() - } - - let mut iter = data.chunks_exact_mut(s); - for chunk in &mut iter { - xor_set1(chunk, &mut self.block[..s]); - self.gen_block(); - } - let rem = iter.into_remainder(); - xor_set1(rem, &mut self.block[..rem.len()]); - self.pos = rem.len() as u8; - } - - fn decrypt(&mut self, mut data: &mut [u8]) { - let s = S::USIZE; - let pos = self.pos as usize; - - if data.len() < s - pos { - let n = data.len(); - xor_set2(data, &mut self.block[pos..pos + n]); - self.pos += n as u8; - return; - } else if pos != 0 { - let (l, r) = { data }.split_at_mut(s - pos); - data = r; - xor_set2(l, &mut self.block[pos..]); - self.gen_block() - } - - let mut iter = data.chunks_exact_mut(s); - for chunk in &mut iter { - xor_set2(chunk, &mut self.block); - self.gen_block(); - } - let rem = iter.into_remainder(); - xor_set2(rem, &mut self.block[..rem.len()]); - self.pos = rem.len() as u8; - } -} diff --git a/gost-modes/src/ctr128.rs b/gost-modes/src/ctr128.rs deleted file mode 100644 index cb48de53..00000000 --- a/gost-modes/src/ctr128.rs +++ /dev/null @@ -1,131 +0,0 @@ -use crate::utils::xor; -use cipher::{ - errors::{LoopError, OverflowError}, - Block, BlockCipher, BlockEncrypt, FromBlockCipher, NewBlockCipher, SeekNum, StreamCipher, - StreamCipherSeek, -}; -use generic_array::typenum::{ - type_operators::{IsGreater, IsLessOrEqual}, - Unsigned, U0, U16, U8, -}; -use generic_array::{ArrayLength, GenericArray}; - -/// Counter (CTR) mode of operation for 128-bit block ciphers as defined in -/// GOST R 34.13-2015 -/// -/// Type parameters: -/// - `C`: block cipher. -/// - `S`: number of block bytes used for message encryption. Default: block size. -#[derive(Clone)] -pub struct GostCtr128::BlockSize> -where - C: BlockCipher + BlockEncrypt + NewBlockCipher, - C::ParBlocks: ArrayLength>, - S: ArrayLength + Unsigned + IsGreater + IsLessOrEqual, -{ - cipher: C, - nonce: u64, - ctr: u64, - block: GenericArray, - pos: u8, -} - -impl GostCtr128 -where - C: BlockCipher + BlockEncrypt + NewBlockCipher, - C::ParBlocks: ArrayLength>, - S: ArrayLength + Unsigned + IsGreater + IsLessOrEqual, -{ - fn gen_block(&self, ctr: u64) -> GenericArray { - let mut block: Block = Default::default(); - block[..8].copy_from_slice(&self.nonce.to_be_bytes()); - block[8..].copy_from_slice(&ctr.to_be_bytes()); - self.cipher.encrypt_block(&mut block); - let mut res: GenericArray = Default::default(); - res.copy_from_slice(&block[..S::USIZE]); - res - } -} - -impl FromBlockCipher for GostCtr128 -where - C: BlockCipher + BlockEncrypt + NewBlockCipher, - C::ParBlocks: ArrayLength>, - S: ArrayLength + Unsigned + IsGreater + IsLessOrEqual, -{ - type BlockCipher = C; - type NonceSize = U8; - - fn from_block_cipher(cipher: C, nonce: &GenericArray) -> Self { - Self { - cipher, - nonce: u64::from_be_bytes(*nonce.as_ref()), - ctr: 0, - block: Default::default(), - pos: 0, - } - } -} - -impl StreamCipher for GostCtr128 -where - C: BlockCipher + BlockEncrypt + NewBlockCipher, - C::ParBlocks: ArrayLength>, - S: ArrayLength + Unsigned + IsGreater + IsLessOrEqual, -{ - fn try_apply_keystream(&mut self, mut data: &mut [u8]) -> Result<(), LoopError> { - let s = self.block.len(); - let pos = self.pos as usize; - let mut ctr = self.ctr; - - if pos != 0 { - if data.len() < s - pos { - let n = data.len(); - xor(data, &self.block[pos..pos + n]); - self.pos += n as u8; - return Ok(()); - } else if pos != 0 { - let (l, r) = { data }.split_at_mut(s - pos); - data = r; - xor(l, &self.block[pos..]); - ctr += 1; - } - } - - let mut iter = data.chunks_exact_mut(s); - for chunk in &mut iter { - xor(chunk, &self.gen_block(ctr)); - ctr += 1; - } - let rem = iter.into_remainder(); - self.pos = rem.len() as u8; - self.ctr = ctr; - if !rem.is_empty() { - self.block = self.gen_block(ctr); - xor(rem, &self.block[..rem.len()]); - } - - Ok(()) - } -} - -impl StreamCipherSeek for GostCtr128 -where - C: BlockCipher + BlockEncrypt + NewBlockCipher, - C::ParBlocks: ArrayLength>, - S: ArrayLength + Unsigned + IsGreater + IsLessOrEqual, -{ - fn try_current_pos(&self) -> Result { - T::from_block_byte(self.ctr, self.pos, S::U8) - } - - fn try_seek(&mut self, pos: T) -> Result<(), LoopError> { - let res = pos.to_block_byte(S::U8)?; - self.ctr = res.0; - self.pos = res.1; - if self.pos != 0 { - self.block = self.gen_block(res.0); - } - Ok(()) - } -} diff --git a/gost-modes/src/ctr64.rs b/gost-modes/src/ctr64.rs deleted file mode 100644 index 302d4fbf..00000000 --- a/gost-modes/src/ctr64.rs +++ /dev/null @@ -1,131 +0,0 @@ -use crate::utils::xor; -use cipher::{ - errors::{LoopError, OverflowError}, - Block, BlockCipher, BlockEncrypt, FromBlockCipher, NewBlockCipher, SeekNum, StreamCipher, - StreamCipherSeek, -}; -use generic_array::typenum::{ - type_operators::{IsGreater, IsLessOrEqual}, - Unsigned, U0, U4, U8, -}; -use generic_array::{ArrayLength, GenericArray}; - -/// Counter (CTR) mode of operation for 64-bit block ciphers as defined in -/// GOST R 34.13-2015 -/// -/// Type parameters: -/// - `C`: block cipher. -/// - `S`: number of block bytes used for message encryption. Default: block size. -#[derive(Clone)] -pub struct GostCtr64::BlockSize> -where - C: BlockCipher + BlockEncrypt + NewBlockCipher, - C::ParBlocks: ArrayLength>, - S: ArrayLength + Unsigned + IsGreater + IsLessOrEqual, -{ - cipher: C, - nonce: u32, - ctr: u32, - block: GenericArray, - pos: u8, -} - -impl GostCtr64 -where - C: BlockCipher + BlockEncrypt + NewBlockCipher, - C::ParBlocks: ArrayLength>, - S: ArrayLength + Unsigned + IsGreater + IsLessOrEqual, -{ - fn gen_block(&self, ctr: u32) -> GenericArray { - let mut block: Block = Default::default(); - block[..4].copy_from_slice(&self.nonce.to_be_bytes()); - block[4..].copy_from_slice(&ctr.to_be_bytes()); - self.cipher.encrypt_block(&mut block); - let mut res: GenericArray = Default::default(); - res.copy_from_slice(&block[..S::USIZE]); - res - } -} - -impl FromBlockCipher for GostCtr64 -where - C: BlockCipher + BlockEncrypt + NewBlockCipher, - C::ParBlocks: ArrayLength>, - S: ArrayLength + Unsigned + IsGreater + IsLessOrEqual, -{ - type BlockCipher = C; - type NonceSize = U4; - - fn from_block_cipher(cipher: C, nonce: &GenericArray) -> Self { - Self { - cipher, - nonce: u32::from_be_bytes(*nonce.as_ref()), - ctr: 0, - block: Default::default(), - pos: 0, - } - } -} - -impl StreamCipher for GostCtr64 -where - C: BlockCipher + BlockEncrypt + NewBlockCipher, - C::ParBlocks: ArrayLength>, - S: ArrayLength + Unsigned + IsGreater + IsLessOrEqual, -{ - fn try_apply_keystream(&mut self, mut data: &mut [u8]) -> Result<(), LoopError> { - let s = self.block.len(); - let pos = self.pos as usize; - let mut ctr = self.ctr; - - if pos != 0 { - if data.len() < s - pos { - let n = data.len(); - xor(data, &self.block[pos..pos + n]); - self.pos += n as u8; - return Ok(()); - } else if pos != 0 { - let (l, r) = { data }.split_at_mut(s - pos); - data = r; - xor(l, &self.block[pos..]); - ctr += 1; - } - } - - let mut iter = data.chunks_exact_mut(s); - for chunk in &mut iter { - xor(chunk, &self.gen_block(ctr)); - ctr += 1; - } - let rem = iter.into_remainder(); - self.pos = rem.len() as u8; - self.ctr = ctr; - if !rem.is_empty() { - self.block = self.gen_block(ctr); - xor(rem, &self.block[..rem.len()]); - } - - Ok(()) - } -} - -impl StreamCipherSeek for GostCtr64 -where - C: BlockCipher + BlockEncrypt + NewBlockCipher, - C::ParBlocks: ArrayLength>, - S: ArrayLength + Unsigned + IsGreater + IsLessOrEqual, -{ - fn try_current_pos(&self) -> Result { - T::from_block_byte(self.ctr, self.pos, S::U8) - } - - fn try_seek(&mut self, pos: T) -> Result<(), LoopError> { - let res = pos.to_block_byte(S::U8)?; - self.ctr = res.0; - self.pos = res.1; - if self.pos != 0 { - self.block = self.gen_block(res.0); - } - Ok(()) - } -} diff --git a/gost-modes/src/lib.rs b/gost-modes/src/lib.rs deleted file mode 100644 index 2f9b75b0..00000000 --- a/gost-modes/src/lib.rs +++ /dev/null @@ -1,79 +0,0 @@ -//! This crate contains generic implementation of [block cipher modes of -//! operation][1] defined in [GOST R 34.13-2015]. -//! -//! CTR, CFB and OFB modes are implemented in terms of traits from the [`cipher`] crate. -//! -//! MAC function defined in the GOST is implemented in the [`cmac`] crate. -//! -//! # Examples -//! ``` -//! use gost_modes::{GostCbc, GostPadding, BlockMode, consts::U2}; -//! use kuznyechik::Kuznyechik; -//! use hex_literal::hex; -//! -//! let key = hex!(" -//! 8899aabbccddeeff0011223344556677 -//! fedcba98765432100123456789abcdef -//! "); -//! let iv = hex!(" -//! 1234567890abcef0a1b2c3d4e5f00112 -//! 23344556677889901213141516171819 -//! "); -//! let pt = b"my secret message"; -//! -//! type Cipher = GostCbc; -//! -//! let cipher = Cipher::new_from_slices(&key, &iv).unwrap(); -//! let ct = cipher.encrypt_vec(pt); -//! -//! let cipher = Cipher::new_from_slices(&key, &iv).unwrap(); -//! let buf = cipher.decrypt_vec(&ct).unwrap(); -//! -//! assert_eq!(buf, &pt[..]); -//! -//! // OFB mode example -//! use gost_modes::{GostOfb, StreamCipher, NewCipher}; -//! -//! let mut cipher = GostOfb::::new_from_slices(&key, &iv).unwrap(); -//! let mut buf = pt.to_vec(); -//! cipher.apply_keystream(&mut buf); -//! assert_eq!(buf, hex!("fddb196e81812e4174d1c9f741a3457a88")); -//! ``` -//! -//! [1]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation -//! [GOST R 34.13-2015]: https://tc26.ru/standard/gost/GOST_R_3413-2015.pdf -//! [`cipher`]: https://docs.rs/cipher/ -//! [`cmac`]: https://docs.rs/cmac/ -#![no_std] -#![doc( - html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg", - html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg" -)] -#![deny(unsafe_code)] -#![warn(missing_docs, rust_2018_idioms)] - -pub use block_modes; -pub use block_modes::block_padding; -pub use cipher::{self, consts}; -pub use generic_array; - -pub use block_modes::{BlockMode, Ecb}; -pub use cipher::{AsyncStreamCipher, NewCipher, StreamCipher, StreamCipherSeek}; - -mod cbc; -mod cfb; -mod ctr128; -mod ctr64; -mod ofb; -mod utils; - -/// Block padding procedure number 2 as defined in GOST R 34.13-2015 -/// -/// Fully equivalent to ISO 7816. -pub type GostPadding = block_padding::Iso7816; - -pub use cbc::GostCbc; -pub use cfb::GostCfb; -pub use ctr128::GostCtr128; -pub use ctr64::GostCtr64; -pub use ofb::GostOfb; diff --git a/gost-modes/src/ofb.rs b/gost-modes/src/ofb.rs deleted file mode 100644 index c3dfcc16..00000000 --- a/gost-modes/src/ofb.rs +++ /dev/null @@ -1,109 +0,0 @@ -use crate::utils::xor; -use cipher::{ - errors::LoopError, Block, BlockCipher, BlockEncrypt, FromBlockCipher, NewBlockCipher, - StreamCipher, -}; -use core::{marker::PhantomData, ops::Mul}; -use generic_array::typenum::{ - type_operators::{IsGreater, IsLessOrEqual}, - Prod, Unsigned, U0, U1, U255, -}; -use generic_array::{ArrayLength, GenericArray}; - -/// Output feedback (OFB) mode of operation as defined in GOST R 34.13-2015 -/// -/// Type parameters: -/// - `C`: block cipher. -/// - `Z`: nonce length in block sizes. Default: 1. -/// - `S`: number of block bytes used for message encryption. Default: block size. -/// -/// With default parameters this mode is fully equivalent to the `Ofb` mode defined -/// in the `block-modes` crate. -#[derive(Clone)] -pub struct GostOfb::BlockSize> -where - C: BlockCipher + BlockEncrypt + NewBlockCipher, - C::BlockSize: IsLessOrEqual, - S: Unsigned + IsGreater + IsLessOrEqual, - Z: ArrayLength> + Unsigned + Mul + IsGreater + IsLessOrEqual, - Prod: ArrayLength, -{ - cipher: C, - state: GenericArray, Z>, - block_pos: u8, - pos: u8, - _p: PhantomData, -} - -impl FromBlockCipher for GostOfb -where - C: BlockCipher + BlockEncrypt + NewBlockCipher, - C::BlockSize: IsLessOrEqual, - S: Unsigned + IsGreater + IsLessOrEqual, - Z: ArrayLength> + Unsigned + Mul + IsGreater + IsLessOrEqual, - Prod: ArrayLength, -{ - type BlockCipher = C; - type NonceSize = Prod; - - fn from_block_cipher(cipher: C, nonce: &GenericArray) -> Self { - let bs = C::BlockSize::to_usize(); - let mut state: GenericArray, Z> = Default::default(); - for (chunk, block) in nonce.chunks_exact(bs).zip(state.iter_mut()) { - let mut t = GenericArray::clone_from_slice(chunk); - cipher.encrypt_block(&mut t); - *block = t; - } - - Self { - cipher, - state, - block_pos: 0, - pos: 0, - _p: Default::default(), - } - } -} - -impl StreamCipher for GostOfb -where - C: BlockCipher + BlockEncrypt + NewBlockCipher, - C::BlockSize: IsLessOrEqual, - S: Unsigned + IsGreater + IsLessOrEqual, - Z: ArrayLength> + Unsigned + Mul + IsGreater + IsLessOrEqual, - Prod: ArrayLength, -{ - fn try_apply_keystream(&mut self, mut data: &mut [u8]) -> Result<(), LoopError> { - let s = S::USIZE; - let pos = self.pos as usize; - let block_pos = self.block_pos as usize; - - if data.len() < s - pos { - let n = data.len(); - xor(data, &self.state[block_pos][pos..pos + n]); - self.pos += n as u8; - return Ok(()); - } else if pos != 0 { - let (l, r) = { data }.split_at_mut(s - pos); - data = r; - xor(l, &self.state[block_pos][pos..s]); - self.pos = 0; - self.cipher - .encrypt_block(&mut self.state[self.block_pos as usize]); - self.block_pos = (self.block_pos + 1) % Z::U8; - } - - let mut iter = data.chunks_exact_mut(s); - for chunk in &mut iter { - xor(chunk, &self.state[self.block_pos as usize][..s]); - self.cipher - .encrypt_block(&mut self.state[self.block_pos as usize]); - self.block_pos = (self.block_pos + 1) % Z::U8; - } - let rem = iter.into_remainder(); - xor(rem, &self.state[self.block_pos as usize][..rem.len()]); - self.pos += rem.len() as u8; - - Ok(()) - } -} diff --git a/gost-modes/src/utils.rs b/gost-modes/src/utils.rs deleted file mode 100644 index f9cbe54d..00000000 --- a/gost-modes/src/utils.rs +++ /dev/null @@ -1,27 +0,0 @@ -#[inline(always)] -pub(crate) fn xor(buf1: &mut [u8], buf2: &[u8]) { - debug_assert_eq!(buf1.len(), buf2.len()); - for (a, b) in buf1.iter_mut().zip(buf2) { - *a ^= *b; - } -} - -#[inline(always)] -pub(crate) fn xor_set1(buf1: &mut [u8], buf2: &mut [u8]) { - debug_assert_eq!(buf1.len(), buf2.len()); - for (a, b) in buf1.iter_mut().zip(buf2) { - let t = *a ^ *b; - *a = t; - *b = t; - } -} - -#[inline(always)] -pub(crate) fn xor_set2(buf1: &mut [u8], buf2: &mut [u8]) { - debug_assert_eq!(buf1.len(), buf2.len()); - for (a, b) in buf1.iter_mut().zip(buf2) { - let t = *a; - *a ^= *b; - *b = t; - } -} diff --git a/gost-modes/tests/lib.rs b/gost-modes/tests/lib.rs deleted file mode 100644 index c73fe2e7..00000000 --- a/gost-modes/tests/lib.rs +++ /dev/null @@ -1,206 +0,0 @@ -//! Test vectors from GOST R 34.13-2015: -//! https://tc26.ru/standard/gost/GOST_R_3413-2015.pdf - -use gost_modes::{ - block_padding::ZeroPadding, - consts::{U14, U16, U2, U3, U32, U5}, - generic_array::GenericArray, - AsyncStreamCipher, BlockMode, Ecb, GostCbc, GostCfb, GostCtr128, GostCtr64, GostOfb, NewCipher, - StreamCipher, -}; -use hex_literal::hex; -use kuznyechik::Kuznyechik; -use magma::{cipher::NewBlockCipher, Magma}; - -fn test_stream_cipher(cipher: impl StreamCipher + Clone, pt: &[u8], ct: &[u8]) { - let mut buf = pt.to_vec(); - cipher.clone().apply_keystream(&mut buf); - assert_eq!(buf, &ct[..]); - cipher.clone().apply_keystream(&mut buf); - assert_eq!(buf, &pt[..]); - - for i in 1..32 { - let mut c = cipher.clone(); - let mut buf = pt.to_vec(); - for chunk in buf.chunks_mut(i) { - c.apply_keystream(chunk); - } - assert_eq!(buf, &ct[..]); - - let mut c = cipher.clone(); - for chunk in buf.chunks_mut(i) { - c.apply_keystream(chunk); - } - assert_eq!(buf, &pt[..]); - } -} - -fn test_async_stream_cipher(cipher: impl AsyncStreamCipher + Clone, pt: &[u8], ct: &[u8]) { - let mut buf = pt.to_vec(); - cipher.clone().encrypt(&mut buf); - assert_eq!(buf, &ct[..]); - cipher.clone().decrypt(&mut buf); - assert_eq!(buf, &pt[..]); - - for i in 1..32 { - let mut c = cipher.clone(); - let mut buf = pt.to_vec(); - for chunk in buf.chunks_mut(i) { - c.encrypt(chunk); - } - assert_eq!(buf, &ct[..]); - - let mut c = cipher.clone(); - for chunk in buf.chunks_mut(i) { - c.decrypt(chunk); - } - assert_eq!(buf, &pt[..]); - } -} - -#[test] -#[rustfmt::skip] -fn kuznyechik_modes() { - let key = GenericArray::from_slice(&hex!(" - 8899aabbccddeeff0011223344556677 - fedcba98765432100123456789abcdef - ")); - let iv = GenericArray::from_slice(&hex!(" - 1234567890abcef0a1b2c3d4e5f00112 - 23344556677889901213141516171819 - ")); - let ctr_iv = GenericArray::from_slice(&hex!(" - 1234567890abcef0 - ")); - let pt = hex!(" - 1122334455667700ffeeddccbbaa9988 - 00112233445566778899aabbcceeff0a - 112233445566778899aabbcceeff0a00 - 2233445566778899aabbcceeff0a0011 - "); - let ecb_ct = hex!(" - 7f679d90bebc24305a468d42b9d4edcd - b429912c6e0032f9285452d76718d08b - f0ca33549d247ceef3f5a5313bd4b157 - d0b09ccde830b9eb3a02c4c5aa8ada98 - "); - let ctr_ct = hex!(" - f195d8bec10ed1dbd57b5fa240bda1b8 - 85eee733f6a13e5df33ce4b33c45dee4 - a5eae88be6356ed3d5e877f13564a3a5 - cb91fab1f20cbab6d1c6d15820bdba73 - "); - let ofb_ct = hex!(" - 81800a59b1842b24ff1f795e897abd95 - ed5b47a7048cfab48fb521369d9326bf - 66a257ac3ca0b8b1c80fe7fc10288a13 - 203ebbc066138660a0292243f6903150 - "); - let cbc_ct = hex!(" - 689972d4a085fa4d90e52e3d6d7dcc27 - 2826e661b478eca6af1e8e448d5ea5ac - fe7babf1e91999e85640e8b0f49d90d0 - 167688065a895c631a2d9a1560b63970 - "); - let cfb_ct = hex!(" - 81800a59b1842b24ff1f795e897abd95 - ed5b47a7048cfab48fb521369d9326bf - 79f2a8eb5cc68d38842d264e97a238b5 - 4ffebecd4e922de6c75bd9dd44fbf4d1 - "); - - let c = GostOfb::::new(&key, &iv); - test_stream_cipher(c, &pt, &ofb_ct); - - let c = GostCfb::::new(&key, &iv); - test_async_stream_cipher(c, &pt, &cfb_ct); - - let c = GostCtr128::::new(&key, &ctr_iv); - test_stream_cipher(c, &pt, &ctr_ct); - - type EcbCipher = Ecb; - let cipher = Kuznyechik::new(&key); - let buf = EcbCipher::new(cipher, &Default::default()).encrypt_vec(&pt); - assert_eq!(buf, &ecb_ct[..]); - let buf = EcbCipher::new(cipher, &Default::default()) - .decrypt_vec(&ecb_ct) - .unwrap(); - assert_eq!(buf, &pt[..]); - - type CbcCipher = GostCbc; - let cipher = Kuznyechik::new(&key); - let buf = CbcCipher::new(cipher, &iv).encrypt_vec(&pt); - assert_eq!(buf, &cbc_ct[..]); - let buf = CbcCipher::new(cipher, &iv).decrypt_vec(&cbc_ct).unwrap(); - assert_eq!(buf, &pt[..]); -} - -#[test] -#[rustfmt::skip] -fn magma_modes() { - let key = GenericArray::from_slice(&hex!(" - ffeeddccbbaa99887766554433221100 - f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff - ")); - let iv = GenericArray::from_slice(&hex!(" - 1234567890abcdef234567890abcdef1 - ")); - let ctr_iv = GenericArray::from_slice(&hex!(" - 12345678 - ")); - let cbc_iv = GenericArray::from_slice(&hex!(" - 1234567890abcdef234567890abcdef134567890abcdef12 - ")); - let pt = hex!(" - 92def06b3c130a59db54c704f8189d20 - 4a98fb2e67a8024c8912409b17b57e41 - "); - let ecb_ct = hex!(" - 2b073f0494f372a0de70e715d3556e48 - 11d8d9e9eacfbc1e7c68260996c67efb - "); - let ctr_ct = hex!(" - 4e98110c97b7b93c3e250d93d6e85d69 - 136d868807b2dbef568eb680ab52a12d - "); - let ofb_ct = hex!(" - db37e0e266903c830d46644c1f9a089c - a0f83062430e327ec824efb8bd4fdb05 - "); - let cbc_ct = hex!(" - 96d1b05eea683919aff76129abb937b9 - 5058b4a1c4bc001920b78b1a7cd7e667 - "); - let cfb_ct = hex!(" - db37e0e266903c830d46644c1f9a089c - 24bdd2035315d38bbcc0321421075505 - "); - - let c = GostOfb::::new(&key, &iv); - test_stream_cipher(c, &pt, &ofb_ct); - - let c = GostCfb::::new(&key, &iv); - test_async_stream_cipher(c, &pt, &cfb_ct); - - let c = GostCtr64::::new(&key, &ctr_iv); - test_stream_cipher(c, &pt, &ctr_ct); - - type EcbCipher = Ecb; - let cipher = Magma::new(&key); - let buf = EcbCipher::new(cipher, &Default::default()).encrypt_vec(&pt); - assert_eq!(buf, &ecb_ct[..]); - let buf = EcbCipher::new(cipher, &Default::default()) - .decrypt_vec(&ecb_ct) - .unwrap(); - assert_eq!(buf, &pt[..]); - - type CbcCipher = GostCbc; - let cipher = Magma::new(&key); - let buf = CbcCipher::new(cipher, &cbc_iv).encrypt_vec(&pt); - assert_eq!(buf, &cbc_ct[..]); - let buf = CbcCipher::new(cipher, &cbc_iv).decrypt_vec(&cbc_ct).unwrap(); - assert_eq!(buf, &pt[..]); -} - -cipher::stream_cipher_seek_test!(kuznyechik_ctr_seek, GostCtr128::); -cipher::stream_cipher_seek_test!(magma_ctr_seek, GostCtr64::); diff --git a/idea/CHANGELOG.md b/idea/CHANGELOG.md index a500f53f..7e287b35 100644 --- a/idea/CHANGELOG.md +++ b/idea/CHANGELOG.md @@ -5,9 +5,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 0.5.0 (2022-02-10) +### Changed +- Bump `cipher` dependency to v0.4 ([#284]) + +[#284]: https://github.com/RustCrypto/block-ciphers/pull/284 + ## 0.4.0 (2021-04-29) ### Changed -- Bump `cipher` dependency to v0.3 release ([#235]) +- Bump `cipher` dependency to v0.3 ([#235]) [#235]: https://github.com/RustCrypto/block-ciphers/pull/235 diff --git a/idea/Cargo.toml b/idea/Cargo.toml index 1abbd0bc..f9391f44 100644 --- a/idea/Cargo.toml +++ b/idea/Cargo.toml @@ -1,19 +1,26 @@ [package] name = "idea" -version = "0.4.0" +version = "0.5.0" # Also update html_root_url in lib.rs when bumping this description = "IDEA block cipher" authors = ["RustCrypto Developers"] -license = "Apache-2.0 AND MIT" +license = "MIT OR Apache-2.0" +edition = "2021" +rust-version = "1.56" readme = "README.md" -edition = "2018" documentation = "https://docs.rs/idea" repository = "https://github.com/RustCrypto/block-ciphers" keywords = ["crypto", "idea", "block-cipher"] categories = ["cryptography", "no-std"] [dependencies] -cipher = "0.3" -opaque-debug = "0.3" +cipher = "0.4" [dev-dependencies] -cipher = { version = "0.3", features = ["dev"] } +cipher = { version = "0.4", features = ["dev"] } + +[features] +zeroize = ["cipher/zeroize"] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] diff --git a/idea/README.md b/idea/README.md index 65aa7c48..c6e0385c 100644 --- a/idea/README.md +++ b/idea/README.md @@ -26,7 +26,7 @@ USE AT YOUR OWN RISK! ## Minimum Supported Rust Version -Rust **1.41** or higher. +Rust **1.56** or higher. Minimum supported Rust version can be changed in the future, but it will be done with a minor version bump. @@ -58,7 +58,7 @@ dual licensed as above, without any additional terms or conditions. [docs-image]: https://docs.rs/idea/badge.svg [docs-link]: https://docs.rs/idea/ [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg -[rustc-image]: https://img.shields.io/badge/rustc-1.41+-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.56+-blue.svg [hazmat-image]: https://img.shields.io/badge/crypto-hazmat%E2%9A%A0-red.svg [hazmat-link]: https://github.com/RustCrypto/meta/blob/master/HAZMAT.md [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg diff --git a/idea/benches/lib.rs b/idea/benches/lib.rs deleted file mode 100644 index 04d72a48..00000000 --- a/idea/benches/lib.rs +++ /dev/null @@ -1,3 +0,0 @@ -#![feature(test)] - -cipher::block_cipher_bench!(idea::Idea, 16); diff --git a/idea/benches/mod.rs b/idea/benches/mod.rs new file mode 100644 index 00000000..cf95a4eb --- /dev/null +++ b/idea/benches/mod.rs @@ -0,0 +1,8 @@ +#![feature(test)] +extern crate test; + +use cipher::{block_decryptor_bench, block_encryptor_bench}; +use idea::Idea; + +block_encryptor_bench!(Key: Idea, idea_encrypt_block, idea_encrypt_blocks); +block_decryptor_bench!(Key: Idea, idea_decrypt_block, idea_decrypt_blocks); diff --git a/idea/src/lib.rs b/idea/src/lib.rs index 539e86df..5608f4f6 100644 --- a/idea/src/lib.rs +++ b/idea/src/lib.rs @@ -1,56 +1,66 @@ -//! An implementation of the [IDEA][1] block cipher. +//! Pure Rust implementation of the [IDEA] block cipher. //! -//! [1]: https://en.wikipedia.org/wiki/International_Data_Encryption_Algorithm +//! [IDEA]: https://en.wikipedia.org/wiki/International_Data_Encryption_Algorithm #![no_std] #![doc( - html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg", - html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg" + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg", + html_root_url = "https://docs.rs/idea/0.5.0" )] -#![forbid(unsafe_code)] +#![deny(unsafe_code)] +#![cfg_attr(docsrs, feature(doc_cfg))] #![warn(missing_docs, rust_2018_idioms)] #![allow(clippy::many_single_char_names)] -pub use cipher::{self, BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher}; +pub use cipher; use cipher::{ - consts::{U1, U16, U8}, - generic_array::GenericArray, + consts::{U16, U8}, + inout::InOut, + AlgorithmName, Block, BlockCipher, Key, KeyInit, KeySizeUser, }; +use core::fmt; + +#[cfg(feature = "zeroize")] +use cipher::zeroize::{Zeroize, ZeroizeOnDrop}; mod consts; -use crate::consts::{FUYI, LENGTH_SUB_KEYS, MAXIM, ONE, ROUNDS}; +#[cfg(test)] +mod tests; + +use consts::{FUYI, LENGTH_SUB_KEYS, MAXIM, ONE, ROUNDS}; /// The International Data Encryption Algorithm (IDEA) block cipher. -#[derive(Copy, Clone)] +#[derive(Clone)] pub struct Idea { - encryption_sub_keys: [u16; LENGTH_SUB_KEYS], - decryption_sub_keys: [u16; LENGTH_SUB_KEYS], + enc_keys: [u16; LENGTH_SUB_KEYS], + dec_keys: [u16; LENGTH_SUB_KEYS], } impl Idea { - fn expand_key(&mut self, key: &GenericArray) { + fn expand_key(&mut self, key: &Key) { let length_key = key.len(); for i in 0..(length_key / 2) { - self.encryption_sub_keys[i] = (u16::from(key[2 * i]) << 8) + u16::from(key[2 * i + 1]); + self.enc_keys[i] = (u16::from(key[2 * i]) << 8) + u16::from(key[2 * i + 1]); } let mut a: u16; let mut b: u16; for i in (length_key / 2)..LENGTH_SUB_KEYS { if (i + 1) % 8 == 0 { - a = self.encryption_sub_keys[i - 15]; + a = self.enc_keys[i - 15]; } else { - a = self.encryption_sub_keys[i - 7]; + a = self.enc_keys[i - 7]; } if (i + 2) % 8 < 2 { - b = self.encryption_sub_keys[i - 14]; + b = self.enc_keys[i - 14]; } else { - b = self.encryption_sub_keys[i - 6]; + b = self.enc_keys[i - 6]; } - self.encryption_sub_keys[i] = (a << 9) + (b >> 7); + self.enc_keys[i] = (a << 9) + (b >> 7); } } @@ -62,26 +72,27 @@ impl Idea { let (m, n) = if i > 0 && i < 8 { (2, 1) } else { (1, 2) }; - self.decryption_sub_keys[j] = self.mul_inv(self.encryption_sub_keys[l]); - self.decryption_sub_keys[j + 1] = self.add_inv(self.encryption_sub_keys[l + m]); - self.decryption_sub_keys[j + 2] = self.add_inv(self.encryption_sub_keys[l + n]); - self.decryption_sub_keys[j + 3] = self.mul_inv(self.encryption_sub_keys[l + 3]); + self.dec_keys[j] = self.mul_inv(self.enc_keys[l]); + self.dec_keys[j + 1] = self.add_inv(self.enc_keys[l + m]); + self.dec_keys[j + 2] = self.add_inv(self.enc_keys[l + n]); + self.dec_keys[j + 3] = self.mul_inv(self.enc_keys[l + 3]); } k = (ROUNDS - 1) * 6; for i in 0..ROUNDS { let j = i * 6; let l = k - j; - self.decryption_sub_keys[j + 4] = self.encryption_sub_keys[l + 4]; - self.decryption_sub_keys[j + 5] = self.encryption_sub_keys[l + 5]; + self.dec_keys[j + 4] = self.enc_keys[l + 4]; + self.dec_keys[j + 5] = self.enc_keys[l + 5]; } } - fn crypt(&self, block: &mut GenericArray, sub_keys: &[u16; LENGTH_SUB_KEYS]) { - let mut x1 = (u16::from(block[0]) << 8) + (u16::from(block[1])); - let mut x2 = (u16::from(block[2]) << 8) + (u16::from(block[3])); - let mut x3 = (u16::from(block[4]) << 8) + (u16::from(block[5])); - let mut x4 = (u16::from(block[6]) << 8) + (u16::from(block[7])); + fn crypt(&self, mut block: InOut<'_, '_, Block>, sub_keys: &[u16; LENGTH_SUB_KEYS]) { + let b = block.get_in(); + let mut x1 = u16::from_be_bytes(b[0..2].try_into().unwrap()); + let mut x2 = u16::from_be_bytes(b[2..4].try_into().unwrap()); + let mut x3 = u16::from_be_bytes(b[4..6].try_into().unwrap()); + let mut x4 = u16::from_be_bytes(b[6..8].try_into().unwrap()); for i in 0..ROUNDS { let j = i * 6; @@ -106,14 +117,11 @@ impl Idea { let y3 = self.add(x2, sub_keys[50]); let y4 = self.mul(x4, sub_keys[51]); - block[0] = (y1 >> 8) as u8; - block[1] = y1 as u8; - block[2] = (y2 >> 8) as u8; - block[3] = y2 as u8; - block[4] = (y3 >> 8) as u8; - block[5] = y3 as u8; - block[6] = (y4 >> 8) as u8; - block[7] = y4 as u8; + let block = block.get_out(); + block[0..2].copy_from_slice(&y1.to_be_bytes()); + block[2..4].copy_from_slice(&y2.to_be_bytes()); + block[4..6].copy_from_slice(&y3.to_be_bytes()); + block[6..8].copy_from_slice(&y4.to_be_bytes()); } fn mul(&self, a: u16, b: u16) -> u16 { @@ -168,13 +176,17 @@ impl Idea { } } -impl NewBlockCipher for Idea { +impl BlockCipher for Idea {} + +impl KeySizeUser for Idea { type KeySize = U16; +} - fn new(key: &GenericArray) -> Self { +impl KeyInit for Idea { + fn new(key: &Key) -> Self { let mut cipher = Self { - encryption_sub_keys: [0u16; 52], - decryption_sub_keys: [0u16; 52], + enc_keys: [0u16; 52], + dec_keys: [0u16; 52], }; cipher.expand_key(key); cipher.invert_sub_keys(); @@ -182,24 +194,37 @@ impl NewBlockCipher for Idea { } } -impl BlockCipher for Idea { - type BlockSize = U8; - type ParBlocks = U1; +impl fmt::Debug for Idea { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Idea { ... }") + } } -impl BlockEncrypt for Idea { - fn encrypt_block(&self, block: &mut GenericArray) { - self.crypt(block, &self.encryption_sub_keys); +impl AlgorithmName for Idea { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Idea") } } -impl BlockDecrypt for Idea { - fn decrypt_block(&self, block: &mut GenericArray) { - self.crypt(block, &self.decryption_sub_keys); +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl Drop for Idea { + fn drop(&mut self) { + self.enc_keys.zeroize(); + self.dec_keys.zeroize(); } } -opaque_debug::implement!(Idea); +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl ZeroizeOnDrop for Idea {} -#[cfg(test)] -mod tests; +cipher::impl_simple_block_encdec!( + Idea, U8, cipher, block, + encrypt: { + cipher.crypt(block, &cipher.enc_keys); + } + decrypt: { + cipher.crypt(block, &cipher.dec_keys); + } +); diff --git a/idea/src/tests.rs b/idea/src/tests.rs index 2d50d915..eaba4c05 100644 --- a/idea/src/tests.rs +++ b/idea/src/tests.rs @@ -1,29 +1,33 @@ use super::*; #[test] +#[rustfmt::skip] fn test_sub_key_generation() { let key: [u8; 16] = [ - 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, - 0x08, + 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, + 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, ]; - let encryption_sub_keys: [u16; 52] = [ - 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0400, 0x0600, 0x0800, - 0x0a00, 0x0c00, 0x0e00, 0x1000, 0x0200, 0x0010, 0x0014, 0x0018, 0x001c, 0x0020, 0x0004, - 0x0008, 0x000c, 0x2800, 0x3000, 0x3800, 0x4000, 0x0800, 0x1000, 0x1800, 0x2000, 0x0070, - 0x0080, 0x0010, 0x0020, 0x0030, 0x0040, 0x0050, 0x0060, 0x0000, 0x2000, 0x4000, 0x6000, - 0x8000, 0xa000, 0xc000, 0xe001, 0x0080, 0x00c0, 0x0100, 0x0140, + let enc_keys: [u16; 52] = [ + 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, + 0x0400, 0x0600, 0x0800, 0x0a00, 0x0c00, 0x0e00, 0x1000, 0x0200, + 0x0010, 0x0014, 0x0018, 0x001c, 0x0020, 0x0004, 0x0008, 0x000c, + 0x2800, 0x3000, 0x3800, 0x4000, 0x0800, 0x1000, 0x1800, 0x2000, + 0x0070, 0x0080, 0x0010, 0x0020, 0x0030, 0x0040, 0x0050, 0x0060, + 0x0000, 0x2000, 0x4000, 0x6000, 0x8000, 0xa000, 0xc000, 0xe001, + 0x0080, 0x00c0, 0x0100, 0x0140, ]; - let decryption_sub_keys: [u16; 52] = [ - 0xfe01, 0xff40, 0xff00, 0x659a, 0xc000, 0xe001, 0xfffd, 0x8000, 0xa000, 0xcccc, 0x0000, - 0x2000, 0xa556, 0xffb0, 0xffc0, 0x52ab, 0x0010, 0x0020, 0x554b, 0xff90, 0xe000, 0xfe01, - 0x0800, 0x1000, 0x332d, 0xc800, 0xd000, 0xfffd, 0x0008, 0x000c, 0x4aab, 0xffe0, 0xffe4, - 0xc001, 0x0010, 0x0014, 0xaa96, 0xf000, 0xf200, 0xff81, 0x0800, 0x0a00, 0x4925, 0xfc00, - 0xfff8, 0x552b, 0x0005, 0x0006, 0x0001, 0xfffe, 0xfffd, 0xc001, + let dec_keys: [u16; 52] = [ + 0xfe01, 0xff40, 0xff00, 0x659a, 0xc000, 0xe001, 0xfffd, 0x8000, + 0xa000, 0xcccc, 0x0000, 0x2000, 0xa556, 0xffb0, 0xffc0, 0x52ab, + 0x0010, 0x0020, 0x554b, 0xff90, 0xe000, 0xfe01, 0x0800, 0x1000, + 0x332d, 0xc800, 0xd000, 0xfffd, 0x0008, 0x000c, 0x4aab, 0xffe0, + 0xffe4, 0xc001, 0x0010, 0x0014, 0xaa96, 0xf000, 0xf200, 0xff81, + 0x0800, 0x0a00, 0x4925, 0xfc00, 0xfff8, 0x552b, 0x0005, 0x0006, + 0x0001, 0xfffe, 0xfffd, 0xc001, ]; - let user_key = GenericArray::from_slice(&key); - let idea = Idea::new(&user_key); + let idea = Idea::new_from_slice(&key).unwrap(); - assert_eq!(&idea.encryption_sub_keys[..], &encryption_sub_keys[..]); - assert_eq!(&idea.decryption_sub_keys[..], &decryption_sub_keys[..]); + assert_eq!(&idea.enc_keys[..], &enc_keys[..]); + assert_eq!(&idea.dec_keys[..], &dec_keys[..]); } diff --git a/idea/tests/lib.rs b/idea/tests/mod.rs similarity index 100% rename from idea/tests/lib.rs rename to idea/tests/mod.rs diff --git a/kuznyechik/CHANGELOG.md b/kuznyechik/CHANGELOG.md index aee126dd..1a42f08a 100644 --- a/kuznyechik/CHANGELOG.md +++ b/kuznyechik/CHANGELOG.md @@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 0.8.0 (2022-02-10) +### Changed +- Bump `cipher` dependency to v0.4 ([#284]) + +### Added +- Encrypt-only `KuznyechikEnc` and decrypt-only `KuznyechikDec` types ([#284]) + +[#284]: https://github.com/RustCrypto/block-ciphers/pull/284 + ## 0.7.2 (2021-08-26) ### Added - Parallel block processing for SSE2 backend ([#278]) @@ -19,7 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## 0.7.0 (2021-04-29) ### Changed -- Bump `cipher` dependency to v0.3 release ([#235]) +- Bump `cipher` dependency to v0.3 ([#235]) [#235]: https://github.com/RustCrypto/block-ciphers/pull/235 diff --git a/kuznyechik/Cargo.toml b/kuznyechik/Cargo.toml index 040da11f..44612559 100644 --- a/kuznyechik/Cargo.toml +++ b/kuznyechik/Cargo.toml @@ -1,26 +1,27 @@ [package] name = "kuznyechik" -version = "0.7.2" +version = "0.8.0" # Also update html_root_url in lib.rs when bumping this description = "Kuznyechik (GOST R 34.12-2015) block cipher" authors = ["RustCrypto Developers"] license = "MIT OR Apache-2.0" +edition = "2021" +rust-version = "1.56" readme = "README.md" -edition = "2018" documentation = "https://docs.rs/kuznyechik" repository = "https://github.com/RustCrypto/block-ciphers" keywords = ["crypto", "kuznyechik", "gost", "block-cipher"] categories = ["cryptography", "no-std"] [dependencies] -cipher = "0.3" +cipher = "0.4" [dev-dependencies] -cipher = { version = "0.3", features = ["dev"] } -hex-literal = "0.2" +cipher = { version = "0.4", features = ["dev"] } +hex-literal = "0.3" [features] -# disables loop unrolling, which reduces resulting binary size, -# but may degrade performance in return -no_unroll = [] -# force software implementation which uses smaller tables -force-soft = [] +zeroize = ["cipher/zeroize"] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] diff --git a/kuznyechik/README.md b/kuznyechik/README.md index 438e4757..3ea1036a 100644 --- a/kuznyechik/README.md +++ b/kuznyechik/README.md @@ -26,7 +26,7 @@ USE AT YOUR OWN RISK! ## Minimum Supported Rust Version -Rust **1.41** or higher. +Rust **1.56** or higher. Minimum supported Rust version can be changed in the future, but it will be done with a minor version bump. @@ -58,7 +58,7 @@ dual licensed as above, without any additional terms or conditions. [docs-image]: https://docs.rs/kuznyechik/badge.svg [docs-link]: https://docs.rs/kuznyechik/ [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg -[rustc-image]: https://img.shields.io/badge/rustc-1.41+-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.56+-blue.svg [hazmat-image]: https://img.shields.io/badge/crypto-hazmat%E2%9A%A0-red.svg [hazmat-link]: https://github.com/RustCrypto/meta/blob/master/HAZMAT.md [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg diff --git a/kuznyechik/benches/lib.rs b/kuznyechik/benches/lib.rs deleted file mode 100644 index 86f68f3b..00000000 --- a/kuznyechik/benches/lib.rs +++ /dev/null @@ -1,3 +0,0 @@ -#![feature(test)] - -cipher::block_cipher_bench!(kuznyechik::Kuznyechik, 32); diff --git a/kuznyechik/benches/mod.rs b/kuznyechik/benches/mod.rs new file mode 100644 index 00000000..2fb5984f --- /dev/null +++ b/kuznyechik/benches/mod.rs @@ -0,0 +1,16 @@ +#![feature(test)] +extern crate test; + +use cipher::{block_decryptor_bench, block_encryptor_bench}; +use kuznyechik::Kuznyechik; + +block_encryptor_bench!( + Key: Kuznyechik, + kuznyechik_encrypt_block, + kuznyechik_encrypt_blocks, +); +block_decryptor_bench!( + Key: Kuznyechik, + kuznyechik_decrypt_block, + kuznyechik_decrypt_blocks, +); diff --git a/kuznyechik/src/lib.rs b/kuznyechik/src/lib.rs index f2c62329..692c1196 100644 --- a/kuznyechik/src/lib.rs +++ b/kuznyechik/src/lib.rs @@ -1,25 +1,39 @@ -//! Pure Rust implementation of the [Kuznyechik][1] (GOST R 34.12-2015) block cipher. +//! Pure Rust implementation of the [Kuznyechik] ([GOST R 34.12-2015]) block cipher. //! -//! [1]: https://en.wikipedia.org/wiki/Kuznyechik +//! # Configuration Flags +//! +//! You can modify crate using the following configuration flag: +//! +//! - `kuznyechik_force_soft`: force software implementation. +//! +//! It can be enabled using `RUSTFLAGS` enviromental variable +//! (e.g. `RUSTFLAGS="--cfg kuznyechik_force_soft"`) or by modifying +//! `.cargo/config`. +//! +//! [Kuznyechik]: https://en.wikipedia.org/wiki/Kuznyechik +//! [GOST R 34.12-2015]: https://tc26.ru/standard/gost/GOST_R_3412-2015.pdf #![no_std] #![doc( - html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg", - html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg" + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg", + html_root_url = "https://docs.rs/kuznyechik/0.8.0" )] +#![cfg_attr(docsrs, feature(doc_cfg))] #![warn(missing_docs, rust_2018_idioms)] #![allow(clippy::needless_range_loop, clippy::transmute_ptr_to_ptr)] pub use cipher; -use core::fmt; +use cipher::{ + consts::{U16, U32}, + generic_array::GenericArray, +}; -#[macro_use] -mod macros; mod consts; #[cfg(all( any(target_arch = "x86_64", target_arch = "x86"), target_feature = "sse2", - not(feature = "force-soft"), + not(kuznyechik_force_soft), ))] #[path = "sse2/mod.rs"] mod imp; @@ -27,15 +41,17 @@ mod imp; #[cfg(not(all( any(target_arch = "x86_64", target_arch = "x86"), target_feature = "sse2", - not(feature = "force-soft"), + not(kuznyechik_force_soft), )))] #[path = "soft/mod.rs"] mod imp; -pub use imp::Kuznyechik; +pub use imp::{Kuznyechik, KuznyechikDec, KuznyechikEnc}; + +type BlockSize = U16; +type KeySize = U32; -impl fmt::Debug for Kuznyechik { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - write!(f, "Kuznyechik {{ ... }}") - } -} +/// 128-bit Kuznyechik block +pub type Block = GenericArray; +/// 256-bit Kuznyechik key +pub type Key = GenericArray; diff --git a/kuznyechik/src/macros.rs b/kuznyechik/src/macros.rs deleted file mode 100644 index bf37c6b0..00000000 --- a/kuznyechik/src/macros.rs +++ /dev/null @@ -1,78 +0,0 @@ -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_macros)] - -#[cfg(not(feature = "no_unroll"))] -#[rustfmt::skip] -macro_rules! unroll8 { - ($var:ident, $body:block) => { - { let $var: usize = 0; $body; } - { let $var: usize = 1; $body; } - { let $var: usize = 2; $body; } - { let $var: usize = 3; $body; } - { let $var: usize = 4; $body; } - { let $var: usize = 5; $body; } - { let $var: usize = 6; $body; } - { let $var: usize = 7; $body; } - }; -} - -#[cfg(feature = "no_unroll")] -macro_rules! unroll8 { - ($var:ident, $body:block) => { - for $var in 0..8 $body - } -} - -#[cfg(not(feature = "no_unroll"))] -#[rustfmt::skip] -macro_rules! unroll9 { - ($var:ident, $body:block) => { - { let $var: usize = 0; $body; } - { let $var: usize = 1; $body; } - { let $var: usize = 2; $body; } - { let $var: usize = 3; $body; } - { let $var: usize = 4; $body; } - { let $var: usize = 5; $body; } - { let $var: usize = 6; $body; } - { let $var: usize = 7; $body; } - { let $var: usize = 8; $body; } - }; -} - -#[cfg(feature = "no_unroll")] -macro_rules! unroll9 { - ($var:ident, $body:block) => { - for $var in 0..9 $body - } -} - - -#[cfg(not(feature = "no_unroll"))] -#[rustfmt::skip] -macro_rules! unroll16 { - ($var:ident, $body:block) => { - { let $var: usize = 0; $body; } - { let $var: usize = 1; $body; } - { let $var: usize = 2; $body; } - { let $var: usize = 3; $body; } - { let $var: usize = 4; $body; } - { let $var: usize = 5; $body; } - { let $var: usize = 6; $body; } - { let $var: usize = 7; $body; } - { let $var: usize = 8; $body; } - { let $var: usize = 9; $body; } - { let $var: usize = 10; $body; } - { let $var: usize = 11; $body; } - { let $var: usize = 12; $body; } - { let $var: usize = 13; $body; } - { let $var: usize = 14; $body; } - { let $var: usize = 15; $body; } - }; -} - -#[cfg(feature = "no_unroll")] -macro_rules! unroll16 { - ($var:ident, $body:block) => { - for $var in 0..16 $body - } -} diff --git a/kuznyechik/src/soft/backends.rs b/kuznyechik/src/soft/backends.rs new file mode 100644 index 00000000..076f4963 --- /dev/null +++ b/kuznyechik/src/soft/backends.rs @@ -0,0 +1,167 @@ +use super::consts::GF; +use crate::consts::{P, P_INV}; +use crate::{Block, Key}; +use cipher::{ + consts::{U1, U16}, + inout::InOut, + BlockBackend, BlockSizeUser, ParBlocks, ParBlocksSizeUser, +}; + +pub(super) type RoundKeys = [Block; 10]; + +#[inline(always)] +fn x(a: &mut Block, b: &Block) { + for i in 0..16 { + a[i] ^= b[i]; + } +} + +fn l_step(msg: &mut Block, i: usize) { + #[inline(always)] + fn get_idx(b: usize, i: usize) -> usize { + b.wrapping_sub(i) & 0x0F + } + #[inline(always)] + fn get_m(msg: &Block, b: usize, i: usize) -> usize { + msg[get_idx(b, i)] as usize + } + + let mut x = msg[get_idx(15, i)]; + x ^= GF[3][get_m(msg, 14, i)]; + x ^= GF[1][get_m(msg, 13, i)]; + x ^= GF[2][get_m(msg, 12, i)]; + x ^= GF[0][get_m(msg, 11, i)]; + x ^= GF[5][get_m(msg, 10, i)]; + x ^= GF[4][get_m(msg, 9, i)]; + x ^= msg[get_idx(8, i)]; + x ^= GF[6][get_m(msg, 7, i)]; + x ^= msg[get_idx(6, i)]; + x ^= GF[4][get_m(msg, 5, i)]; + x ^= GF[5][get_m(msg, 4, i)]; + x ^= GF[0][get_m(msg, 3, i)]; + x ^= GF[2][get_m(msg, 2, i)]; + x ^= GF[1][get_m(msg, 1, i)]; + x ^= GF[3][get_m(msg, 0, i)]; + msg[get_idx(15, i)] = x; +} + +#[inline(always)] +fn lsx(block: &mut Block, key: &Block) { + x(block, key); + // s + for i in 0..16 { + block[i] = P[block[i] as usize]; + } + // l + for i in 0..16 { + l_step(block, i); + } +} + +#[inline(always)] +fn lsx_inv(block: &mut Block, key: &Block) { + x(block, key); + // l_inv + for i in 0..16 { + l_step(block, 15 - i); + } + // s_inv + for i in 0..16 { + block[15 - i] = P_INV[block[15 - i] as usize]; + } +} + +fn get_c(n: usize) -> Block { + let mut v = Block::default(); + v[15] = n as u8; + for i in 0..16 { + l_step(&mut v, i); + } + v +} + +fn f(k1: &mut Block, k2: &mut Block, n: usize) { + for i in 0..4 { + let mut k1_cpy = *k1; + lsx(&mut k1_cpy, &get_c(8 * n + 2 * i + 1)); + x(k2, &k1_cpy); + + let mut k2_cpy = *k2; + lsx(&mut k2_cpy, &get_c(8 * n + 2 * i + 2)); + x(k1, &k2_cpy); + } +} + +pub(super) fn expand(key: &Key) -> RoundKeys { + let mut keys = RoundKeys::default(); + + let mut k1 = Block::default(); + let mut k2 = Block::default(); + + k1.copy_from_slice(&key[..16]); + k2.copy_from_slice(&key[16..]); + + keys[0] = k1; + keys[1] = k2; + + for i in 1..5 { + f(&mut k1, &mut k2, i - 1); + keys[2 * i] = k1; + keys[2 * i + 1] = k2; + } + keys +} + +pub(crate) struct EncBackend<'a>(pub(crate) &'a RoundKeys); + +impl<'a> BlockSizeUser for EncBackend<'a> { + type BlockSize = U16; +} + +impl<'a> ParBlocksSizeUser for EncBackend<'a> { + type ParBlocksSize = U1; +} + +impl<'a> BlockBackend for EncBackend<'a> { + #[inline] + fn proc_block(&mut self, mut block: InOut<'_, '_, Block>) { + let mut b = *block.get_in(); + for i in 0..9 { + lsx(&mut b, &self.0[i]); + } + x(&mut b, &self.0[9]); + *block.get_out() = b; + } + + #[inline(always)] + fn proc_par_blocks(&mut self, mut blocks: InOut<'_, '_, ParBlocks>) { + self.proc_block(blocks.get(0)); + } +} + +pub(crate) struct DecBackend<'a>(pub(crate) &'a RoundKeys); + +impl<'a> BlockSizeUser for DecBackend<'a> { + type BlockSize = U16; +} + +impl<'a> ParBlocksSizeUser for DecBackend<'a> { + type ParBlocksSize = U1; +} + +impl<'a> BlockBackend for DecBackend<'a> { + #[inline] + fn proc_block(&mut self, mut block: InOut<'_, '_, Block>) { + let mut b = *block.get_in(); + for i in 0..9 { + lsx_inv(&mut b, &self.0[9 - i]); + } + x(&mut b, &self.0[0]); + *block.get_out() = b; + } + + #[inline(always)] + fn proc_par_blocks(&mut self, mut blocks: InOut<'_, '_, ParBlocks>) { + self.proc_block(blocks.get(0)); + } +} diff --git a/kuznyechik/src/soft/mod.rs b/kuznyechik/src/soft/mod.rs index 693ab2c5..09ca882b 100644 --- a/kuznyechik/src/soft/mod.rs +++ b/kuznyechik/src/soft/mod.rs @@ -1,161 +1,214 @@ -pub use cipher; - -use crate::consts::{P, P_INV}; +use crate::{BlockSize, Key, KeySize}; use cipher::{ - consts::{U1, U16, U32}, - generic_array::GenericArray, - BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher, + AlgorithmName, BlockCipher, BlockClosure, BlockDecrypt, BlockEncrypt, BlockSizeUser, KeyInit, + KeySizeUser, }; +use core::fmt; + +#[cfg(feature = "zeroize")] +use cipher::zeroize::{Zeroize, ZeroizeOnDrop}; +mod backends; mod consts; -type Block = GenericArray; +use backends::{DecBackend, EncBackend, RoundKeys}; /// Kuznyechik (GOST R 34.12-2015) block cipher -#[derive(Clone, Copy)] +#[derive(Clone)] pub struct Kuznyechik { - keys: [[u8; 16]; 10], + keys: RoundKeys, } -#[inline(always)] -fn x(a: &mut [u8; 16], b: &[u8; 16]) { - for i in 0..16 { - a[i] ^= b[i]; - } +impl BlockCipher for Kuznyechik {} + +impl KeySizeUser for Kuznyechik { + type KeySize = KeySize; } -fn l_step(msg: &mut [u8; 16], i: usize) { - #[inline(always)] - fn get_idx(b: usize, i: usize) -> usize { - b.wrapping_sub(i) & 0x0F +impl BlockSizeUser for Kuznyechik { + type BlockSize = BlockSize; +} + +impl KeyInit for Kuznyechik { + fn new(key: &Key) -> Self { + Self { + keys: backends::expand(key), + } } - #[inline(always)] - fn get_m(msg: &[u8; 16], b: usize, i: usize) -> usize { - msg[get_idx(b, i)] as usize +} + +impl From for Kuznyechik { + #[inline] + fn from(enc: KuznyechikEnc) -> Kuznyechik { + Self { keys: enc.keys } } +} - let mut x = msg[get_idx(15, i)]; - x ^= consts::GF[3][get_m(msg, 14, i)]; - x ^= consts::GF[1][get_m(msg, 13, i)]; - x ^= consts::GF[2][get_m(msg, 12, i)]; - x ^= consts::GF[0][get_m(msg, 11, i)]; - x ^= consts::GF[5][get_m(msg, 10, i)]; - x ^= consts::GF[4][get_m(msg, 9, i)]; - x ^= msg[get_idx(8, i)]; - x ^= consts::GF[6][get_m(msg, 7, i)]; - x ^= msg[get_idx(6, i)]; - x ^= consts::GF[4][get_m(msg, 5, i)]; - x ^= consts::GF[5][get_m(msg, 4, i)]; - x ^= consts::GF[0][get_m(msg, 3, i)]; - x ^= consts::GF[2][get_m(msg, 2, i)]; - x ^= consts::GF[1][get_m(msg, 1, i)]; - x ^= consts::GF[3][get_m(msg, 0, i)]; - msg[get_idx(15, i)] = x; +impl From<&KuznyechikEnc> for Kuznyechik { + #[inline] + fn from(enc: &KuznyechikEnc) -> Kuznyechik { + Self { + keys: enc.keys.clone(), + } + } } -#[inline(always)] -fn lsx(msg: &mut [u8; 16], key: &[u8; 16]) { - x(msg, key); - // s - unroll16! {i, { msg[i] = P[msg[i] as usize]; }}; - // l - unroll16! {i, { l_step(msg, i) }}; +impl BlockEncrypt for Kuznyechik { + fn encrypt_with_backend(&self, f: impl BlockClosure) { + f.call(&mut EncBackend(&self.keys)); + } } -#[inline(always)] -fn lsx_inv(msg: &mut [u8; 16], key: &[u8; 16]) { - x(msg, key); - // l_inv - unroll16! {i, { l_step(msg, 15 - i) }}; - // s_inv - unroll16! {i, { msg[15 - i] = P_INV[msg[15 - i] as usize]; }}; +impl BlockDecrypt for Kuznyechik { + fn decrypt_with_backend(&self, f: impl BlockClosure) { + f.call(&mut DecBackend(&self.keys)); + } } -fn get_c(n: usize) -> [u8; 16] { - let mut v = [0u8; 16]; - v[15] = n as u8; - for i in 0..16 { - l_step(&mut v, i); +impl fmt::Debug for Kuznyechik { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str("Kuznyechik { ... }") } - v } -fn f(k1: &mut [u8; 16], k2: &mut [u8; 16], n: usize) { - for i in 0..4 { - let mut k1_cpy = *k1; - lsx(&mut k1_cpy, &get_c(8 * n + 2 * i + 1)); - x(k2, &k1_cpy); +impl AlgorithmName for Kuznyechik { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Kuznyechik") + } +} - let mut k2_cpy = *k2; - lsx(&mut k2_cpy, &get_c(8 * n + 2 * i + 2)); - x(k1, &k2_cpy); +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl Drop for Kuznyechik { + fn drop(&mut self) { + self.keys.zeroize(); } } -impl Kuznyechik { - fn expand_key(&mut self, key: &GenericArray) { - let mut k1 = [0u8; 16]; - let mut k2 = [0u8; 16]; +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl ZeroizeOnDrop for Kuznyechik {} + +/// Kuznyechik (GOST R 34.12-2015) block cipher (encrypt-only) +#[derive(Clone)] +pub struct KuznyechikEnc { + keys: RoundKeys, +} + +impl BlockCipher for KuznyechikEnc {} - k1.copy_from_slice(&key[..16]); - k2.copy_from_slice(&key[16..]); +impl KeySizeUser for KuznyechikEnc { + type KeySize = KeySize; +} - self.keys[0] = k1; - self.keys[1] = k2; +impl BlockSizeUser for KuznyechikEnc { + type BlockSize = BlockSize; +} - for i in 1..5 { - f(&mut k1, &mut k2, i - 1); - self.keys[2 * i] = k1; - self.keys[2 * i + 1] = k2; +impl KeyInit for KuznyechikEnc { + fn new(key: &Key) -> Self { + Self { + keys: backends::expand(key), } } +} - fn encrypt(&self, msg: &mut [u8; 16]) { - unroll9! { - i, { lsx(msg, &self.keys[i]) ; } - } - x(msg, &self.keys[9]) +impl BlockEncrypt for KuznyechikEnc { + fn encrypt_with_backend(&self, f: impl BlockClosure) { + f.call(&mut EncBackend(&self.keys)); } +} - fn decrypt(&self, msg: &mut [u8; 16]) { - unroll9! { - i, { lsx_inv(msg, &self.keys[9 - i]) ; } - } - x(msg, &self.keys[0]) +impl fmt::Debug for KuznyechikEnc { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str("KuznyechikEnc { ... }") } } -impl NewBlockCipher for Kuznyechik { - type KeySize = U32; +impl AlgorithmName for KuznyechikEnc { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Kuznyechik") + } +} - fn new(key: &GenericArray) -> Self { - let mut cipher = Self { - keys: Default::default(), - }; - cipher.expand_key(key); - cipher +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl Drop for KuznyechikEnc { + fn drop(&mut self) { + self.keys.zeroize(); } } -impl BlockCipher for Kuznyechik { - type BlockSize = U16; - type ParBlocks = U1; +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl ZeroizeOnDrop for KuznyechikEnc {} + +/// Kuznyechik (GOST R 34.12-2015) block cipher (decrypt-only) +#[derive(Clone)] +pub struct KuznyechikDec { + keys: RoundKeys, } -impl BlockEncrypt for Kuznyechik { +impl BlockCipher for KuznyechikDec {} + +impl KeySizeUser for KuznyechikDec { + type KeySize = KeySize; +} + +impl BlockSizeUser for KuznyechikDec { + type BlockSize = BlockSize; +} + +impl KeyInit for KuznyechikDec { + fn new(key: &Key) -> Self { + Self { + keys: backends::expand(key), + } + } +} + +impl From for KuznyechikDec { #[inline] - fn encrypt_block(&self, block: &mut Block) { - #[allow(unsafe_code)] - let block: &mut [u8; 16] = unsafe { core::mem::transmute(block) }; - self.encrypt(block); + fn from(enc: KuznyechikEnc) -> KuznyechikDec { + Self { keys: enc.keys } } } -impl BlockDecrypt for Kuznyechik { +impl From<&KuznyechikEnc> for KuznyechikDec { #[inline] - fn decrypt_block(&self, block: &mut Block) { - #[allow(unsafe_code)] - let block: &mut [u8; 16] = unsafe { core::mem::transmute(block) }; - self.decrypt(block); + fn from(enc: &KuznyechikEnc) -> KuznyechikDec { + Self { + keys: enc.keys.clone(), + } + } +} + +impl BlockDecrypt for KuznyechikDec { + fn decrypt_with_backend(&self, f: impl BlockClosure) { + f.call(&mut DecBackend(&self.keys)); + } +} + +impl fmt::Debug for KuznyechikDec { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str("KuznyechikDec { ... }") } } + +impl AlgorithmName for KuznyechikDec { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Kuznyechik") + } +} + +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl Drop for KuznyechikDec { + fn drop(&mut self) { + self.keys.zeroize(); + } +} + +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl ZeroizeOnDrop for KuznyechikDec {} diff --git a/kuznyechik/src/sse2/backends.rs b/kuznyechik/src/sse2/backends.rs new file mode 100644 index 00000000..3ffda10d --- /dev/null +++ b/kuznyechik/src/sse2/backends.rs @@ -0,0 +1,296 @@ +use super::consts::{Table, DEC_TABLE, ENC_TABLE, RKEY_GEN}; +use crate::{ + consts::{P, P_INV}, + Block, Key, +}; +use cipher::{ + consts::{U16, U4}, + inout::InOut, + typenum::Unsigned, + BlockBackend, BlockSizeUser, ParBlocks, ParBlocksSizeUser, +}; +use core::arch::x86_64::*; + +pub(super) type RoundKeys = [__m128i; 10]; + +type ParBlocksSize = U4; + +#[rustfmt::skip] +macro_rules! unroll_par { + ($var:ident, $body:block) => { + { let $var: usize = 0; $body; } + { let $var: usize = 1; $body; } + { let $var: usize = 2; $body; } + { let $var: usize = 3; $body; } + }; +} + +#[inline(always)] +unsafe fn sub_bytes(block: __m128i, sbox: &[u8; 256]) -> __m128i { + let t0 = _mm_extract_epi16(block, 0) as u16; + let t1 = _mm_extract_epi16(block, 1) as u16; + let t2 = _mm_extract_epi16(block, 2) as u16; + let t3 = _mm_extract_epi16(block, 3) as u16; + let t4 = _mm_extract_epi16(block, 4) as u16; + let t5 = _mm_extract_epi16(block, 5) as u16; + let t6 = _mm_extract_epi16(block, 6) as u16; + let t7 = _mm_extract_epi16(block, 7) as u16; + + _mm_set_epi8( + sbox[(t7 >> 8) as usize] as i8, + sbox[(t7 & 0xFF) as usize] as i8, + sbox[(t6 >> 8) as usize] as i8, + sbox[(t6 & 0xFF) as usize] as i8, + sbox[(t5 >> 8) as usize] as i8, + sbox[(t5 & 0xFF) as usize] as i8, + sbox[(t4 >> 8) as usize] as i8, + sbox[(t4 & 0xFF) as usize] as i8, + sbox[(t3 >> 8) as usize] as i8, + sbox[(t3 & 0xFF) as usize] as i8, + sbox[(t2 >> 8) as usize] as i8, + sbox[(t2 & 0xFF) as usize] as i8, + sbox[(t1 >> 8) as usize] as i8, + sbox[(t1 & 0xFF) as usize] as i8, + sbox[(t0 >> 8) as usize] as i8, + sbox[(t0 & 0xFF) as usize] as i8, + ) +} + +#[inline(always)] +unsafe fn transform(block: __m128i, table: &Table) -> __m128i { + macro_rules! get { + ($table:expr, $ind:expr, $i:expr) => {{ + let idx = _mm_extract_epi16($ind, $i) as u16 as usize; + let p = &($table.0[idx]) as *const u8 as *const __m128i; + // correct aligment of `p` is guaranteed since offset values + // are shifted by 4 bits left and the table is aligned to 16 bytes + debug_assert_eq!(p as usize % 16, 0); + _mm_load_si128(p) + }}; + } + + macro_rules! xor_get { + ($val:expr, $table:expr, $ind:expr, $i:expr) => { + $val = _mm_xor_si128($val, get!($table, $ind, $i)); + }; + } + + let ind = _mm_set_epi64x(0x0f0e0d0c0b0a0908, 0x0706050403020100); + + let lind = _mm_slli_epi16(_mm_unpacklo_epi8(block, ind), 4); + + let mut lt = get!(table, lind, 0); + xor_get!(lt, table, lind, 1); + xor_get!(lt, table, lind, 2); + xor_get!(lt, table, lind, 3); + xor_get!(lt, table, lind, 4); + xor_get!(lt, table, lind, 5); + xor_get!(lt, table, lind, 6); + xor_get!(lt, table, lind, 7); + + let rind = _mm_slli_epi16(_mm_unpackhi_epi8(block, ind), 4); + + let mut rt = get!(table, rind, 0); + xor_get!(rt, table, rind, 1); + xor_get!(rt, table, rind, 2); + xor_get!(rt, table, rind, 3); + xor_get!(rt, table, rind, 4); + xor_get!(rt, table, rind, 5); + xor_get!(rt, table, rind, 6); + xor_get!(rt, table, rind, 7); + + _mm_xor_si128(lt, rt) +} + +pub(super) fn expand_enc_keys(key: &Key) -> RoundKeys { + macro_rules! next_const { + ($i:expr) => {{ + let p = RKEY_GEN.0.as_ptr() as *const __m128i; + // correct aligment of `p` is guaranteed since the table + // is aligned to 16 bytes + let p = p.add($i); + debug_assert_eq!(p as usize % 16, 0); + $i += 1; + _mm_load_si128(p) + }}; + } + + unsafe { + let mut enc_keys = [_mm_setzero_si128(); 10]; + + let pk: *const __m128i = key.as_ptr() as *const __m128i; + let mut k1 = _mm_loadu_si128(pk); + let mut k2 = _mm_loadu_si128(pk.add(1)); + enc_keys[0] = k1; + enc_keys[1] = k2; + + let mut cidx = 0; + for i in 1..5 { + for _ in 0..4 { + let mut t = _mm_xor_si128(k1, next_const!(cidx)); + t = transform(t, &ENC_TABLE); + k2 = _mm_xor_si128(k2, t); + + let mut t = _mm_xor_si128(k2, next_const!(cidx)); + t = transform(t, &ENC_TABLE); + k1 = _mm_xor_si128(k1, t); + } + + enc_keys[2 * i] = k1; + enc_keys[2 * i + 1] = k2; + } + + enc_keys + } +} + +pub(super) fn inv_enc_keys(enc_keys: &RoundKeys) -> RoundKeys { + unsafe { + let mut dec_keys = [_mm_setzero_si128(); 10]; + + dec_keys[0] = enc_keys[9]; + for i in 1..9 { + let k = sub_bytes(enc_keys[i], &P); + dec_keys[9 - i] = transform(k, &DEC_TABLE); + } + dec_keys[9] = enc_keys[0]; + + dec_keys + } +} + +pub(crate) struct EncBackend<'a>(pub(crate) &'a RoundKeys); + +impl<'a> BlockSizeUser for EncBackend<'a> { + type BlockSize = U16; +} + +impl<'a> ParBlocksSizeUser for EncBackend<'a> { + type ParBlocksSize = ParBlocksSize; +} + +impl<'a> BlockBackend for EncBackend<'a> { + #[inline] + fn proc_block(&mut self, block: InOut<'_, '_, Block>) { + let k = self.0; + unsafe { + let (in_ptr, out_ptr) = block.into_raw(); + let mut b = _mm_loadu_si128(in_ptr as *const __m128i); + + for i in 0..9 { + b = _mm_xor_si128(b, k[i]); + b = transform(b, &ENC_TABLE); + } + b = _mm_xor_si128(b, k[9]); + _mm_storeu_si128(out_ptr as *mut __m128i, b); + } + } + + #[inline] + fn proc_par_blocks(&mut self, blocks: InOut<'_, '_, ParBlocks>) { + let k = self.0; + unsafe { + let (in_ptr, out_ptr) = blocks.into_raw(); + let in_ptr = in_ptr as *mut __m128i; + let out_ptr = out_ptr as *mut __m128i; + + let mut blocks = [_mm_setzero_si128(); ParBlocksSize::USIZE]; + unroll_par! { + i, { + blocks[i] = _mm_loadu_si128(in_ptr.add(i)); + } + }; + + for i in 0..9 { + unroll_par!(j, { + let t = _mm_xor_si128(blocks[j], k[i]); + blocks[j] = transform(t, &ENC_TABLE); + }); + } + + unroll_par! { + i, { + let t = _mm_xor_si128(blocks[i], k[9]); + _mm_storeu_si128(out_ptr.add(i), t); + } + }; + } + } +} + +pub(crate) struct DecBackend<'a>(pub(crate) &'a RoundKeys); + +impl<'a> BlockSizeUser for DecBackend<'a> { + type BlockSize = U16; +} + +impl<'a> ParBlocksSizeUser for DecBackend<'a> { + type ParBlocksSize = ParBlocksSize; +} + +impl<'a> BlockBackend for DecBackend<'a> { + #[inline] + fn proc_block(&mut self, block: InOut<'_, '_, Block>) { + let k = self.0; + unsafe { + let (in_ptr, out_ptr) = block.into_raw(); + let mut b = _mm_loadu_si128(in_ptr as *const __m128i); + + b = _mm_xor_si128(b, k[0]); + + b = sub_bytes(b, &P); + b = transform(b, &DEC_TABLE); + + for i in 1..9 { + b = transform(b, &DEC_TABLE); + b = _mm_xor_si128(b, k[i]); + } + b = sub_bytes(b, &P_INV); + b = _mm_xor_si128(b, k[9]); + + _mm_storeu_si128(out_ptr as *mut __m128i, b) + } + } + + #[inline] + fn proc_par_blocks(&mut self, blocks: InOut<'_, '_, ParBlocks>) { + let k = self.0; + unsafe { + let (in_ptr, out_ptr) = blocks.into_raw(); + let in_ptr = in_ptr as *mut __m128i; + let out_ptr = out_ptr as *mut __m128i; + + let mut blocks = [_mm_setzero_si128(); ParBlocksSize::USIZE]; + unroll_par! { + i, { + blocks[i] = _mm_loadu_si128(in_ptr.add(i)); + } + }; + + unroll_par! { + i, { + let t = _mm_xor_si128(blocks[i], k[0]); + let t = sub_bytes(t, &P); + blocks[i] = transform(t, &DEC_TABLE); + } + } + + for i in 1..9 { + unroll_par! { + j, { + let t = transform(blocks[j], &DEC_TABLE); + blocks[j] = _mm_xor_si128(t, k[i]); + } + } + } + + unroll_par! { + i, { + let t = sub_bytes(blocks[i], &P_INV); + let t2 = _mm_xor_si128(t, k[9]); + _mm_storeu_si128(out_ptr.add(i), t2) + } + } + } + } +} diff --git a/kuznyechik/src/sse2/mod.rs b/kuznyechik/src/sse2/mod.rs index 039a5b99..3ba16862 100644 --- a/kuznyechik/src/sse2/mod.rs +++ b/kuznyechik/src/sse2/mod.rs @@ -1,293 +1,225 @@ -//! SSE2-based implementation based on https://github.com/aprelev/lg15 +//! SSE2-based implementation based on -pub use cipher; - -use crate::consts::{P, P_INV}; +use crate::{BlockSize, Key, KeySize}; use cipher::{ - consts::{U16, U32}, - generic_array::{typenum::Unsigned, GenericArray}, - BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher, + AlgorithmName, BlockCipher, BlockClosure, BlockDecrypt, BlockEncrypt, BlockSizeUser, KeyInit, + KeySizeUser, }; -use core::arch::x86_64::*; - -type ParBlocks = cipher::consts::U4; - -#[rustfmt::skip] -macro_rules! unroll_par { - ($var:ident, $body:block) => { - { let $var: usize = 0; $body; } - { let $var: usize = 1; $body; } - { let $var: usize = 2; $body; } - { let $var: usize = 3; $body; } - }; -} +use core::fmt; -mod consts; +#[cfg(feature = "zeroize")] +use cipher::zeroize::{Zeroize, ZeroizeOnDrop}; -use consts::{Table, DEC_TABLE, ENC_TABLE}; +mod backends; +mod consts; -type Block = GenericArray; +use backends::{expand_enc_keys, inv_enc_keys, DecBackend, EncBackend, RoundKeys}; /// Kuznyechik (GOST R 34.12-2015) block cipher -#[derive(Clone, Copy)] -#[repr(align(16))] +#[derive(Clone)] pub struct Kuznyechik { - enc_keys: [__m128i; 10], - dec_keys: [__m128i; 8], + enc_keys: RoundKeys, + dec_keys: RoundKeys, } -#[inline(always)] -unsafe fn sub_bytes(block: __m128i, sbox: &[u8; 256]) -> __m128i { - let t0 = _mm_extract_epi16(block, 0) as u16; - let t1 = _mm_extract_epi16(block, 1) as u16; - let t2 = _mm_extract_epi16(block, 2) as u16; - let t3 = _mm_extract_epi16(block, 3) as u16; - let t4 = _mm_extract_epi16(block, 4) as u16; - let t5 = _mm_extract_epi16(block, 5) as u16; - let t6 = _mm_extract_epi16(block, 6) as u16; - let t7 = _mm_extract_epi16(block, 7) as u16; - - _mm_set_epi8( - sbox[(t7 >> 8) as usize] as i8, - sbox[(t7 & 0xFF) as usize] as i8, - sbox[(t6 >> 8) as usize] as i8, - sbox[(t6 & 0xFF) as usize] as i8, - sbox[(t5 >> 8) as usize] as i8, - sbox[(t5 & 0xFF) as usize] as i8, - sbox[(t4 >> 8) as usize] as i8, - sbox[(t4 & 0xFF) as usize] as i8, - sbox[(t3 >> 8) as usize] as i8, - sbox[(t3 & 0xFF) as usize] as i8, - sbox[(t2 >> 8) as usize] as i8, - sbox[(t2 & 0xFF) as usize] as i8, - sbox[(t1 >> 8) as usize] as i8, - sbox[(t1 & 0xFF) as usize] as i8, - sbox[(t0 >> 8) as usize] as i8, - sbox[(t0 & 0xFF) as usize] as i8, - ) +impl BlockCipher for Kuznyechik {} + +impl KeySizeUser for Kuznyechik { + type KeySize = KeySize; } -#[inline(always)] -unsafe fn transform(block: __m128i, table: &Table) -> __m128i { - macro_rules! get { - ($table:expr, $ind:expr, $i:expr) => {{ - let idx = _mm_extract_epi16($ind, $i) as u16 as usize; - let p = &($table.0[idx]) as *const u8 as *const __m128i; - // correct aligment of `p` is guaranteed since offset values - // are shifted by 4 bits left and the table is aligned to 16 bytes - debug_assert_eq!(p as usize % 16, 0); - _mm_load_si128(p) - }}; +impl BlockSizeUser for Kuznyechik { + type BlockSize = BlockSize; +} + +impl KeyInit for Kuznyechik { + fn new(key: &Key) -> Self { + let enc_keys = expand_enc_keys(key); + let dec_keys = inv_enc_keys(&enc_keys); + Self { dec_keys, enc_keys } } +} - macro_rules! xor_get { - ($val:expr, $table:expr, $ind:expr, $i:expr) => { - $val = _mm_xor_si128($val, get!($table, $ind, $i)); - }; +impl From for Kuznyechik { + #[inline] + fn from(enc: KuznyechikEnc) -> Kuznyechik { + Self { + dec_keys: inv_enc_keys(&enc.keys), + enc_keys: enc.keys, + } } +} - let ind = _mm_set_epi64x(0x0f0e0d0c0b0a0908, 0x0706050403020100); +impl From<&KuznyechikEnc> for Kuznyechik { + #[inline] + fn from(enc: &KuznyechikEnc) -> Kuznyechik { + Self { + dec_keys: inv_enc_keys(&enc.keys), + enc_keys: enc.keys, + } + } +} - let lind = _mm_slli_epi16(_mm_unpacklo_epi8(block, ind), 4); +impl BlockEncrypt for Kuznyechik { + fn encrypt_with_backend(&self, f: impl BlockClosure) { + f.call(&mut EncBackend(&self.enc_keys)); + } +} - let mut lt = get!(table, lind, 0); - xor_get!(lt, table, lind, 1); - xor_get!(lt, table, lind, 2); - xor_get!(lt, table, lind, 3); - xor_get!(lt, table, lind, 4); - xor_get!(lt, table, lind, 5); - xor_get!(lt, table, lind, 6); - xor_get!(lt, table, lind, 7); +impl BlockDecrypt for Kuznyechik { + fn decrypt_with_backend(&self, f: impl BlockClosure) { + f.call(&mut DecBackend(&self.dec_keys)); + } +} - let rind = _mm_slli_epi16(_mm_unpackhi_epi8(block, ind), 4); +impl fmt::Debug for Kuznyechik { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str("Kuznyechik { ... }") + } +} - let mut rt = get!(table, rind, 0); - xor_get!(rt, table, rind, 1); - xor_get!(rt, table, rind, 2); - xor_get!(rt, table, rind, 3); - xor_get!(rt, table, rind, 4); - xor_get!(rt, table, rind, 5); - xor_get!(rt, table, rind, 6); - xor_get!(rt, table, rind, 7); +impl AlgorithmName for Kuznyechik { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Kuznyechik") + } +} - _mm_xor_si128(lt, rt) +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl Drop for Kuznyechik { + fn drop(&mut self) { + self.enc_keys.zeroize(); + self.dec_keys.zeroize(); + } } -impl NewBlockCipher for Kuznyechik { - type KeySize = U32; - - fn new(key: &GenericArray) -> Self { - macro_rules! next_const { - ($i:expr) => {{ - let p = consts::RKEY_GEN.0.as_ptr() as *const __m128i; - // correct aligment of `p` is guaranteed since the table - // is aligned to 16 bytes - let p = p.add($i); - debug_assert_eq!(p as usize % 16, 0); - $i += 1; - _mm_load_si128(p) - }}; - } +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl ZeroizeOnDrop for Kuznyechik {} - unsafe { - let mut enc_keys = [_mm_setzero_si128(); 10]; - let mut dec_keys = [_mm_setzero_si128(); 8]; - - let pk: *const __m128i = key.as_ptr() as *const __m128i; - let mut k1 = _mm_loadu_si128(pk); - let mut k2 = _mm_loadu_si128(pk.add(1)); - enc_keys[0] = k1; - enc_keys[1] = k2; - - let mut cidx = 0; - for i in 1..5 { - for _ in 0..4 { - let mut t = _mm_xor_si128(k1, next_const!(cidx)); - t = transform(t, &ENC_TABLE); - k2 = _mm_xor_si128(k2, t); - - let mut t = _mm_xor_si128(k2, next_const!(cidx)); - t = transform(t, &ENC_TABLE); - k1 = _mm_xor_si128(k1, t); - } - - enc_keys[2 * i] = k1; - enc_keys[2 * i + 1] = k2; - } - - for i in 1..9 { - let k = sub_bytes(enc_keys[i], &P); - dec_keys[8 - i] = transform(k, &DEC_TABLE); - } - - Self { enc_keys, dec_keys } +/// Kuznyechik (GOST R 34.12-2015) block cipher (encrypt-only) +#[derive(Clone)] +pub struct KuznyechikEnc { + keys: RoundKeys, +} + +impl BlockCipher for KuznyechikEnc {} + +impl KeySizeUser for KuznyechikEnc { + type KeySize = KeySize; +} + +impl BlockSizeUser for KuznyechikEnc { + type BlockSize = BlockSize; +} + +impl KeyInit for KuznyechikEnc { + fn new(key: &Key) -> Self { + Self { + keys: expand_enc_keys(key), } } } -impl BlockCipher for Kuznyechik { - type BlockSize = U16; - type ParBlocks = ParBlocks; +impl BlockEncrypt for KuznyechikEnc { + fn encrypt_with_backend(&self, f: impl BlockClosure) { + f.call(&mut EncBackend(&self.keys)); + } } -impl BlockEncrypt for Kuznyechik { - #[inline] - fn encrypt_block(&self, block: &mut Block) { - let k = self.enc_keys; - unsafe { - let block_ptr = block.as_ptr() as *mut __m128i; - let mut block = _mm_loadu_si128(block_ptr); - - unroll9! { - i, { - block = _mm_xor_si128(block, k[i]); - block = transform(block, &ENC_TABLE); - } - }; - block = _mm_xor_si128(block, k[9]); - _mm_storeu_si128(block_ptr, block) - } +impl fmt::Debug for KuznyechikEnc { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str("KuznyechikEnc { ... }") } +} - #[inline] - fn encrypt_par_blocks(&self, blocks: &mut GenericArray) { - let k = self.enc_keys; - unsafe { - let bptr = blocks.as_ptr() as *mut __m128i; - let mut blocks = [_mm_setzero_si128(); ParBlocks::USIZE]; - unroll_par! { - i, { - blocks[i] = _mm_loadu_si128(bptr.add(i)); - } - }; - - unroll9! { - i, { - unroll_par!{ - j, { - let t = _mm_xor_si128(blocks[j], k[i]); - blocks[j] = transform(t, &ENC_TABLE); - } - } - } - } - - unroll_par! { - i, { - let t = _mm_xor_si128(blocks[i], k[9]); - _mm_storeu_si128(bptr.add(i), t); - } - } +impl AlgorithmName for KuznyechikEnc { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Kuznyechik") + } +} + +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl Drop for KuznyechikEnc { + fn drop(&mut self) { + self.keys.zeroize(); + } +} + +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl ZeroizeOnDrop for KuznyechikEnc {} + +/// Kuznyechik (GOST R 34.12-2015) block cipher (decrypt-only) +#[derive(Clone)] +pub struct KuznyechikDec { + keys: RoundKeys, +} + +impl BlockCipher for KuznyechikDec {} + +impl KeySizeUser for KuznyechikDec { + type KeySize = KeySize; +} + +impl BlockSizeUser for KuznyechikDec { + type BlockSize = BlockSize; +} + +impl KeyInit for KuznyechikDec { + fn new(key: &Key) -> Self { + let enc_keys = expand_enc_keys(key); + Self { + keys: inv_enc_keys(&enc_keys), } } } -impl BlockDecrypt for Kuznyechik { +impl From for KuznyechikDec { #[inline] - fn decrypt_block(&self, block: &mut Block) { - let ek = self.enc_keys; - let dk = self.dec_keys; - unsafe { - let block_ptr = block.as_ptr() as *mut __m128i; - let mut block = _mm_loadu_si128(block_ptr); - - block = _mm_xor_si128(block, ek[9]); - - block = sub_bytes(block, &P); - block = transform(block, &DEC_TABLE); - - unroll8! { - i, { - block = transform(block, &DEC_TABLE); - block = _mm_xor_si128(block, dk[i]); - } - } - - block = sub_bytes(block, &P_INV); - block = _mm_xor_si128(block, ek[0]); - _mm_storeu_si128(block_ptr, block) + fn from(enc: KuznyechikEnc) -> KuznyechikDec { + Self { + keys: inv_enc_keys(&enc.keys), } } +} +impl From<&KuznyechikEnc> for KuznyechikDec { #[inline] - fn decrypt_par_blocks(&self, blocks: &mut GenericArray) { - let ek = self.enc_keys; - let dk = self.dec_keys; - unsafe { - let bptr = blocks.as_ptr() as *mut __m128i; - let mut blocks = [_mm_setzero_si128(); ParBlocks::USIZE]; - unroll_par! { - i, { - blocks[i] = _mm_loadu_si128(bptr.add(i)); - } - }; - - unroll_par! { - i, { - let t = _mm_xor_si128(blocks[i], ek[9]); - let t = sub_bytes(t, &P); - blocks[i] = transform(t, &DEC_TABLE); - } - } - - unroll8! { - i, { - unroll_par!{ - j, { - let t = transform(blocks[j], &DEC_TABLE); - blocks[j] = _mm_xor_si128(t, dk[i]); - } - } - } - } - - unroll_par! { - i, { - let t = sub_bytes(blocks[i], &P_INV); - let t2 = _mm_xor_si128(t, ek[0]); - _mm_storeu_si128(bptr.add(i), t2) - } - } + fn from(enc: &KuznyechikEnc) -> KuznyechikDec { + Self { + keys: inv_enc_keys(&enc.keys), } } } + +impl BlockDecrypt for KuznyechikDec { + fn decrypt_with_backend(&self, f: impl BlockClosure) { + f.call(&mut DecBackend(&self.keys)); + } +} + +impl fmt::Debug for KuznyechikDec { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str("KuznyechikDec { ... }") + } +} + +impl AlgorithmName for KuznyechikDec { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Kuznyechik") + } +} + +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl Drop for KuznyechikDec { + fn drop(&mut self) { + self.keys.zeroize(); + } +} + +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl ZeroizeOnDrop for KuznyechikDec {} diff --git a/kuznyechik/tests/lib.rs b/kuznyechik/tests/lib.rs deleted file mode 100644 index a5910a82..00000000 --- a/kuznyechik/tests/lib.rs +++ /dev/null @@ -1,24 +0,0 @@ -#![cfg_attr(rustfmt, rustfmt_skip)] - -use cipher::{generic_array::GenericArray, BlockEncrypt, BlockDecrypt, NewBlockCipher}; -use hex_literal::hex; - -/// Example vectors from GOST 34.12-2018 -#[test] -fn kuznyechik() { - let key = hex!(" - 8899AABBCCDDEEFF0011223344556677 - FEDCBA98765432100123456789ABCDEF - "); - let plaintext = hex!("1122334455667700FFEEDDCCBBAA9988"); - let ciphertext = hex!("7F679D90BEBC24305a468d42b9d4EDCD"); - - let state = kuznyechik::Kuznyechik::new_from_slice(&key).unwrap(); - - let mut block = GenericArray::clone_from_slice(&plaintext); - state.encrypt_block(&mut block); - assert_eq!(&ciphertext, block.as_slice()); - - state.decrypt_block(&mut block); - assert_eq!(&plaintext, block.as_slice()); -} diff --git a/kuznyechik/tests/mod.rs b/kuznyechik/tests/mod.rs new file mode 100644 index 00000000..d23f144b --- /dev/null +++ b/kuznyechik/tests/mod.rs @@ -0,0 +1,70 @@ +use cipher::{Block, BlockDecrypt, BlockEncrypt, KeyInit}; +use hex_literal::hex; +use kuznyechik::{Kuznyechik, KuznyechikDec, KuznyechikEnc}; + +/// Example vector from GOST 34.12-2018 +#[test] +fn kuznyechik() { + let key = hex!( + "8899AABBCCDDEEFF0011223344556677" + "FEDCBA98765432100123456789ABCDEF" + ); + let plaintext = hex!("1122334455667700FFEEDDCCBBAA9988"); + let ciphertext = hex!("7F679D90BEBC24305a468d42b9d4EDCD"); + + let cipher = Kuznyechik::new(&key.into()); + let cipher_enc = KuznyechikEnc::new(&key.into()); + let cipher_dec = KuznyechikDec::new(&key.into()); + + let mut block = plaintext.into(); + cipher.encrypt_block(&mut block); + assert_eq!(&ciphertext, block.as_slice()); + + cipher.decrypt_block(&mut block); + assert_eq!(&plaintext, block.as_slice()); + + cipher_enc.encrypt_block(&mut block); + assert_eq!(&ciphertext, block.as_slice()); + + cipher_dec.decrypt_block(&mut block); + assert_eq!(&plaintext, block.as_slice()); + + // test that encrypt_blocks/decrypt_blocks work correctly + let mut blocks = [Block::::default(); 101]; + for (i, block) in blocks.iter_mut().enumerate() { + block.iter_mut().enumerate().for_each(|(j, b)| { + *b = (i + j) as u8; + }); + } + + let mut blocks2 = blocks.clone(); + let blocks_cpy = blocks.clone(); + + cipher.encrypt_blocks(&mut blocks); + assert!(blocks[..] != blocks_cpy[..]); + for block in blocks2.iter_mut() { + cipher.encrypt_block(block); + } + assert_eq!(blocks[..], blocks2[..]); + + cipher.decrypt_blocks(&mut blocks); + assert_eq!(blocks[..], blocks_cpy[..]); + for block in blocks2.iter_mut().rev() { + cipher.decrypt_block(block); + } + assert_eq!(blocks2[..], blocks_cpy[..]); + + cipher_enc.encrypt_blocks(&mut blocks); + assert!(blocks[..] != blocks_cpy[..]); + for block in blocks2.iter_mut() { + cipher_enc.encrypt_block(block); + } + assert_eq!(blocks[..], blocks2[..]); + + cipher_dec.decrypt_blocks(&mut blocks); + assert_eq!(blocks[..], blocks_cpy[..]); + for block in blocks2.iter_mut().rev() { + cipher_dec.decrypt_block(block); + } + assert_eq!(blocks2[..], blocks_cpy[..]); +} diff --git a/magma/CHANGELOG.md b/magma/CHANGELOG.md index 3cb8f6ec..f3ee8816 100644 --- a/magma/CHANGELOG.md +++ b/magma/CHANGELOG.md @@ -5,9 +5,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 0.8.0 (2022-02-10) +### Changed +- Bump `cipher` dependency to v0.4 ([#284]) + +[#284]: https://github.com/RustCrypto/block-ciphers/pull/284 + ## 0.7.0 (2021-04-29) ### Changed -- Bump `cipher` dependency to v0.3 release ([#235]) +- Bump `cipher` dependency to v0.3 ([#235]) [#235]: https://github.com/RustCrypto/block-ciphers/pull/235 diff --git a/magma/Cargo.toml b/magma/Cargo.toml index 606a5079..f3a1f2d1 100644 --- a/magma/Cargo.toml +++ b/magma/Cargo.toml @@ -1,20 +1,27 @@ [package] name = "magma" -version = "0.7.0" -description = "Magma (GOST 28147-89 and GOST R 34.12-2015) block cipher" +version = "0.8.0" # Also update html_root_url in lib.rs when bumping this +description = "Magma (GOST R 34.12-2015) block cipher" authors = ["RustCrypto Developers"] license = "MIT OR Apache-2.0" +edition = "2021" +rust-version = "1.56" readme = "README.md" -edition = "2018" documentation = "https://docs.rs/magma" repository = "https://github.com/RustCrypto/block-ciphers" keywords = ["crypto", "magma", "gost", "block-cipher"] categories = ["cryptography", "no-std"] [dependencies] -cipher = "0.3" -opaque-debug = "0.3" +cipher = "0.4" [dev-dependencies] -cipher = { version = "0.3", features = ["dev"] } -hex-literal = "0.2" +cipher = { version = "0.4", features = ["dev"] } +hex-literal = "0.3" + +[features] +zeroize = ["cipher/zeroize"] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] diff --git a/magma/README.md b/magma/README.md index 8acea193..f6d07632 100644 --- a/magma/README.md +++ b/magma/README.md @@ -26,7 +26,7 @@ USE AT YOUR OWN RISK! ## Minimum Supported Rust Version -Rust **1.41** or higher. +Rust **1.56** or higher. Minimum supported Rust version can be changed in the future, but it will be done with a minor version bump. @@ -58,7 +58,7 @@ dual licensed as above, without any additional terms or conditions. [docs-image]: https://docs.rs/magma/badge.svg [docs-link]: https://docs.rs/magma/ [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg -[rustc-image]: https://img.shields.io/badge/rustc-1.41+-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.56+-blue.svg [hazmat-image]: https://img.shields.io/badge/crypto-hazmat%E2%9A%A0-red.svg [hazmat-link]: https://github.com/RustCrypto/meta/blob/master/HAZMAT.md [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg diff --git a/magma/benches/lib.rs b/magma/benches/lib.rs deleted file mode 100644 index 03005d9f..00000000 --- a/magma/benches/lib.rs +++ /dev/null @@ -1,3 +0,0 @@ -#![feature(test)] - -cipher::block_cipher_bench!(magma::Magma, 32); diff --git a/magma/benches/mod.rs b/magma/benches/mod.rs new file mode 100644 index 00000000..2a7976ca --- /dev/null +++ b/magma/benches/mod.rs @@ -0,0 +1,8 @@ +#![feature(test)] +extern crate test; + +use cipher::{block_decryptor_bench, block_encryptor_bench}; +use magma::Magma; + +block_encryptor_bench!(Key: Magma, magma_encrypt_block, magma_encrypt_blocks); +block_decryptor_bench!(Key: Magma, magma_decrypt_block, magma_decrypt_blocks); diff --git a/magma/src/lib.rs b/magma/src/lib.rs index f10ce379..af6af333 100644 --- a/magma/src/lib.rs +++ b/magma/src/lib.rs @@ -1,21 +1,24 @@ -//! Implementation of the [block cipher][1] defined in GOST 28147-89 -//! and GOST R 34.12-2015. +//! Pure Rust implementation of the [Magma] block cipher defined in GOST 28147-89 +//! and [GOST R 34.12-2015]. //! //! # Examples //! ``` -//! use magma::{Magma, BlockCipher, BlockEncrypt, BlockDecrypt, NewBlockCipher}; -//! use magma::cipher::generic_array::GenericArray; +//! use magma::Magma; +//! use magma::cipher::{ +//! generic_array::GenericArray, +//! BlockEncrypt, BlockDecrypt, KeyInit, +//! }; //! use hex_literal::hex; //! //! // Example vector from GOST 34.12-2018 -//! let key = hex!(" -//! FFEEDDCCBBAA99887766554433221100 -//! F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF -//! "); +//! let key = hex!( +//! "FFEEDDCCBBAA99887766554433221100" +//! "F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF" +//! ); //! let plaintext = hex!("FEDCBA9876543210"); //! let ciphertext = hex!("4EE901E5C2D8CA3D"); //! -//! let cipher = Magma::new(GenericArray::from_slice(&key)); +//! let cipher = Magma::new(&key.into()); //! //! let mut block = GenericArray::clone_from_slice(&plaintext); //! cipher.encrypt_block(&mut block); @@ -25,89 +28,122 @@ //! assert_eq!(&plaintext, block.as_slice()); //! ``` //! -//! [1]: https://en.wikipedia.org/wiki/GOST_(block_cipher) +//! [Magma]: https://en.wikipedia.org/wiki/GOST_(block_cipher) +//! [GOST R 34.12-2015]: https://tc26.ru/standard/gost/GOST_R_3412-2015.pdf #![no_std] #![doc( - html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg", - html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg" + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg", + html_root_url = "https://docs.rs/magma/0.8.0" )] #![deny(unsafe_code)] -#![warn(rust_2018_idioms)] +#![cfg_attr(docsrs, feature(doc_cfg))] +#![warn(missing_docs, rust_2018_idioms)] -pub use cipher::{self, BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher}; +pub use cipher; use cipher::{ - consts::{U1, U32, U8}, - generic_array::GenericArray, + consts::{U32, U8}, + AlgorithmName, BlockCipher, Key, KeyInit, KeySizeUser, }; -use core::{convert::TryInto, marker::PhantomData}; +use core::{fmt, marker::PhantomData}; + +#[cfg(feature = "zeroize")] +use cipher::zeroize::{Zeroize, ZeroizeOnDrop}; mod sboxes; pub use sboxes::Sbox; /// Block cipher defined in GOST 28147-89 generic over S-box -#[derive(Clone, Copy)] +#[derive(Clone)] pub struct Gost89 { key: [u32; 8], _p: PhantomData, } -impl NewBlockCipher for Gost89 { +impl BlockCipher for Gost89 {} + +impl KeySizeUser for Gost89 { type KeySize = U32; +} - fn new(key: &GenericArray) -> Self { +impl KeyInit for Gost89 { + fn new(key: &Key) -> Self { let mut key_u32 = [0u32; 8]; key.chunks_exact(4) .zip(key_u32.iter_mut()) .for_each(|(chunk, v)| *v = to_u32(chunk)); Self { key: key_u32, - _p: Default::default(), + _p: PhantomData, } } } -impl BlockCipher for Gost89 { - type BlockSize = U8; - type ParBlocks = U1; +impl fmt::Debug for Gost89 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Gost89<")?; + f.write_str(S::NAME)?; + f.write_str("> { ... }") + } +} + +impl AlgorithmName for Gost89 { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Gost89<")?; + f.write_str(S::NAME)?; + f.write_str("> { ... }") + } +} + +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl Drop for Gost89 { + fn drop(&mut self) { + self.key.zeroize(); + } } -impl BlockEncrypt for Gost89 { - #[inline] - fn encrypt_block(&self, block: &mut GenericArray) { - let mut v = (to_u32(&block[0..4]), to_u32(&block[4..8])); +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl ZeroizeOnDrop for Gost89 {} + +cipher::impl_simple_block_encdec!( + Gost89, U8, cipher, block, + encrypt: { + let b = block.get_in(); + let mut v = (to_u32(&b[0..4]), to_u32(&b[4..8])); for _ in 0..3 { for i in 0..8 { - v = (v.1, v.0 ^ S::g(v.1, self.key[i])); + v = (v.1, v.0 ^ S::g(v.1, cipher.key[i])); } } for i in (0..8).rev() { - v = (v.1, v.0 ^ S::g(v.1, self.key[i])); + v = (v.1, v.0 ^ S::g(v.1, cipher.key[i])); } + let block = block.get_out(); block[0..4].copy_from_slice(&v.1.to_be_bytes()); block[4..8].copy_from_slice(&v.0.to_be_bytes()); } -} - -impl BlockDecrypt for Gost89 { - #[inline] - fn decrypt_block(&self, block: &mut GenericArray) { - let mut v = (to_u32(&block[0..4]), to_u32(&block[4..8])); + decrypt: { + let b = block.get_in(); + let mut v = (to_u32(&b[0..4]), to_u32(&b[4..8])); for i in 0..8 { - v = (v.1, v.0 ^ S::g(v.1, self.key[i])); + v = (v.1, v.0 ^ S::g(v.1, cipher.key[i])); } for _ in 0..3 { for i in (0..8).rev() { - v = (v.1, v.0 ^ S::g(v.1, self.key[i])); + v = (v.1, v.0 ^ S::g(v.1, cipher.key[i])); } } + let block = block.get_out(); block[0..4].copy_from_slice(&v.1.to_be_bytes()); block[4..8].copy_from_slice(&v.0.to_be_bytes()); } -} +); /// Block cipher defined in GOST R 34.12-2015 (Magma) pub type Magma = Gost89; @@ -122,6 +158,7 @@ pub type Gost89CryptoProC = Gost89; /// Block cipher defined in GOST 28147-89 with CryptoPro S-box version D pub type Gost89CryptoProD = Gost89; +#[inline(always)] fn to_u32(chunk: &[u8]) -> u32 { u32::from_be_bytes(chunk.try_into().unwrap()) } diff --git a/magma/src/sboxes.rs b/magma/src/sboxes.rs index 526e204e..380e2483 100644 --- a/magma/src/sboxes.rs +++ b/magma/src/sboxes.rs @@ -3,7 +3,7 @@ type ExpSbox = [[u8; 256]; 4]; type SmallSbox = [[u8; 16]; 8]; -/// Trait implemented for the GOST 28147-89 cipher S-boxes +/// Trait implemented for the GOST 28147-89 cipher S-boxes. pub trait Sbox { /// Expanded S-box const EXP_SBOX: ExpSbox; @@ -11,6 +11,10 @@ pub trait Sbox { /// Unexpanded S-box const SBOX: SmallSbox; + /// S-Box name + const NAME: &'static str; + + /// Generate expanded version of S-box. #[allow(clippy::needless_range_loop)] fn gen_exp_sbox() -> ExpSbox { let mut out = [[0u8; 256]; 4]; @@ -26,6 +30,7 @@ pub trait Sbox { out } + /// Apply S-box and return result. fn apply_sbox(a: u32) -> u32 { let mut v = 0; for i in 0..4 { @@ -36,15 +41,17 @@ pub trait Sbox { v } + /// Function `g` based on the S-box. fn g(a: u32, k: u32) -> u32 { Self::apply_sbox(a.wrapping_add(k)).rotate_left(11) } } -#[derive(Clone, Copy)] +#[derive(Clone)] pub enum Tc26 {} impl Sbox for Tc26 { + const NAME: &'static str = "Tc26"; const EXP_SBOX: ExpSbox = [ [ 108, 100, 102, 98, 106, 101, 107, 105, 110, 104, 109, 103, 96, 99, 111, 97, 140, 132, @@ -124,10 +131,11 @@ impl Sbox for Tc26 { ]; } -#[derive(Clone, Copy)] +#[derive(Clone)] pub enum TestSbox {} impl Sbox for TestSbox { + const NAME: &'static str = "TestSbox"; const EXP_SBOX: ExpSbox = [ [ 228, 234, 233, 226, 237, 232, 224, 238, 230, 235, 225, 236, 231, 239, 229, 227, 180, @@ -207,10 +215,11 @@ impl Sbox for TestSbox { ]; } -#[derive(Clone, Copy)] +#[derive(Clone)] pub enum CryptoProA {} impl Sbox for CryptoProA { + const NAME: &'static str = "CryptoProA"; const EXP_SBOX: ExpSbox = [ [ 57, 54, 51, 50, 56, 59, 49, 55, 58, 52, 62, 63, 60, 48, 61, 53, 121, 118, 115, 114, @@ -290,10 +299,11 @@ impl Sbox for CryptoProA { ]; } -#[derive(Clone, Copy)] +#[derive(Clone)] pub enum CryptoProB {} impl Sbox for CryptoProB { + const NAME: &'static str = "CryptoProB"; const EXP_SBOX: ExpSbox = [ [ 8, 4, 11, 1, 3, 5, 0, 9, 2, 14, 10, 12, 13, 6, 7, 15, 24, 20, 27, 17, 19, 21, 16, 25, @@ -373,10 +383,11 @@ impl Sbox for CryptoProB { ]; } -#[derive(Clone, Copy)] +#[derive(Clone)] pub enum CryptoProC {} impl Sbox for CryptoProC { + const NAME: &'static str = "CryptoProC"; const EXP_SBOX: ExpSbox = [ [ 1, 11, 12, 2, 9, 13, 0, 15, 4, 5, 8, 14, 10, 7, 6, 3, 17, 27, 28, 18, 25, 29, 16, 31, @@ -456,10 +467,11 @@ impl Sbox for CryptoProC { ]; } -#[derive(Clone, Copy)] +#[derive(Clone)] pub enum CryptoProD {} impl Sbox for CryptoProD { + const NAME: &'static str = "CryptoProD"; const EXP_SBOX: ExpSbox = [ [ 90, 84, 85, 86, 88, 81, 83, 87, 93, 92, 94, 80, 89, 82, 91, 95, 250, 244, 245, 246, diff --git a/rc2/CHANGELOG.md b/rc2/CHANGELOG.md index 978c6c7c..5d610cce 100644 --- a/rc2/CHANGELOG.md +++ b/rc2/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 0.8.0 (2022-02-10) +### Changed +- Bump `cipher` dependency to v0.4 ([#284]) + +[#284]: https://github.com/RustCrypto/block-ciphers/pull/284 + ## 0.7.0 (2021-04-29) ### Changed - Bump `cipher` dependency to v0.3 release ([#235]) diff --git a/rc2/Cargo.toml b/rc2/Cargo.toml index 7782ea2b..9eeebeb8 100644 --- a/rc2/Cargo.toml +++ b/rc2/Cargo.toml @@ -1,19 +1,26 @@ [package] name = "rc2" -version = "0.7.0" +version = "0.8.0" # Also update html_root_url in lib.rs when bumping this description = "RC2 block cipher" authors = ["RustCrypto Developers"] license = "MIT OR Apache-2.0" +edition = "2021" +rust-version = "1.56" readme = "README.md" -edition = "2018" documentation = "https://docs.rs/rc2" repository = "https://github.com/RustCrypto/block-ciphers" keywords = ["crypto", "rc2", "block-cipher"] categories = ["cryptography", "no-std"] [dependencies] -cipher = "0.3" -opaque-debug = "0.3" +cipher = "0.4" [dev-dependencies] -cipher = { version = "0.3", features = ["dev"] } +cipher = { version = "0.4", features = ["dev"] } + +[features] +zeroize = ["cipher/zeroize"] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] diff --git a/rc2/README.md b/rc2/README.md index c87e1c2b..89186b28 100644 --- a/rc2/README.md +++ b/rc2/README.md @@ -26,7 +26,7 @@ USE AT YOUR OWN RISK! ## Minimum Supported Rust Version -Rust **1.41** or higher. +Rust **1.56** or higher. Minimum supported Rust version can be changed in the future, but it will be done with a minor version bump. @@ -58,7 +58,7 @@ dual licensed as above, without any additional terms or conditions. [docs-image]: https://docs.rs/rc2/badge.svg [docs-link]: https://docs.rs/rc2/ [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg -[rustc-image]: https://img.shields.io/badge/rustc-1.41+-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.56+-blue.svg [hazmat-image]: https://img.shields.io/badge/crypto-hazmat%E2%9A%A0-red.svg [hazmat-link]: https://github.com/RustCrypto/meta/blob/master/HAZMAT.md [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg diff --git a/rc2/benches/lib.rs b/rc2/benches/lib.rs deleted file mode 100644 index 6ecd07a7..00000000 --- a/rc2/benches/lib.rs +++ /dev/null @@ -1,3 +0,0 @@ -#![feature(test)] - -cipher::block_cipher_bench!(rc2::Rc2, 16); diff --git a/rc2/benches/mod.rs b/rc2/benches/mod.rs new file mode 100644 index 00000000..2510857b --- /dev/null +++ b/rc2/benches/mod.rs @@ -0,0 +1,8 @@ +#![feature(test)] +extern crate test; + +use cipher::{block_decryptor_bench, block_encryptor_bench}; +use rc2::Rc2; + +block_encryptor_bench!(Key: Rc2, rc2_encrypt_block, rc2_encrypt_blocks); +block_decryptor_bench!(Key: Rc2, rc2_decrypt_block, rc2_decrypt_blocks); diff --git a/rc2/src/lib.rs b/rc2/src/lib.rs index cee6d1c7..bbe7aab9 100644 --- a/rc2/src/lib.rs +++ b/rc2/src/lib.rs @@ -1,37 +1,42 @@ -//! An implementation of the [RC2][1] block cipher. +//! Pure Rust implementation of the [RC2] block cipher. //! -//! [1]: https://en.wikipedia.org/wiki/RC2 +//! [RC2]: https://en.wikipedia.org/wiki/RC2 #![no_std] #![doc( - html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg", - html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg" + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg", + html_root_url = "https://docs.rs/rc2/0.8.0" )] -#![forbid(unsafe_code)] -#![warn(rust_2018_idioms)] +#![deny(unsafe_code)] +#![cfg_attr(docsrs, feature(doc_cfg))] +#![warn(missing_docs, rust_2018_idioms)] pub use cipher; use cipher::{ - consts::{U1, U32, U8}, - errors::InvalidLength, - generic_array::GenericArray, - BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher, + consts::{U32, U8}, + AlgorithmName, BlockCipher, InvalidLength, Key, KeyInit, KeySizeUser, }; +use core::fmt; + +#[cfg(feature = "zeroize")] +use cipher::zeroize::{Zeroize, ZeroizeOnDrop}; mod consts; use crate::consts::PI_TABLE; /// A structure that represents the block cipher initialized with a key +#[derive(Clone)] pub struct Rc2 { - exp_key: [u16; 64], + keys: [u16; 64], } impl Rc2 { /// Create a cipher with the specified effective key length pub fn new_with_eff_key_len(key: &[u8], eff_key_len: usize) -> Self { Self { - exp_key: Rc2::expand_key(key, eff_key_len), + keys: Rc2::expand_key(key, eff_key_len), } } @@ -40,7 +45,7 @@ impl Rc2 { let t8: usize = (t1 + 7) >> 3; - let tm: usize = (255 % ((2 as u32).pow((8 + t1 - 8 * t8) as u32))) as usize; + let tm: usize = (255 % ((2u32).pow((8 + t1 - 8 * t8) as u32))) as usize; let mut key_buffer: [u8; 128] = [0; 128]; key_buffer[..key_len].copy_from_slice(&key[..key_len]); @@ -67,28 +72,28 @@ impl Rc2 { fn mix(&self, r: &mut [u16; 4], j: &mut usize) { r[0] = r[0] - .wrapping_add(self.exp_key[*j]) + .wrapping_add(self.keys[*j]) .wrapping_add(r[3] & r[2]) .wrapping_add(!r[3] & r[1]); *j += 1; r[0] = (r[0] << 1) | (r[0] >> 15); r[1] = r[1] - .wrapping_add(self.exp_key[*j]) + .wrapping_add(self.keys[*j]) .wrapping_add(r[0] & r[3]) .wrapping_add(!r[0] & r[2]); *j += 1; r[1] = (r[1] << 2) | (r[1] >> 14); r[2] = r[2] - .wrapping_add(self.exp_key[*j]) + .wrapping_add(self.keys[*j]) .wrapping_add(r[1] & r[0]) .wrapping_add(!r[1] & r[3]); *j += 1; r[2] = (r[2] << 3) | (r[2] >> 13); r[3] = r[3] - .wrapping_add(self.exp_key[*j]) + .wrapping_add(self.keys[*j]) .wrapping_add(r[2] & r[1]) .wrapping_add(!r[2] & r[0]); *j += 1; @@ -96,108 +101,58 @@ impl Rc2 { } fn mash(&self, r: &mut [u16; 4]) { - r[0] = r[0].wrapping_add(self.exp_key[(r[3] & 63) as usize]); - r[1] = r[1].wrapping_add(self.exp_key[(r[0] & 63) as usize]); - r[2] = r[2].wrapping_add(self.exp_key[(r[1] & 63) as usize]); - r[3] = r[3].wrapping_add(self.exp_key[(r[2] & 63) as usize]); + r[0] = r[0].wrapping_add(self.keys[(r[3] & 63) as usize]); + r[1] = r[1].wrapping_add(self.keys[(r[0] & 63) as usize]); + r[2] = r[2].wrapping_add(self.keys[(r[1] & 63) as usize]); + r[3] = r[3].wrapping_add(self.keys[(r[2] & 63) as usize]); } fn reverse_mix(&self, r: &mut [u16; 4], j: &mut usize) { r[3] = (r[3] << 11) | (r[3] >> 5); r[3] = r[3] - .wrapping_sub(self.exp_key[*j]) + .wrapping_sub(self.keys[*j]) .wrapping_sub(r[2] & r[1]) .wrapping_sub(!r[2] & r[0]); *j -= 1; r[2] = (r[2] << 13) | (r[2] >> 3); r[2] = r[2] - .wrapping_sub(self.exp_key[*j]) + .wrapping_sub(self.keys[*j]) .wrapping_sub(r[1] & r[0]) .wrapping_sub(!r[1] & r[3]); *j -= 1; r[1] = (r[1] << 14) | (r[1] >> 2); r[1] = r[1] - .wrapping_sub(self.exp_key[*j]) + .wrapping_sub(self.keys[*j]) .wrapping_sub(r[0] & r[3]) .wrapping_sub(!r[0] & r[2]); *j -= 1; r[0] = (r[0] << 15) | (r[0] >> 1); r[0] = r[0] - .wrapping_sub(self.exp_key[*j]) + .wrapping_sub(self.keys[*j]) .wrapping_sub(r[3] & r[2]) .wrapping_sub(!r[3] & r[1]); *j = j.wrapping_sub(1); } fn reverse_mash(&self, r: &mut [u16; 4]) { - r[3] = r[3].wrapping_sub(self.exp_key[(r[2] & 63) as usize]); - r[2] = r[2].wrapping_sub(self.exp_key[(r[1] & 63) as usize]); - r[1] = r[1].wrapping_sub(self.exp_key[(r[0] & 63) as usize]); - r[0] = r[0].wrapping_sub(self.exp_key[(r[3] & 63) as usize]); - } - - fn encrypt(&self, block: &mut GenericArray) { - let mut r: [u16; 4] = [ - (u16::from(block[1]) << 8) + u16::from(block[0]), - (u16::from(block[3]) << 8) + u16::from(block[2]), - (u16::from(block[5]) << 8) + u16::from(block[4]), - (u16::from(block[7]) << 8) + u16::from(block[6]), - ]; - - let mut j = 0; - - for i in 0..16 { - self.mix(&mut r, &mut j); - if i == 4 || i == 10 { - self.mash(&mut r); - } - } - - block[0] = (r[0] & 0xff) as u8; - block[1] = (r[0] >> 8) as u8; - block[2] = (r[1] & 0xff) as u8; - block[3] = (r[1] >> 8) as u8; - block[4] = (r[2] & 0xff) as u8; - block[5] = (r[2] >> 8) as u8; - block[6] = (r[3] & 0xff) as u8; - block[7] = (r[3] >> 8) as u8; - } - - fn decrypt(&self, block: &mut GenericArray) { - let mut r: [u16; 4] = [ - (u16::from(block[1]) << 8) + u16::from(block[0]), - (u16::from(block[3]) << 8) + u16::from(block[2]), - (u16::from(block[5]) << 8) + u16::from(block[4]), - (u16::from(block[7]) << 8) + u16::from(block[6]), - ]; - - let mut j = 63; - - for i in 0..16 { - self.reverse_mix(&mut r, &mut j); - if i == 4 || i == 10 { - self.reverse_mash(&mut r); - } - } - - block[0] = r[0] as u8; - block[1] = (r[0] >> 8) as u8; - block[2] = r[1] as u8; - block[3] = (r[1] >> 8) as u8; - block[4] = r[2] as u8; - block[5] = (r[2] >> 8) as u8; - block[6] = r[3] as u8; - block[7] = (r[3] >> 8) as u8; + r[3] = r[3].wrapping_sub(self.keys[(r[2] & 63) as usize]); + r[2] = r[2].wrapping_sub(self.keys[(r[1] & 63) as usize]); + r[1] = r[1].wrapping_sub(self.keys[(r[0] & 63) as usize]); + r[0] = r[0].wrapping_sub(self.keys[(r[3] & 63) as usize]); } } -impl NewBlockCipher for Rc2 { +impl BlockCipher for Rc2 {} + +impl KeySizeUser for Rc2 { type KeySize = U32; +} - fn new(key: &GenericArray) -> Self { +impl KeyInit for Rc2 { + fn new(key: &Key) -> Self { Self::new_from_slice(key).unwrap() } @@ -210,21 +165,78 @@ impl NewBlockCipher for Rc2 { } } -impl BlockCipher for Rc2 { - type BlockSize = U8; - type ParBlocks = U1; +impl fmt::Debug for Rc2 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Rc2 { ... }") + } } -impl BlockEncrypt for Rc2 { - fn encrypt_block(&self, block: &mut GenericArray) { - self.encrypt(block); +impl AlgorithmName for Rc2 { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Rc2") } } -impl BlockDecrypt for Rc2 { - fn decrypt_block(&self, block: &mut GenericArray) { - self.decrypt(block); +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl Drop for Rc2 { + fn drop(&mut self) { + self.keys.zeroize(); } } -opaque_debug::implement!(Rc2); +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl ZeroizeOnDrop for Rc2 {} + +cipher::impl_simple_block_encdec!( + Rc2, U8, cipher, block, + encrypt: { + let b = block.get_in(); + let mut b = [ + u16::from_le_bytes(b[0..2].try_into().unwrap()), + u16::from_le_bytes(b[2..4].try_into().unwrap()), + u16::from_le_bytes(b[4..6].try_into().unwrap()), + u16::from_le_bytes(b[6..8].try_into().unwrap()), + ]; + + let mut j = 0; + + for i in 0..16 { + cipher.mix(&mut b, &mut j); + if i == 4 || i == 10 { + cipher.mash(&mut b); + } + } + + let block = block.get_out(); + block[0..2].copy_from_slice(&b[0].to_le_bytes()); + block[2..4].copy_from_slice(&b[1].to_le_bytes()); + block[4..6].copy_from_slice(&b[2].to_le_bytes()); + block[6..8].copy_from_slice(&b[3].to_le_bytes()); + } + decrypt: { + let b = block.get_in(); + let mut b = [ + u16::from_le_bytes(b[0..2].try_into().unwrap()), + u16::from_le_bytes(b[2..4].try_into().unwrap()), + u16::from_le_bytes(b[4..6].try_into().unwrap()), + u16::from_le_bytes(b[6..8].try_into().unwrap()), + ]; + + let mut j = 63; + + for i in 0..16 { + cipher.reverse_mix(&mut b, &mut j); + if i == 4 || i == 10 { + cipher.reverse_mash(&mut b); + } + } + + let block = block.get_out(); + block[0..2].copy_from_slice(&b[0].to_le_bytes()); + block[2..4].copy_from_slice(&b[1].to_le_bytes()); + block[4..6].copy_from_slice(&b[2].to_le_bytes()); + block[6..8].copy_from_slice(&b[3].to_le_bytes()); + } +); diff --git a/rc2/tests/lib.rs b/rc2/tests/mod.rs similarity index 97% rename from rc2/tests/lib.rs rename to rc2/tests/mod.rs index e0371105..626be1c5 100644 --- a/rc2/tests/lib.rs +++ b/rc2/tests/mod.rs @@ -1,5 +1,5 @@ use cipher::generic_array::GenericArray; -use cipher::{BlockDecrypt, BlockEncrypt, NewBlockCipher}; +use cipher::{BlockDecrypt, BlockEncrypt, KeyInit}; struct Test { key: &'static [u8], diff --git a/serpent/CHANGELOG.md b/serpent/CHANGELOG.md index 5ec7e3b4..e7b94f8a 100644 --- a/serpent/CHANGELOG.md +++ b/serpent/CHANGELOG.md @@ -5,9 +5,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 0.5.0 (2022-02-10) +### Changed +- Bump `cipher` dependency to v0.4 ([#284]) + +[#284]: https://github.com/RustCrypto/block-ciphers/pull/284 + ## 0.4.0 (2021-04-29) ### Changed -- Bump `cipher` dependency to v0.3 release ([#235]) +- Bump `cipher` dependency to v0.3 ([#235]) [#235]: https://github.com/RustCrypto/block-ciphers/pull/235 diff --git a/serpent/Cargo.toml b/serpent/Cargo.toml index 7a1717ac..25f3b24f 100644 --- a/serpent/Cargo.toml +++ b/serpent/Cargo.toml @@ -1,11 +1,12 @@ [package] name = "serpent" -version = "0.4.0" +version = "0.5.0" # Also update html_root_url in lib.rs when bumping this description = "Serpent block cipher" authors = ["RustCrypto Developers"] -license = "Apache-2.0 OR MIT" +license = "MIT OR Apache-2.0" +edition = "2021" +rust-version = "1.56" readme = "README.md" -edition = "2018" documentation = "https://docs.rs/serpent" repository = "https://github.com/RustCrypto/block-ciphers" keywords = ["crypto", "serpent", "block-cipher"] @@ -13,8 +14,14 @@ categories = ["cryptography", "no-std"] [dependencies] byteorder = { version = "1", default-features = false } -cipher = "0.3" -opaque-debug = "0.3" +cipher = "0.4" [dev-dependencies] -cipher = { version = "0.3", features = ["dev"] } +cipher = { version = "0.4", features = ["dev"] } + +[features] +zeroize = ["cipher/zeroize"] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] diff --git a/serpent/README.md b/serpent/README.md index a9ec7a2e..1902e143 100644 --- a/serpent/README.md +++ b/serpent/README.md @@ -28,7 +28,7 @@ USE AT YOUR OWN RISK! ## Minimum Supported Rust Version -Rust **1.41** or higher. +Rust **1.56** or higher. Minimum supported Rust version can be changed in the future, but it will be done with a minor version bump. @@ -60,7 +60,7 @@ dual licensed as above, without any additional terms or conditions. [docs-image]: https://docs.rs/serpent/badge.svg [docs-link]: https://docs.rs/serpent/ [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg -[rustc-image]: https://img.shields.io/badge/rustc-1.41+-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.56+-blue.svg [hazmat-image]: https://img.shields.io/badge/crypto-hazmat%E2%9A%A0-red.svg [hazmat-link]: https://github.com/RustCrypto/meta/blob/master/HAZMAT.md [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg diff --git a/serpent/benches/lib.rs b/serpent/benches/lib.rs deleted file mode 100644 index b7c4955e..00000000 --- a/serpent/benches/lib.rs +++ /dev/null @@ -1,3 +0,0 @@ -#![feature(test)] - -cipher::block_cipher_bench!(serpent::Serpent, 16); diff --git a/serpent/benches/mod.rs b/serpent/benches/mod.rs new file mode 100644 index 00000000..5ab10141 --- /dev/null +++ b/serpent/benches/mod.rs @@ -0,0 +1,8 @@ +#![feature(test)] +extern crate test; + +use cipher::{block_decryptor_bench, block_encryptor_bench}; +use serpent::Serpent; + +block_encryptor_bench!(Key: Serpent, serpent_encrypt_block, serpent_encrypt_blocks); +block_decryptor_bench!(Key: Serpent, serpent_decrypt_block, serpent_decrypt_blocks); diff --git a/serpent/src/lib.rs b/serpent/src/lib.rs index 376a5a05..43066ea1 100644 --- a/serpent/src/lib.rs +++ b/serpent/src/lib.rs @@ -1,27 +1,27 @@ -//! An implementation of the [Serpent1][1] block cipher. -//! Inspired by [Serpent reference implementation][2] and [Lars Viklund Rust implementation][3]. -//! [1]: https://www.cl.cam.ac.uk/~rja14/Papers/serpent.pdf -//! [2]: https://www.cl.cam.ac.uk/~fms27/serpent/ -//! [3]: https://github.com/efb9-860a-e752-0dac/serpent +//! Pure Rust implementation of the [Serpent] block cipher. +//! +//! [Serpent]: https://en.wikipedia.org/wiki/Serpent_(cipher) #![no_std] #![doc( - html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg", - html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg" + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg", + html_root_url = "https://docs.rs/serpent/0.5.0" )] -#![forbid(unsafe_code)] +#![deny(unsafe_code)] +#![cfg_attr(docsrs, feature(doc_cfg))] #![warn(missing_docs, rust_2018_idioms)] #![allow(clippy::needless_range_loop)] pub use cipher; +// TODO: remove dependency on byteorder use byteorder::{ByteOrder, LE}; -use cipher::{ - consts::{U1, U16}, - errors::InvalidLength, - generic_array::GenericArray, - BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher, -}; +use cipher::{consts::U16, AlgorithmName, BlockCipher, InvalidLength, KeyInit, KeySizeUser}; +use core::fmt; + +#[cfg(feature = "zeroize")] +use cipher::zeroize::{Zeroize, ZeroizeOnDrop}; mod consts; use consts::{PHI, ROUNDS, S, S_INVERSE}; @@ -31,7 +31,7 @@ type Subkeys = [Key; ROUNDS + 1]; type Block128 = [u8; 16]; type Word = [u8; 16]; -/// Serpent block cipher +/// Serpent block cipher. #[derive(Clone)] pub struct Serpent { k: Subkeys, @@ -173,7 +173,7 @@ fn xor_block(b1: Block128, k: Key) -> Block128 { } fn expand_key(source: &[u8], len_bits: usize, key: &mut [u8; 32]) { - key[..source.len()].copy_from_slice(&source); + key[..source.len()].copy_from_slice(source); if len_bits < 256 { let byte_i = len_bits / 8; let bit_i = len_bits % 8; @@ -233,10 +233,14 @@ impl Serpent { } } -impl NewBlockCipher for Serpent { +impl BlockCipher for Serpent {} + +impl KeySizeUser for Serpent { type KeySize = U16; +} - fn new(key: &GenericArray) -> Self { +impl KeyInit for Serpent { + fn new(key: &cipher::Key) -> Self { Self::new_from_slice(key).unwrap() } @@ -252,40 +256,44 @@ impl NewBlockCipher for Serpent { } } -impl BlockCipher for Serpent { - type BlockSize = U16; - type ParBlocks = U1; +impl fmt::Debug for Serpent { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Serpent { ... }") + } } -impl BlockEncrypt for Serpent { - fn encrypt_block(&self, block: &mut GenericArray) { - let mut b = [0u8; 16]; - - for (i, v) in block.iter().enumerate() { - b[i] = *v; - } +impl AlgorithmName for Serpent { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Serpent") + } +} - for i in 0..ROUNDS { - round_bitslice(i, b, self.k, &mut b); - } - *block = *GenericArray::from_slice(&b); +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl Drop for Serpent { + fn drop(&mut self) { + self.k.zeroize(); } } -impl BlockDecrypt for Serpent { - fn decrypt_block(&self, block: &mut GenericArray) { - let mut b = [0u8; 16]; +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl ZeroizeOnDrop for Serpent {} - for (i, v) in block.iter().enumerate() { - b[i] = *v; +cipher::impl_simple_block_encdec!( + Serpent, U16, cipher, block, + encrypt: { + let mut b = block.clone_in().into(); + for i in 0..ROUNDS { + round_bitslice(i, b, cipher.k, &mut b); } - + *block.get_out() = b.into(); + } + decrypt: { + let mut b = block.clone_in().into(); for i in (0..ROUNDS).rev() { - round_inverse_bitslice(i, b, self.k, &mut b); + round_inverse_bitslice(i, b, cipher.k, &mut b); } - - *block = *GenericArray::from_slice(&b); + *block.get_out() = b.into(); } -} - -opaque_debug::implement!(Serpent); +); diff --git a/serpent/tests/lib.rs b/serpent/tests/mod.rs similarity index 100% rename from serpent/tests/lib.rs rename to serpent/tests/mod.rs diff --git a/sm4/CHANGELOG.md b/sm4/CHANGELOG.md index 236db52a..6974e7dd 100644 --- a/sm4/CHANGELOG.md +++ b/sm4/CHANGELOG.md @@ -5,9 +5,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 0.5.0 (2022-02-10) +### Changed +- Bump `cipher` dependency to v0.4 ([#284]) + +[#284]: https://github.com/RustCrypto/block-ciphers/pull/284 + ## 0.4.0 (2021-04-29) ### Changed -- Bump `cipher` dependency to v0.3 release ([#235]) +- Bump `cipher` dependency to v0.3 ([#235]) [#235]: https://github.com/RustCrypto/block-ciphers/pull/235 diff --git a/sm4/Cargo.toml b/sm4/Cargo.toml index 97d32727..79b3ffb6 100644 --- a/sm4/Cargo.toml +++ b/sm4/Cargo.toml @@ -1,21 +1,27 @@ [package] name = "sm4" -version = "0.4.0" -authors = ["andelf "] -license = "Apache-2.0 OR MIT" +version = "0.5.0" # Also update html_root_url in lib.rs when bumping this description = "SM4 block cipher algorithm" -documentation = "https://docs.rs/sm4" -repository = "https://github.com/RustCrypto/block-ciphers/tree/master/sm4" +authors = ["RustCrypto Developers"] +license = "MIT OR Apache-2.0" +edition = "2021" +rust-version = "1.56" readme = "README.md" -edition = "2018" +documentation = "https://docs.rs/sm4" +repository = "https://github.com/RustCrypto/block-ciphers" keywords = ["crypto", "sm4", "block-cipher"] -categories = ["cryptography"] +categories = ["cryptography", "no-std"] [dependencies] -cipher = "0.3" -byteorder = { version = "1", default-features = false } -opaque-debug = "0.3" +cipher = "0.4" [dev-dependencies] -cipher = { version = "0.3", features = ["dev"] } -hex-literal = "0.2" +cipher = { version = "0.4", features = ["dev"] } +hex-literal = "0.3" + +[features] +zeroize = ["cipher/zeroize"] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] diff --git a/sm4/README.md b/sm4/README.md index fd81f797..10f285ba 100644 --- a/sm4/README.md +++ b/sm4/README.md @@ -26,7 +26,7 @@ USE AT YOUR OWN RISK! ## Minimum Supported Rust Version -Rust **1.41** or higher. +Rust **1.56** or higher. Minimum supported Rust version can be changed in the future, but it will be done with a minor version bump. @@ -58,7 +58,7 @@ dual licensed as above, without any additional terms or conditions. [docs-image]: https://docs.rs/sm4/badge.svg [docs-link]: https://docs.rs/sm4/ [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg -[rustc-image]: https://img.shields.io/badge/rustc-1.41+-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.56+-blue.svg [hazmat-image]: https://img.shields.io/badge/crypto-hazmat%E2%9A%A0-red.svg [hazmat-link]: https://github.com/RustCrypto/meta/blob/master/HAZMAT.md [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg diff --git a/sm4/benches/lib.rs b/sm4/benches/lib.rs deleted file mode 100644 index 255f5880..00000000 --- a/sm4/benches/lib.rs +++ /dev/null @@ -1,3 +0,0 @@ -#![feature(test)] - -cipher::block_cipher_bench!(sm4::Sm4, 16); diff --git a/sm4/benches/mod.rs b/sm4/benches/mod.rs new file mode 100644 index 00000000..413633ed --- /dev/null +++ b/sm4/benches/mod.rs @@ -0,0 +1,8 @@ +#![feature(test)] +extern crate test; + +use cipher::{block_decryptor_bench, block_encryptor_bench}; +use sm4::Sm4; + +block_encryptor_bench!(Key: Sm4, sm4_encrypt_block, sm4_encrypt_blocks); +block_decryptor_bench!(Key: Sm4, sm4_decrypt_block, sm4_decrypt_blocks); diff --git a/sm4/src/consts.rs b/sm4/src/consts.rs new file mode 100644 index 00000000..88227ec1 --- /dev/null +++ b/sm4/src/consts.rs @@ -0,0 +1,27 @@ +pub(crate) const SBOX: [u8; 256] = [ + 0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05, + 0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99, + 0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62, + 0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6, + 0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8, + 0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35, + 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87, + 0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e, + 0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1, + 0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3, + 0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f, + 0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51, + 0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8, + 0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0, + 0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84, + 0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48, +]; + +pub(crate) const FK: [u32; 4] = [0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc]; + +pub(crate) const CK: [u32; 32] = [ + 0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269, 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9, + 0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249, 0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9, + 0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229, 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299, + 0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209, 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279, +]; diff --git a/sm4/src/lib.rs b/sm4/src/lib.rs index 21420d6f..7870a599 100644 --- a/sm4/src/lib.rs +++ b/sm4/src/lib.rs @@ -1,62 +1,36 @@ -//! An implementation of the [SM4][1] block cipher. +//! Pure Rust implementation of the [SM4] block cipher. //! -//! [1]: https://en.wikipedia.org/wiki/SM4_(cipher) +//! [SM4]: https://en.wikipedia.org/wiki/SM4_(cipher) #![no_std] #![doc( - html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg", - html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg" + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg", + html_root_url = "https://docs.rs/sm4/0.5.0" )] -#![forbid(unsafe_code)] -#![warn(rust_2018_idioms)] -#![allow(clippy::unreadable_literal)] +#![deny(unsafe_code)] +#![cfg_attr(docsrs, feature(doc_cfg))] +#![warn(missing_docs, rust_2018_idioms)] pub use cipher; -use byteorder::{ByteOrder, BE}; -use cipher::{ - consts::{U1, U16}, - generic_array::GenericArray, - BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher, -}; - -pub const SBOX: [u8; 256] = [ - 0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05, - 0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99, - 0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62, - 0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6, - 0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8, - 0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35, - 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87, - 0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e, - 0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1, - 0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3, - 0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f, - 0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51, - 0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8, - 0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0, - 0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84, - 0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48, -]; - -pub const FK: [u32; 4] = [0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc]; - -pub const CK: [u32; 32] = [ - 0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269, 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9, - 0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249, 0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9, - 0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229, 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299, - 0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209, 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279, -]; +use cipher::{consts::U16, AlgorithmName, BlockCipher, Key, KeyInit, KeySizeUser}; +use core::fmt; + +#[cfg(feature = "zeroize")] +use cipher::zeroize::{Zeroize, ZeroizeOnDrop}; + +mod consts; +use consts::{CK, FK, SBOX}; #[inline] fn tau(a: u32) -> u32 { - let mut buf = [0u8; 4]; - BE::write_u32(&mut buf, a); + let mut buf = a.to_be_bytes(); buf[0] = SBOX[buf[0] as usize]; buf[1] = SBOX[buf[1] as usize]; buf[2] = SBOX[buf[2] as usize]; buf[3] = SBOX[buf[3] as usize]; - BE::read_u32(&buf) + u32::from_be_bytes(buf) } /// L: linear transformation @@ -80,19 +54,27 @@ fn t_prime(val: u32) -> u32 { el_prime(tau(val)) } -/// SM4 cipher -#[derive(Copy, Clone)] +/// SM4 block cipher. +#[derive(Clone)] pub struct Sm4 { rk: [u32; 32], } -impl NewBlockCipher for Sm4 { +impl BlockCipher for Sm4 {} + +impl KeySizeUser for Sm4 { type KeySize = U16; +} - fn new(key: &GenericArray) -> Self { - let mut mk = [0u32; 4]; +impl KeyInit for Sm4 { + fn new(key: &Key) -> Self { + let mk = [ + u32::from_be_bytes(key[0..4].try_into().unwrap()), + u32::from_be_bytes(key[4..8].try_into().unwrap()), + u32::from_be_bytes(key[8..12].try_into().unwrap()), + u32::from_be_bytes(key[12..16].try_into().unwrap()), + ]; let mut rk = [0u32; 32]; - BE::read_u32_into(key, &mut mk); let mut k = [mk[0] ^ FK[0], mk[1] ^ FK[1], mk[2] ^ FK[2], mk[3] ^ FK[3]]; for i in 0..8 { @@ -111,39 +93,76 @@ impl NewBlockCipher for Sm4 { } } -impl BlockCipher for Sm4 { - type BlockSize = U16; - type ParBlocks = U1; +impl fmt::Debug for Sm4 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Sm4 { ... }") + } +} + +impl AlgorithmName for Sm4 { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Sm4") + } +} + +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl Drop for Sm4 { + fn drop(&mut self) { + self.rk.zeroize(); + } } -impl BlockEncrypt for Sm4 { - fn encrypt_block(&self, block: &mut GenericArray) { - let mut x = [0u32; 4]; - BE::read_u32_into(block, &mut x); - let rk = &self.rk; +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl ZeroizeOnDrop for Sm4 {} + +cipher::impl_simple_block_encdec!( + Sm4, U16, cipher, block, + encrypt: { + let b = block.get_in(); + let mut x = [ + u32::from_be_bytes(b[0..4].try_into().unwrap()), + u32::from_be_bytes(b[4..8].try_into().unwrap()), + u32::from_be_bytes(b[8..12].try_into().unwrap()), + u32::from_be_bytes(b[12..16].try_into().unwrap()), + ]; + + let rk = &cipher.rk; for i in 0..8 { x[0] ^= t(x[1] ^ x[2] ^ x[3] ^ rk[i * 4]); x[1] ^= t(x[2] ^ x[3] ^ x[0] ^ rk[i * 4 + 1]); x[2] ^= t(x[3] ^ x[0] ^ x[1] ^ rk[i * 4 + 2]); x[3] ^= t(x[0] ^ x[1] ^ x[2] ^ rk[i * 4 + 3]); } - x = [x[3], x[2], x[1], x[0]]; - BE::write_u32_into(&x, block); - } -} -impl BlockDecrypt for Sm4 { - fn decrypt_block(&self, block: &mut GenericArray) { - let mut x = [0u32; 4]; - BE::read_u32_into(block, &mut x); - let rk = &self.rk; + let block = block.get_out(); + block[0..4].copy_from_slice(&x[3].to_be_bytes()); + block[4..8].copy_from_slice(&x[2].to_be_bytes()); + block[8..12].copy_from_slice(&x[1].to_be_bytes()); + block[12..16].copy_from_slice(&x[0].to_be_bytes()); + } + decrypt: { + let b = block.get_in(); + let mut x = [ + u32::from_be_bytes(b[0..4].try_into().unwrap()), + u32::from_be_bytes(b[4..8].try_into().unwrap()), + u32::from_be_bytes(b[8..12].try_into().unwrap()), + u32::from_be_bytes(b[12..16].try_into().unwrap()), + ]; + + let rk = &cipher.rk; for i in 0..8 { x[0] ^= t(x[1] ^ x[2] ^ x[3] ^ rk[31 - i * 4]); x[1] ^= t(x[2] ^ x[3] ^ x[0] ^ rk[31 - (i * 4 + 1)]); x[2] ^= t(x[3] ^ x[0] ^ x[1] ^ rk[31 - (i * 4 + 2)]); x[3] ^= t(x[0] ^ x[1] ^ x[2] ^ rk[31 - (i * 4 + 3)]); } - x = [x[3], x[2], x[1], x[0]]; - BE::write_u32_into(&x, block); + + let block = block.get_out(); + block[0..4].copy_from_slice(&x[3].to_be_bytes()); + block[4..8].copy_from_slice(&x[2].to_be_bytes()); + block[8..12].copy_from_slice(&x[1].to_be_bytes()); + block[12..16].copy_from_slice(&x[0].to_be_bytes()); } -} +); diff --git a/sm4/tests/lib.rs b/sm4/tests/mod.rs similarity index 94% rename from sm4/tests/lib.rs rename to sm4/tests/mod.rs index 56212949..c7d55737 100644 --- a/sm4/tests/lib.rs +++ b/sm4/tests/mod.rs @@ -1,6 +1,6 @@ //! Test vectors are from GM/T 0002-2012 -use cipher::{BlockDecrypt, BlockEncrypt, NewBlockCipher}; +use cipher::{BlockDecrypt, BlockEncrypt, KeyInit}; use hex_literal::hex; use sm4::Sm4; diff --git a/threefish/CHANGELOG.md b/threefish/CHANGELOG.md index ecf48dbe..7caf47c1 100644 --- a/threefish/CHANGELOG.md +++ b/threefish/CHANGELOG.md @@ -5,9 +5,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 0.5.0 (2022-02-10) +### Changed +- Bump `cipher` dependency to v0.4 ([#284]) + +[#284]: https://github.com/RustCrypto/block-ciphers/pull/284 + ## 0.4.0 (2021-04-29) ### Changed -- Bump `cipher` dependency to v0.3 release ([#235]) +- Bump `cipher` dependency to v0.3 ([#235]) [#235]: https://github.com/RustCrypto/block-ciphers/pull/235 diff --git a/threefish/Cargo.toml b/threefish/Cargo.toml index baca67f8..57a319dc 100644 --- a/threefish/Cargo.toml +++ b/threefish/Cargo.toml @@ -1,17 +1,27 @@ [package] name = "threefish" -version = "0.4.0" +version = "0.5.0" # Also update html_root_url in lib.rs when bumping this +description = "Threefish block cipher" authors = ["The Rust-Crypto Project Developers"] license = "MIT OR Apache-2.0" -description = "Threefish block cipher" -documentation = "https://docs.rs/threefish" +edition = "2021" +rust-version = "1.56" readme = "README.md" -edition = "2018" +documentation = "https://docs.rs/threefish" repository = "https://github.com/RustCrypto/block-ciphers" -keywords = ["crypto", "threefish", "gost", "block-cipher"] +keywords = ["crypto", "threefish", "block-cipher"] +categories = ["cryptography", "no-std"] [dependencies] -cipher = "0.3" +cipher = "0.4" [dev-dependencies] -cipher = { version = "0.3", features = ["dev"] } +cipher = { version = "0.4", features = ["dev"] } +hex-literal = "0.3" + +[features] +zeroize = ["cipher/zeroize"] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] diff --git a/threefish/README.md b/threefish/README.md index 628a5dd2..8734b486 100644 --- a/threefish/README.md +++ b/threefish/README.md @@ -26,7 +26,7 @@ USE AT YOUR OWN RISK! ## Minimum Supported Rust Version -Rust **1.41** or higher. +Rust **1.56** or higher. Minimum supported Rust version can be changed in the future, but it will be done with a minor version bump. @@ -58,7 +58,7 @@ dual licensed as above, without any additional terms or conditions. [docs-image]: https://docs.rs/threefish/badge.svg [docs-link]: https://docs.rs/threefish/ [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg -[rustc-image]: https://img.shields.io/badge/rustc-1.41+-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.56+-blue.svg [hazmat-image]: https://img.shields.io/badge/crypto-hazmat%E2%9A%A0-red.svg [hazmat-link]: https://github.com/RustCrypto/meta/blob/master/HAZMAT.md [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg diff --git a/threefish/benches/lib.rs b/threefish/benches/lib.rs deleted file mode 100644 index dd4fe267..00000000 --- a/threefish/benches/lib.rs +++ /dev/null @@ -1,42 +0,0 @@ -#![feature(test)] - -extern crate test; - -use cipher::{generic_array::GenericArray, BlockEncrypt, NewBlockCipher}; -use test::Bencher; - -#[bench] -pub fn encrypt_1_256(bh: &mut Bencher) { - let key = Default::default(); - let state = threefish::Threefish256::new(&key); - let input = &[1u8; 32]; - - bh.iter(|| { - state.encrypt_block(&mut GenericArray::clone_from_slice(input)); - }); - bh.bytes = 32u64; -} - -#[bench] -pub fn encrypt_2_512(bh: &mut Bencher) { - let key = Default::default(); - let state = threefish::Threefish512::new(&key); - let input = &[1u8; 64]; - - bh.iter(|| { - state.encrypt_block(&mut GenericArray::clone_from_slice(input)); - }); - bh.bytes = 64u64; -} - -#[bench] -pub fn encrypt_3_1024(bh: &mut Bencher) { - let key = Default::default(); - let state = threefish::Threefish1024::new(&key); - let input = &[1u8; 128]; - - bh.iter(|| { - state.encrypt_block(&mut GenericArray::clone_from_slice(input)); - }); - bh.bytes = 128u64; -} diff --git a/threefish/benches/mod.rs b/threefish/benches/mod.rs new file mode 100644 index 00000000..47cbdb9d --- /dev/null +++ b/threefish/benches/mod.rs @@ -0,0 +1,38 @@ +#![feature(test)] +extern crate test; + +use cipher::{block_decryptor_bench, block_encryptor_bench}; +use threefish::{Threefish1024, Threefish256, Threefish512}; + +block_encryptor_bench!( + Key: Threefish256, + threefish256_encrypt_block, + threefish256_encrypt_blocks, +); +block_decryptor_bench!( + Key: Threefish256, + threefish256_decrypt_block, + threefish256_decrypt_blocks, +); + +block_encryptor_bench!( + Key: Threefish512, + threefish512_encrypt_block, + threefish512_encrypt_blocks, +); +block_decryptor_bench!( + Key: Threefish512, + threefish512_decrypt_block, + threefish512_decrypt_blocks, +); + +block_encryptor_bench!( + Key: Threefish1024, + threefish1024_encrypt_block, + threefish1024_encrypt_blocks, +); +block_decryptor_bench!( + Key: Threefish1024, + threefish1024_decrypt_block, + threefish1024_decrypt_blocks, +); diff --git a/threefish/src/consts.rs b/threefish/src/consts.rs index d1ab2916..2a45f565 100644 --- a/threefish/src/consts.rs +++ b/threefish/src/consts.rs @@ -4,7 +4,7 @@ pub const C240: u64 = 0x1BD11BDAA9FC1A22; // Rotation constants for the different key lengths -pub const R_256: [[u32; 2]; 8] = [ +pub const R256: [[u8; 2]; 8] = [ [14, 16], [52, 57], [23, 40], @@ -15,7 +15,7 @@ pub const R_256: [[u32; 2]; 8] = [ [32, 32], ]; -pub const R_512: [[u32; 4]; 8] = [ +pub const R512: [[u8; 4]; 8] = [ [46, 36, 19, 37], [33, 27, 14, 42], [17, 49, 36, 39], @@ -26,7 +26,7 @@ pub const R_512: [[u32; 4]; 8] = [ [8, 35, 56, 22], ]; -pub const R_1024: [[u32; 8]; 8] = [ +pub const R1024: [[u8; 8]; 8] = [ [24, 13, 8, 47, 8, 17, 22, 37], [38, 19, 10, 55, 49, 18, 23, 52], [33, 4, 51, 13, 34, 41, 59, 17], @@ -38,6 +38,6 @@ pub const R_1024: [[u32; 8]; 8] = [ ]; // Permutation tables for the different key lengths -pub const P_256: [usize; 4] = [0, 3, 2, 1]; -pub const P_512: [usize; 8] = [6, 1, 0, 7, 2, 5, 4, 3]; -pub const P_1024: [usize; 16] = [0, 15, 2, 11, 6, 13, 4, 9, 14, 1, 8, 5, 10, 3, 12, 7]; +pub const P256: [u8; 4] = [0, 3, 2, 1]; +pub const P512: [u8; 8] = [6, 1, 0, 7, 2, 5, 4, 3]; +pub const P1024: [u8; 16] = [0, 15, 2, 11, 6, 13, 4, 9, 14, 1, 8, 5, 10, 3, 12, 7]; diff --git a/threefish/src/lib.rs b/threefish/src/lib.rs index 07dc54f3..770656c1 100644 --- a/threefish/src/lib.rs +++ b/threefish/src/lib.rs @@ -1,31 +1,39 @@ -//! Threefish +//! Pure Rust implementation of the [Threefish] block ciphers. +//! +//! [Threefish]: https://en.wikipedia.org/wiki/Threefish #![no_std] #![doc( - html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg", - html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg" + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg", + html_root_url = "https://docs.rs/threefish/0.5.0" )] -#![forbid(unsafe_code)] -#![warn(rust_2018_idioms)] +#![deny(unsafe_code)] +#![cfg_attr(docsrs, feature(doc_cfg))] +#![warn(missing_docs, rust_2018_idioms)] + +pub use cipher; mod consts; -use crate::consts::{C240, P_1024, P_256, P_512, R_1024, R_256, R_512}; +use crate::consts::{C240, P1024, P256, P512, R1024, R256, R512}; use cipher::{ - consts::{U1, U128, U32, U64}, - generic_array::GenericArray, - BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher, + consts::{U128, U32, U64}, + AlgorithmName, BlockCipher, Key, KeyInit, KeySizeUser, }; -use core::{convert::TryInto, ops::BitXor}; +use core::fmt; + +#[cfg(feature = "zeroize")] +use cipher::zeroize::{Zeroize, ZeroizeOnDrop}; -fn mix(r: u32, x: (u64, u64)) -> (u64, u64) { +fn mix(r: u8, x: (u64, u64)) -> (u64, u64) { let y0 = x.0.wrapping_add(x.1); - let y1 = x.1.rotate_left(r) ^ y0; + let y1 = x.1.rotate_left(r as u32) ^ y0; (y0, y1) } -fn inv_mix(r: u32, y: (u64, u64)) -> (u64, u64) { - let x1 = (y.0 ^ y.1).rotate_right(r); +fn inv_mix(r: u8, y: (u64, u64)) -> (u64, u64) { + let x1 = (y.0 ^ y.1).rotate_right(r as u32); let x0 = y.0.wrapping_sub(x1); (x0, x1) } @@ -33,21 +41,23 @@ fn inv_mix(r: u32, y: (u64, u64)) -> (u64, u64) { macro_rules! impl_threefish( ( $name:ident, $rounds:expr, $n_w:expr, $block_size:ty, - $rot:expr, $perm:expr + $rot:expr, $perm:expr, $doc_name:expr ) => ( - - #[derive(Clone, Copy)] + #[doc=$doc_name] + #[doc="block cipher."] + #[derive(Clone)] pub struct $name { sk: [[u64; $n_w]; $rounds / 4 + 1] } impl $name { + /// Create new block cipher instance with the given key and tweak. pub fn new_with_tweak(key: &[u8; $n_w*8], tweak: &[u8; 16]) -> $name { let mut k = [0u64; $n_w + 1]; for (kv, chunk) in k[..$n_w].iter_mut().zip(key.chunks_exact(8)) { *kv = u64::from_le_bytes(chunk.try_into().unwrap()); } - k[$n_w] = k[..$n_w].iter().fold(C240, BitXor::bitxor); + k[$n_w] = k[..$n_w].iter().fold(C240, core::ops::BitXor::bitxor); let t0 = u64::from_le_bytes(tweak[..8].try_into().unwrap()); let t1 = u64::from_le_bytes(tweak[8..].try_into().unwrap()); @@ -71,25 +81,50 @@ macro_rules! impl_threefish( } } - impl NewBlockCipher for $name { + impl BlockCipher for $name {} + + impl KeySizeUser for $name { type KeySize = $block_size; + } - fn new(key: &GenericArray) -> Self { + impl KeyInit for $name { + fn new(key: &Key) -> Self { let mut tmp_key = [0u8; $n_w*8]; tmp_key.copy_from_slice(key); Self::new_with_tweak(&tmp_key, &Default::default()) } } - impl BlockCipher for $name { - type BlockSize = $block_size; - type ParBlocks = U1; + impl fmt::Debug for $name { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(concat!(stringify!($name), " { ... }")) + } + } + + impl AlgorithmName for $name { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(stringify!($name)) + } } - impl BlockEncrypt for $name { - fn encrypt_block(&self, block: &mut GenericArray) { + #[cfg(feature = "zeroize")] + #[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] + impl Drop for $name { + fn drop(&mut self) { + self.sk.zeroize(); + } + } + + #[cfg(feature = "zeroize")] + #[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] + impl ZeroizeOnDrop for $name {} + + cipher::impl_simple_block_encdec!( + $name, $block_size, cipher, block, + encrypt: { let mut v = [0u64; $n_w]; - for (vv, chunk) in v.iter_mut().zip(block.chunks_exact(8)) { + let b = block.get_in(); + for (vv, chunk) in v.iter_mut().zip(b.chunks_exact(8)) { *vv = u64::from_le_bytes(chunk.try_into().unwrap()); } @@ -99,8 +134,8 @@ macro_rules! impl_threefish( let (v0, v1) = (v_tmp[2 * j], v_tmp[2 * j + 1]); let (e0, e1) = if d % 4 == 0 { - (v0.wrapping_add(self.sk[d / 4][2 * j]), - v1.wrapping_add(self.sk[d / 4][2 * j + 1])) + (v0.wrapping_add(cipher.sk[d / 4][2 * j]), + v1.wrapping_add(cipher.sk[d / 4][2 * j + 1])) } else { (v0, v1) }; @@ -108,44 +143,43 @@ macro_rules! impl_threefish( let (f0, f1) = mix(r, (e0, e1)); let (pi0, pi1) = ($perm[2 * j], $perm[2 * j + 1]); - v[pi0] = f0; - v[pi1] = f1; + v[pi0 as usize] = f0; + v[pi1 as usize] = f1; } } for i in 0..$n_w { - v[i] = v[i].wrapping_add(self.sk[$rounds / 4][i]); + v[i] = v[i].wrapping_add(cipher.sk[$rounds / 4][i]); } + let block = block.get_out(); for (chunk, vv) in block.chunks_exact_mut(8).zip(v.iter()) { chunk.copy_from_slice(&vv.to_le_bytes()); } } - } - - impl BlockDecrypt for $name { - fn decrypt_block(&self, block: &mut GenericArray) { + decrypt: { let mut v = [0u64; $n_w]; - for (vv, chunk) in v.iter_mut().zip(block.chunks_exact(8)) { + let b = block.get_in(); + for (vv, chunk) in v.iter_mut().zip(b.chunks_exact(8)) { *vv = u64::from_le_bytes(chunk.try_into().unwrap()); } for i in 0..$n_w { - v[i] = v[i].wrapping_sub(self.sk[$rounds / 4][i]); + v[i] = v[i].wrapping_sub(cipher.sk[$rounds / 4][i]); } for d in (0..$rounds).rev() { let v_tmp = v.clone(); for j in 0..($n_w / 2) { let (inv_pi0, inv_pi1) = - ($perm[2 * j], $perm[2 * j + 1]); + ($perm[2 * j] as usize, $perm[2 * j + 1] as usize); let (f0, f1) = (v_tmp[inv_pi0], v_tmp[inv_pi1]); let r = $rot[d % 8][j]; let (e0, e1) = inv_mix(r, (f0, f1)); let (v0, v1) = if d % 4 == 0 { - (e0.wrapping_sub(self.sk[d / 4][2 * j]), - e1.wrapping_sub(self.sk[d / 4][2 * j + 1])) + (e0.wrapping_sub(cipher.sk[d / 4][2 * j]), + e1.wrapping_sub(cipher.sk[d / 4][2 * j + 1])) } else { (e0, e1) }; @@ -154,14 +188,15 @@ macro_rules! impl_threefish( } } + let block = block.get_out(); for (chunk, vv) in block.chunks_exact_mut(8).zip(v.iter()) { chunk.copy_from_slice(&vv.to_le_bytes()); } } - } + ); ) ); -impl_threefish!(Threefish256, 72, 4, U32, R_256, P_256); -impl_threefish!(Threefish512, 72, 8, U64, R_512, P_512); -impl_threefish!(Threefish1024, 80, 16, U128, R_1024, P_1024); +impl_threefish!(Threefish256, 72, 4, U32, R256, P256, "Threefish-256"); +impl_threefish!(Threefish512, 72, 8, U64, R512, P512, "Threefish-512"); +impl_threefish!(Threefish1024, 80, 16, U128, R1024, P1024, "Threefish-1024"); diff --git a/threefish/tests/mod.rs b/threefish/tests/mod.rs new file mode 100644 index 00000000..ed30438e --- /dev/null +++ b/threefish/tests/mod.rs @@ -0,0 +1,236 @@ +//! Test vectors from: +//! https://github.com/weidai11/cryptopp/blob/master/TestVectors/threefish.txt +use cipher::{Block, BlockDecrypt, BlockEncrypt, KeyInit}; +use hex_literal::hex; +use threefish::{Threefish1024, Threefish256, Threefish512}; + +struct Vector { + key: &'static [u8], + tweak: Option<&'static [u8]>, + pt: &'static [u8], + ct: &'static [u8], +} + +macro_rules! impl_test { + {$name:ident, $cipher:ty, $tests:expr,} => { + #[test] + fn $name() { + let vectors = $tests; + for &Vector { key, tweak, pt, ct } in vectors.iter() { + let cipher = match tweak { + Some(tweak) => { + let key = key.try_into().unwrap(); + let tweak = tweak.try_into().unwrap(); + <$cipher>::new_with_tweak(key, tweak) + } + None => <$cipher>::new_from_slice(key).unwrap(), + }; + let mut t = Block::<$cipher>::clone_from_slice(pt); + cipher.encrypt_block(&mut t); + assert_eq!(t[..], ct[..]); + cipher.decrypt_block(&mut t); + assert_eq!(t[..], pt[..]); + + let mut t = [t; 64]; + cipher.encrypt_blocks(&mut t); + assert!(t.iter().all(|b| b[..] == ct[..])); + cipher.decrypt_blocks(&mut t); + assert!(t.iter().all(|b| b[..] == pt[..])); + } + } + }; +} + +impl_test! { + test_threefish_256, + Threefish256, + [ + Vector { + key: &[0; 32], + tweak: None, + pt: &[0; 32], + ct: &hex!( + "84DA2A1F8BEAEE94 7066AE3E3103F1AD" + "536DB1F4A1192495 116B9F3CE6133FD8" + ), + }, + Vector { + key: &hex!( + "1011121314151617 18191A1B1C1D1E1F" + "2021222324252627 28292A2B2C2D2E2F" + ), + tweak: Some(&hex!("0001020304050607 08090A0B0C0D0E0F")), + pt: &hex!( + "FFFEFDFCFBFAF9F8 F7F6F5F4F3F2F1F0" + "EFEEEDECEBEAE9E8 E7E6E5E4E3E2E1E0" + ), + ct: &hex!( + "E0D091FF0EEA8FDF C98192E62ED80AD5" + "9D865D08588DF476 657056B5955E97DF" + ), + }, + ], +} + +impl_test! { + test_threefish_512, + Threefish512, + [ + Vector { + key: &[0; 64], + tweak: None, + pt: &[0; 64], + ct: &hex!( + "B1A2BBC6EF6025BC 40EB3822161F36E3" + "75D1BB0AEE3186FB D19E47C5D479947B" + "7BC2F8586E35F0CF F7E7F03084B0B7B1" + "F1AB3961A580A3E9 7EB41EA14A6D7BBE" + ), + }, + Vector { + key: &hex!( + "B1A2BBC6EF6025BC 40EB3822161F36E3" + "75D1BB0AEE3186FB D19E47C5D479947B" + "7BC2F8586E35F0CF F7E7F03084B0B7B1" + "F1AB3961A580A3E9 7EB41EA14A6D7BBE" + ), + tweak: None, + pt: &[0; 64], + ct: &hex!( + "F13CA06760DD9BBE AB87B6C56F3BBBDB" + "E9D08A77978B942A C02D471DC10268F2" + "261C3D4330D6CA34 1F4BD4115DEE16A2" + "1DCDA2A34A0A76FB A976174E4CF1E306" + ), + }, + Vector { + key: &hex!( + "F13CA06760DD9BBE AB87B6C56F3BBBDB" + "E9D08A77978B942A C02D471DC10268F2" + "261C3D4330D6CA34 1F4BD4115DEE16A2" + "1DCDA2A34A0A76FB A976174E4CF1E306" + ), + tweak: None, + pt: &hex!( + "B1A2BBC6EF6025BC 40EB3822161F36E3" + "75D1BB0AEE3186FB D19E47C5D479947B" + "7BC2F8586E35F0CF F7E7F03084B0B7B1" + "F1AB3961A580A3E9 7EB41EA14A6D7BBE" + ), + ct: &hex!( + "1BEC82CBA1357566 B34E1CF1FBF123A1" + "41C8F4089F6E4CE3 209AEA10095AEC93" + "C900D068BDC7F7A2 DD58513C11DEC956" + "B93169B1C4F24CED E31A265DE83E36B4" + ), + }, + Vector { + key: &hex!( + "F13CA06760DD9BBE AB87B6C56F3BBBDB" + "E9D08A77978B942A C02D471DC10268F2" + "261C3D4330D6CA34 1F4BD4115DEE16A2" + "1DCDA2A34A0A76FB A976174E4CF1E306" + ), + tweak: None, + pt: &hex!( + "B1A2BBC6EF6025BC 40EB3822161F36E3" + "75D1BB0AEE3186FB D19E47C5D479947B" + "7BC2F8586E35F0CF F7E7F03084B0B7B1" + "F1AB3961A580A3E9 7EB41EA14A6D7BBF" + ), + ct: &hex!( + "073CB5F8FABFA17D B751477F294EB3DD" + "4ACD92B78397331F CC36A9C3D3055B81" + "D867CBDD56279037 373359CA1832669A" + "F4B87A1F2FDAF8D3 6E2FB7A6D19F5D45" + ), + }, + Vector { + key: &[0; 64], + tweak: None, + pt: &[0; 64], + ct: &hex!( + "B1A2BBC6EF6025BC 40EB3822161F36E3" + "75D1BB0AEE3186FB D19E47C5D479947B" + "7BC2F8586E35F0CF F7E7F03084B0B7B1" + "F1AB3961A580A3E9 7EB41EA14A6D7BBE" + ), + }, + Vector { + key: &hex!( + "1011121314151617 18191A1B1C1D1E1F" + "2021222324252627 28292A2B2C2D2E2F" + "3031323334353637 38393A3B3C3D3E3F" + "4041424344454647 48494A4B4C4D4E4F" + ), + tweak: Some(&hex!("0001020304050607 08090A0B0C0D0E0F")), + pt: &hex!( + "FFFEFDFCFBFAF9F8 F7F6F5F4F3F2F1F0" + "EFEEEDECEBEAE9E8 E7E6E5E4E3E2E1E0" + "DFDEDDDCDBDAD9D8 D7D6D5D4D3D2D1D0" + "CFCECDCCCBCAC9C8 C7C6C5C4C3C2C1C0" + ), + ct: &hex!( + "E304439626D45A2C B401CAD8D636249A" + "6338330EB06D45DD 8B36B90E97254779" + "272A0A8D99463504 784420EA18C9A725" + "AF11DFFEA1016234 8927673D5C1CAF3D" + ), + }, + ], +} + +impl_test! { + test_threefish_1024, + Threefish1024, + [ + Vector { + key: &[0; 128], + tweak: None, + pt: &[0; 128], + ct: &hex!( + "F05C3D0A3D05B304 F785DDC7D1E03601" + "5C8AA76E2F217B06 C6E1544C0BC1A90D" + "F0ACCB9473C24E0F D54FEA68057F4332" + "9CB454761D6DF5CF 7B2E9B3614FBD5A2" + "0B2E4760B4060354 0D82EABC5482C171" + "C832AFBE68406BC3 9500367A592943FA" + "9A5B4A43286CA3C4 CF46104B443143D5" + "60A4B230488311DF 4FEEF7E1DFE8391E" + ), + }, + Vector { + key: &hex!( + "1011121314151617 18191A1B1C1D1E1F" + "2021222324252627 28292A2B2C2D2E2F" + "3031323334353637 38393A3B3C3D3E3F" + "4041424344454647 48494A4B4C4D4E4F" + "5051525354555657 58595A5B5C5D5E5F" + "6061626364656667 68696A6B6C6D6E6F" + "7071727374757677 78797A7B7C7D7E7F" + "8081828384858687 88898A8B8C8D8E8F" + ), + tweak: Some(&hex!("0001020304050607 08090A0B0C0D0E0F")), + pt: &hex!( + "FFFEFDFCFBFAF9F8 F7F6F5F4F3F2F1F0" + "EFEEEDECEBEAE9E8 E7E6E5E4E3E2E1E0" + "DFDEDDDCDBDAD9D8 D7D6D5D4D3D2D1D0" + "CFCECDCCCBCAC9C8 C7C6C5C4C3C2C1C0" + "BFBEBDBCBBBAB9B8 B7B6B5B4B3B2B1B0" + "AFAEADACABAAA9A8 A7A6A5A4A3A2A1A0" + "9F9E9D9C9B9A9998 9796959493929190" + "8F8E8D8C8B8A8988 8786858483828180" + ), + ct: &hex!( + "A6654DDBD73CC3B0 5DD777105AA849BC" + "E49372EAAFFC5568 D254771BAB85531C" + "94F780E7FFAAE430 D5D8AF8C70EEBBE1" + "760F3B42B737A89C B363490D670314BD" + "8AA41EE63C2E1F45 FBD477922F8360B3" + "88D6125EA6C7AF0A D7056D01796E90C8" + "3313F4150A5716B3 0ED5F569288AE974" + "CE2B4347926FCE57 DE44512177DD7CDE" + ), + }, + ], +} diff --git a/twofish/CHANGELOG.md b/twofish/CHANGELOG.md index c9d7a1ca..07649d7b 100644 --- a/twofish/CHANGELOG.md +++ b/twofish/CHANGELOG.md @@ -5,9 +5,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 0.7.0 (2022-02-10) +### Changed +- Bump `cipher` dependency to v0.4 ([#284]) + +[#284]: https://github.com/RustCrypto/block-ciphers/pull/284 + ## 0.6.0 (2021-04-29) ### Changed -- Bump `cipher` dependency to v0.3 release ([#235]) +- Bump `cipher` dependency to v0.3 ([#235]) [#235]: https://github.com/RustCrypto/block-ciphers/pull/235 diff --git a/twofish/Cargo.toml b/twofish/Cargo.toml index 0c9bb85d..1406f80b 100644 --- a/twofish/Cargo.toml +++ b/twofish/Cargo.toml @@ -1,21 +1,27 @@ [package] name = "twofish" -version = "0.6.0" +version = "0.7.0" # Also update html_root_url in lib.rs when bumping this description = "Twofish block cipher" authors = ["RustCrypto Developers"] license = "MIT OR Apache-2.0" +edition = "2021" +rust-version = "1.56" readme = "README.md" -edition = "2018" documentation = "https://docs.rs/twofish" repository = "https://github.com/RustCrypto/block-ciphers" keywords = ["crypto", "twofish", "block-cipher"] categories = ["cryptography", "no-std"] [dependencies] -byteorder = { version = "1", default-features = false } -cipher = "0.3" -opaque-debug = "0.3" +cipher = "0.4" [dev-dependencies] -cipher = { version = "0.3", features = ["dev"] } -hex-literal = "0.2" +cipher = { version = "0.4", features = ["dev"] } +hex-literal = "0.3" + +[features] +zeroize = ["cipher/zeroize"] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] diff --git a/twofish/README.md b/twofish/README.md index 0a331e5b..73c29af4 100644 --- a/twofish/README.md +++ b/twofish/README.md @@ -26,7 +26,7 @@ USE AT YOUR OWN RISK! ## Minimum Supported Rust Version -Rust **1.41** or higher. +Rust **1.56** or higher. Minimum supported Rust version can be changed in the future, but it will be done with a minor version bump. @@ -58,7 +58,7 @@ dual licensed as above, without any additional terms or conditions. [docs-image]: https://docs.rs/twofish/badge.svg [docs-link]: https://docs.rs/twofish/ [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg -[rustc-image]: https://img.shields.io/badge/rustc-1.41+-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.56+-blue.svg [hazmat-image]: https://img.shields.io/badge/crypto-hazmat%E2%9A%A0-red.svg [hazmat-link]: https://github.com/RustCrypto/meta/blob/master/HAZMAT.md [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg diff --git a/twofish/benches/lib.rs b/twofish/benches/lib.rs deleted file mode 100644 index 0874baa3..00000000 --- a/twofish/benches/lib.rs +++ /dev/null @@ -1,3 +0,0 @@ -#![feature(test)] - -cipher::block_cipher_bench!(twofish::Twofish, 16); diff --git a/twofish/benches/mod.rs b/twofish/benches/mod.rs new file mode 100644 index 00000000..b780788d --- /dev/null +++ b/twofish/benches/mod.rs @@ -0,0 +1,8 @@ +#![feature(test)] +extern crate test; + +use cipher::{block_decryptor_bench, block_encryptor_bench}; +use twofish::Twofish; + +block_encryptor_bench!(Key: Twofish, twofish_encrypt_block, twofish_encrypt_blocks); +block_decryptor_bench!(Key: Twofish, twofish_decrypt_block, twofish_decrypt_blocks); diff --git a/twofish/src/lib.rs b/twofish/src/lib.rs index e99f279c..ae2324ca 100644 --- a/twofish/src/lib.rs +++ b/twofish/src/lib.rs @@ -1,29 +1,32 @@ -//! Twofish block cipher +//! Pure Rust implementation of the [Twofish] block cipher. +//! +//! [Twofish]: https://en.wikipedia.org/wiki/Twofish #![no_std] #![doc( - html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg", - html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg" + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg", + html_root_url = "https://docs.rs/twofish/0.7.0" )] -#![forbid(unsafe_code)] +#![deny(unsafe_code)] +#![cfg_attr(docsrs, feature(doc_cfg))] #![warn(missing_docs, rust_2018_idioms)] #![allow(clippy::needless_range_loop, clippy::unreadable_literal)] pub use cipher; -use byteorder::{ByteOrder, LE}; use cipher::{ - consts::{U1, U16, U32}, - errors::InvalidLength, - generic_array::GenericArray, - BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher, + consts::{U16, U32}, + AlgorithmName, BlockCipher, InvalidLength, Key, KeyInit, KeySizeUser, }; +use core::fmt; + +#[cfg(feature = "zeroize")] +use cipher::zeroize::{Zeroize, ZeroizeOnDrop}; mod consts; use crate::consts::{MDS_POLY, QBOX, QORD, RS, RS_POLY}; -type Block = GenericArray; - /// Twofish block cipher #[derive(Clone)] pub struct Twofish { @@ -71,7 +74,7 @@ fn mds_column_mult(x: u8, column: usize) -> u32 { 3 => [x5b, x, xef, x5b], _ => unreachable!(), }; - LE::read_u32(&v) + u32::from_le_bytes(v) } fn mds_mult(y: [u8; 4]) -> u32 { @@ -93,8 +96,7 @@ fn rs_mult(m: &[u8], out: &mut [u8]) { #[allow(clippy::many_single_char_names)] fn h(x: u32, m: &[u8], k: usize, offset: usize) -> u32 { - let mut y = [0u8; 4]; - LE::write_u32(&mut y, x); + let mut y = x.to_le_bytes(); if k == 4 { y[0] = sbox(1, y[0]) ^ m[4 * (6 + offset)]; @@ -162,13 +164,19 @@ impl Twofish { } } -impl NewBlockCipher for Twofish { +impl BlockCipher for Twofish {} + +impl KeySizeUser for Twofish { type KeySize = U32; +} - fn new(key: &GenericArray) -> Self { +impl KeyInit for Twofish { + #[inline] + fn new(key: &Key) -> Self { Self::new_from_slice(key).unwrap() } + #[inline] fn new_from_slice(key: &[u8]) -> Result { let n = key.len(); if n != 16 && n != 24 && n != 32 { @@ -184,79 +192,112 @@ impl NewBlockCipher for Twofish { } } -impl BlockCipher for Twofish { - type BlockSize = U16; - type ParBlocks = U1; +impl fmt::Debug for Twofish { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Twofish { ... }") + } +} + +impl AlgorithmName for Twofish { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Twofish") + } +} + +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl Drop for Twofish { + fn drop(&mut self) { + self.s.zeroize(); + self.k.zeroize(); + self.start.zeroize(); + } } -impl BlockEncrypt for Twofish { - fn encrypt_block(&self, block: &mut Block) { - let mut p = [0u32; 4]; - LE::read_u32_into(block, &mut p); +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl ZeroizeOnDrop for Twofish {} + +cipher::impl_simple_block_encdec!( + Twofish, U16, cipher, block, + encrypt: { + let b = block.get_in(); + let mut p = [ + u32::from_le_bytes(b[0..4].try_into().unwrap()), + u32::from_le_bytes(b[4..8].try_into().unwrap()), + u32::from_le_bytes(b[8..12].try_into().unwrap()), + u32::from_le_bytes(b[12..16].try_into().unwrap()), + ]; // Input whitening for i in 0..4 { - p[i] ^= self.k[i]; + p[i] ^= cipher.k[i]; } for r in 0..8 { let k = 4 * r + 8; - let t1 = self.g_func(p[1].rotate_left(8)); - let t0 = self.g_func(p[0]).wrapping_add(t1); - p[2] = (p[2] ^ (t0.wrapping_add(self.k[k]))).rotate_right(1); - let t2 = t1.wrapping_add(t0).wrapping_add(self.k[k + 1]); + let t1 = cipher.g_func(p[1].rotate_left(8)); + let t0 = cipher.g_func(p[0]).wrapping_add(t1); + p[2] = (p[2] ^ (t0.wrapping_add(cipher.k[k]))).rotate_right(1); + let t2 = t1.wrapping_add(t0).wrapping_add(cipher.k[k + 1]); p[3] = p[3].rotate_left(1) ^ t2; - let t1 = self.g_func(p[3].rotate_left(8)); - let t0 = self.g_func(p[2]).wrapping_add(t1); - p[0] = (p[0] ^ (t0.wrapping_add(self.k[k + 2]))).rotate_right(1); - let t2 = t1.wrapping_add(t0).wrapping_add(self.k[k + 3]); + let t1 = cipher.g_func(p[3].rotate_left(8)); + let t0 = cipher.g_func(p[2]).wrapping_add(t1); + p[0] = (p[0] ^ (t0.wrapping_add(cipher.k[k + 2]))).rotate_right(1); + let t2 = t1.wrapping_add(t0).wrapping_add(cipher.k[k + 3]); p[1] = (p[1].rotate_left(1)) ^ t2; } // Undo last swap and output whitening - LE::write_u32(&mut block[0..4], p[2] ^ self.k[4]); - LE::write_u32(&mut block[4..8], p[3] ^ self.k[5]); - LE::write_u32(&mut block[8..12], p[0] ^ self.k[6]); - LE::write_u32(&mut block[12..16], p[1] ^ self.k[7]); + p[2] ^= cipher.k[4]; + p[3] ^= cipher.k[5]; + p[0] ^= cipher.k[6]; + p[1] ^= cipher.k[7]; + + let block = block.get_out(); + block[0..4].copy_from_slice(&p[2].to_le_bytes()); + block[4..8].copy_from_slice(&p[3].to_le_bytes()); + block[8..12].copy_from_slice(&p[0].to_le_bytes()); + block[12..16].copy_from_slice(&p[1].to_le_bytes()); } -} - -impl BlockDecrypt for Twofish { - fn decrypt_block(&self, block: &mut Block) { - let mut c = [0u32; 4]; - - c[0] = LE::read_u32(&block[8..12]) ^ self.k[6]; - c[1] = LE::read_u32(&block[12..16]) ^ self.k[7]; - c[2] = LE::read_u32(&block[0..4]) ^ self.k[4]; - c[3] = LE::read_u32(&block[4..8]) ^ self.k[5]; + decrypt: { + let b = block.get_in(); + let mut c = [ + u32::from_le_bytes(b[8..12].try_into().unwrap()) ^ cipher.k[6], + u32::from_le_bytes(b[12..16].try_into().unwrap()) ^ cipher.k[7], + u32::from_le_bytes(b[0..4].try_into().unwrap()) ^ cipher.k[4], + u32::from_le_bytes(b[4..8].try_into().unwrap()) ^ cipher.k[5], + ]; for r in (0..8).rev() { let k = 4 * r + 8; - let t1 = self.g_func(c[3].rotate_left(8)); - let t0 = self.g_func(c[2]).wrapping_add(t1); - c[0] = c[0].rotate_left(1) ^ (t0.wrapping_add(self.k[k + 2])); - let t2 = t1.wrapping_add(t0).wrapping_add(self.k[k + 3]); + let t1 = cipher.g_func(c[3].rotate_left(8)); + let t0 = cipher.g_func(c[2]).wrapping_add(t1); + c[0] = c[0].rotate_left(1) ^ (t0.wrapping_add(cipher.k[k + 2])); + let t2 = t1.wrapping_add(t0).wrapping_add(cipher.k[k + 3]); c[1] = (c[1] ^ t2).rotate_right(1); - let t1 = self.g_func(c[1].rotate_left(8)); - let t0 = self.g_func(c[0]).wrapping_add(t1); - c[2] = c[2].rotate_left(1) ^ (t0.wrapping_add(self.k[k])); - let t2 = t1.wrapping_add(t0).wrapping_add(self.k[k + 1]); + let t1 = cipher.g_func(c[1].rotate_left(8)); + let t0 = cipher.g_func(c[0]).wrapping_add(t1); + c[2] = c[2].rotate_left(1) ^ (t0.wrapping_add(cipher.k[k])); + let t2 = t1.wrapping_add(t0).wrapping_add(cipher.k[k + 1]); c[3] = (c[3] ^ t2).rotate_right(1); } for i in 0..4 { - c[i] ^= self.k[i]; + c[i] ^= cipher.k[i]; } - LE::write_u32_into(&c[..], block); + let block = block.get_out(); + block[0..4].copy_from_slice(&c[0].to_le_bytes()); + block[4..8].copy_from_slice(&c[1].to_le_bytes()); + block[8..12].copy_from_slice(&c[2].to_le_bytes()); + block[12..16].copy_from_slice(&c[3].to_le_bytes()); } -} - -opaque_debug::implement!(Twofish); +); #[cfg(test)] mod tests; diff --git a/twofish/tests/lib.rs b/twofish/tests/mod.rs similarity index 98% rename from twofish/tests/lib.rs rename to twofish/tests/mod.rs index a0ba036a..35a5dfde 100644 --- a/twofish/tests/lib.rs +++ b/twofish/tests/mod.rs @@ -1,4 +1,4 @@ -use cipher::{generic_array::GenericArray, BlockDecrypt, BlockEncrypt, NewBlockCipher}; +use cipher::{generic_array::GenericArray, BlockDecrypt, BlockEncrypt, KeyInit}; use hex_literal::hex; use twofish::Twofish; From 524e17b3747b7e5944ae74595b950d1cad2bb102 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Thu, 10 Feb 2022 11:42:46 +0300 Subject: [PATCH 2/2] tweak crate docs --- aes/src/lib.rs | 16 ++++++++++++---- blowfish/src/lib.rs | 8 ++++++++ cast5/src/lib.rs | 10 +++++++++- des/src/lib.rs | 8 ++++++++ idea/src/lib.rs | 8 ++++++++ kuznyechik/src/lib.rs | 8 ++++++++ magma/src/lib.rs | 8 ++++++++ rc2/src/lib.rs | 8 ++++++++ serpent/src/lib.rs | 8 ++++++++ sm4/src/lib.rs | 8 ++++++++ threefish/src/lib.rs | 8 ++++++++ twofish/src/lib.rs | 8 ++++++++ 12 files changed, 101 insertions(+), 5 deletions(-) diff --git a/aes/src/lib.rs b/aes/src/lib.rs index d8c9bf86..13896ef9 100644 --- a/aes/src/lib.rs +++ b/aes/src/lib.rs @@ -1,6 +1,14 @@ //! Pure Rust implementation of the [Advanced Encryption Standard][AES] //! (AES, a.k.a. Rijndael). //! +//! # ⚠️ Security Warning: Hazmat! +//! +//! This crate implements only the low-level block cipher function, and is intended +//! for use for implementing higher-level constructions *only*. It is NOT +//! intended for direct use in applications. +//! +//! USE AT YOUR OWN RISK! +//! //! # Supported backends //! This crate provides multiple backends including a portable pure Rust //! backend as well as ones based on CPU intrinsics. @@ -42,7 +50,7 @@ //! Note: runtime detection is not possible on SGX targets. Please use the //! afforementioned `RUSTFLAGS` to leverage AES-NI on these targets. //! -//! # Usage example +//! # Examples //! ``` //! use aes::Aes128; //! use aes::cipher::{ @@ -84,8 +92,8 @@ //! } //! ``` //! -//! For implementations of block cipher modes of operation see -//! [`block-modes`] crate. +//! For implementation of block cipher modes of operation see +//! [`block-modes`] repository. //! //! # Configuration Flags //! @@ -102,7 +110,7 @@ //! [AES]: https://en.wikipedia.org/wiki/Advanced_Encryption_Standard //! [fixslicing]: https://eprint.iacr.org/2020/1123.pdf //! [AES-NI]: https://en.wikipedia.org/wiki/AES_instruction_set -//! [`block-modes`]: https://docs.rs/block-modes +//! [`block-modes`]: https://github.com/RustCrypto/block-modes/ #![no_std] #![doc( diff --git a/blowfish/src/lib.rs b/blowfish/src/lib.rs index 0b0d8d29..e5fa617d 100644 --- a/blowfish/src/lib.rs +++ b/blowfish/src/lib.rs @@ -1,5 +1,13 @@ //! Pure Rust implementation of the [Blowfish] block cipher. //! +//! # ⚠️ Security Warning: Hazmat! +//! +//! This crate implements only the low-level block cipher function, and is intended +//! for use for implementing higher-level constructions *only*. It is NOT +//! intended for direct use in applications. +//! +//! USE AT YOUR OWN RISK! +//! //! [Blowfish]: https://en.wikipedia.org/wiki/Blowfish_(cipher) #![no_std] diff --git a/cast5/src/lib.rs b/cast5/src/lib.rs index 0e0773d4..120add38 100644 --- a/cast5/src/lib.rs +++ b/cast5/src/lib.rs @@ -1,6 +1,14 @@ //! Pure Rust implementation of the [CAST5] block cipher ([RFC 2144]). //! -//! # Usage example +//! # ⚠️ Security Warning: Hazmat! +//! +//! This crate implements only the low-level block cipher function, and is intended +//! for use for implementing higher-level constructions *only*. It is NOT +//! intended for direct use in applications. +//! +//! USE AT YOUR OWN RISK! +//! +//! # Examples //! ``` //! use cast5::cipher::generic_array::GenericArray; //! use cast5::cipher::{Key, Block, BlockEncrypt, BlockDecrypt, KeyInit}; diff --git a/des/src/lib.rs b/des/src/lib.rs index 955a35d9..277050c4 100644 --- a/des/src/lib.rs +++ b/des/src/lib.rs @@ -1,6 +1,14 @@ //! Pure Rust implementation of the [Data Encryption Standard][DES] (DES), //! including [Triple DES] (TDES, 3DES) block ciphers. //! +//! # ⚠️ Security Warning: Hazmat! +//! +//! This crate implements only the low-level block cipher function, and is intended +//! for use for implementing higher-level constructions *only*. It is NOT +//! intended for direct use in applications. +//! +//! USE AT YOUR OWN RISK! +//! //! [DES]: https://en.wikipedia.org/wiki/Data_Encryption_Standard //! [Triple DES]: https://en.wikipedia.org/wiki/Triple_DES diff --git a/idea/src/lib.rs b/idea/src/lib.rs index 5608f4f6..1ddac951 100644 --- a/idea/src/lib.rs +++ b/idea/src/lib.rs @@ -1,5 +1,13 @@ //! Pure Rust implementation of the [IDEA] block cipher. //! +//! # ⚠️ Security Warning: Hazmat! +//! +//! This crate implements only the low-level block cipher function, and is intended +//! for use for implementing higher-level constructions *only*. It is NOT +//! intended for direct use in applications. +//! +//! USE AT YOUR OWN RISK! +//! //! [IDEA]: https://en.wikipedia.org/wiki/International_Data_Encryption_Algorithm #![no_std] diff --git a/kuznyechik/src/lib.rs b/kuznyechik/src/lib.rs index 692c1196..beef63d2 100644 --- a/kuznyechik/src/lib.rs +++ b/kuznyechik/src/lib.rs @@ -1,5 +1,13 @@ //! Pure Rust implementation of the [Kuznyechik] ([GOST R 34.12-2015]) block cipher. //! +//! # ⚠️ Security Warning: Hazmat! +//! +//! This crate implements only the low-level block cipher function, and is intended +//! for use for implementing higher-level constructions *only*. It is NOT +//! intended for direct use in applications. +//! +//! USE AT YOUR OWN RISK! +//! //! # Configuration Flags //! //! You can modify crate using the following configuration flag: diff --git a/magma/src/lib.rs b/magma/src/lib.rs index af6af333..f0fcc36a 100644 --- a/magma/src/lib.rs +++ b/magma/src/lib.rs @@ -1,6 +1,14 @@ //! Pure Rust implementation of the [Magma] block cipher defined in GOST 28147-89 //! and [GOST R 34.12-2015]. //! +//! # ⚠️ Security Warning: Hazmat! +//! +//! This crate implements only the low-level block cipher function, and is intended +//! for use for implementing higher-level constructions *only*. It is NOT +//! intended for direct use in applications. +//! +//! USE AT YOUR OWN RISK! +//! //! # Examples //! ``` //! use magma::Magma; diff --git a/rc2/src/lib.rs b/rc2/src/lib.rs index bbe7aab9..0bf6bfac 100644 --- a/rc2/src/lib.rs +++ b/rc2/src/lib.rs @@ -1,5 +1,13 @@ //! Pure Rust implementation of the [RC2] block cipher. //! +//! # ⚠️ Security Warning: Hazmat! +//! +//! This crate implements only the low-level block cipher function, and is intended +//! for use for implementing higher-level constructions *only*. It is NOT +//! intended for direct use in applications. +//! +//! USE AT YOUR OWN RISK! +//! //! [RC2]: https://en.wikipedia.org/wiki/RC2 #![no_std] diff --git a/serpent/src/lib.rs b/serpent/src/lib.rs index 43066ea1..3faa2945 100644 --- a/serpent/src/lib.rs +++ b/serpent/src/lib.rs @@ -1,5 +1,13 @@ //! Pure Rust implementation of the [Serpent] block cipher. //! +//! # ⚠️ Security Warning: Hazmat! +//! +//! This crate implements only the low-level block cipher function, and is intended +//! for use for implementing higher-level constructions *only*. It is NOT +//! intended for direct use in applications. +//! +//! USE AT YOUR OWN RISK! +//! //! [Serpent]: https://en.wikipedia.org/wiki/Serpent_(cipher) #![no_std] diff --git a/sm4/src/lib.rs b/sm4/src/lib.rs index 7870a599..c2354173 100644 --- a/sm4/src/lib.rs +++ b/sm4/src/lib.rs @@ -1,5 +1,13 @@ //! Pure Rust implementation of the [SM4] block cipher. //! +//! # ⚠️ Security Warning: Hazmat! +//! +//! This crate implements only the low-level block cipher function, and is intended +//! for use for implementing higher-level constructions *only*. It is NOT +//! intended for direct use in applications. +//! +//! USE AT YOUR OWN RISK! +//! //! [SM4]: https://en.wikipedia.org/wiki/SM4_(cipher) #![no_std] diff --git a/threefish/src/lib.rs b/threefish/src/lib.rs index 770656c1..70f72693 100644 --- a/threefish/src/lib.rs +++ b/threefish/src/lib.rs @@ -1,5 +1,13 @@ //! Pure Rust implementation of the [Threefish] block ciphers. //! +//! # ⚠️ Security Warning: Hazmat! +//! +//! This crate implements only the low-level block cipher function, and is intended +//! for use for implementing higher-level constructions *only*. It is NOT +//! intended for direct use in applications. +//! +//! USE AT YOUR OWN RISK! +//! //! [Threefish]: https://en.wikipedia.org/wiki/Threefish #![no_std] diff --git a/twofish/src/lib.rs b/twofish/src/lib.rs index ae2324ca..1525b7f4 100644 --- a/twofish/src/lib.rs +++ b/twofish/src/lib.rs @@ -1,5 +1,13 @@ //! Pure Rust implementation of the [Twofish] block cipher. //! +//! # ⚠️ Security Warning: Hazmat! +//! +//! This crate implements only the low-level block cipher function, and is intended +//! for use for implementing higher-level constructions *only*. It is NOT +//! intended for direct use in applications. +//! +//! USE AT YOUR OWN RISK! +//! //! [Twofish]: https://en.wikipedia.org/wiki/Twofish #![no_std]