diff --git a/Cargo.toml b/Cargo.toml index 63b21b070..6b42b93e0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ version = "0.1.4" # *** Internal Dependencies *** bouncycastle = { path = "./" } bouncycastle-aes = { path = "./crypto/aes" } +bouncycastle-camellia = { path = "./crypto/camellia" } bouncycastle-ascon = { path = "./crypto/ascon" } bouncycastle-base64 = { path = "./crypto/base64" } bouncycastle-chacha20 = { path = "./crypto/chacha20" } @@ -62,6 +63,7 @@ edition.workspace = true [dependencies] bouncycastle-aes.workspace = true +bouncycastle-camellia.workspace = true bouncycastle-ascon.workspace = true bouncycastle-base64.workspace = true bouncycastle-chacha20.workspace = true diff --git a/cli/src/aes_ccm_cmd.rs b/cli/src/aes_ccm_cmd.rs index cc2af0bcc..e3f054431 100644 --- a/cli/src/aes_ccm_cmd.rs +++ b/cli/src/aes_ccm_cmd.rs @@ -63,7 +63,7 @@ use crate::helpers::block_mode_helpers::{CipherDirection, load_key}; /// The one-shots this command uses are on the key's role traits, and the key type carries the /// nonce and tag lengths as const parameters, so a generic `run` over the key length needs a way /// to name the key type for an `(N, T)` it chooses at run time: this generic associated type. -trait CcmKeys { +pub(crate) trait CcmKeys { /// The key type at nonce length `N` and tag length `T`. type Key: FromKeyMaterial + AeadDeclaredEncryptionKey @@ -227,7 +227,7 @@ fn load_aad(aad: &Option, aad_file: &Option) -> Vec { /// be matched into one of the permitted instantiations. The two nested matches are the price of /// that, and they are exhaustive over A.1's sets: 7 nonce lengths x 7 tag lengths. #[allow(clippy::too_many_arguments)] // the three key lengths' inputs, already parsed -fn run, const KEY_LEN: usize>( +pub(crate) fn run, const KEY_LEN: usize>( action: &CipherDirection, key: &KeyMaterial, nonce: &Option, diff --git a/cli/src/aes_kw_cmd.rs b/cli/src/aes_kw_cmd.rs index 56d5ec7b1..fdb2eff30 100644 --- a/cli/src/aes_kw_cmd.rs +++ b/cli/src/aes_kw_cmd.rs @@ -138,9 +138,13 @@ pub(crate) fn aes256_kwp_cmd( } /// Reads all of stdin, wraps or unwraps it under `kek`, and writes the result. `alg` names the -/// algorithm in error messages. -fn run(direction: &CipherDirection, kek: &K, output_hex: bool, alg: &str) -where +/// algorithm in error messages. Shared with the other block ciphers' key-wrap commands. +pub(crate) fn run( + direction: &CipherDirection, + kek: &K, + output_hex: bool, + alg: &str, +) where K: KeyWrappingKey + KeyUnwrappingKey, { let mut input = Vec::new(); diff --git a/cli/src/camellia_cbc_cmd.rs b/cli/src/camellia_cbc_cmd.rs new file mode 100644 index 000000000..e3251faee --- /dev/null +++ b/cli/src/camellia_cbc_cmd.rs @@ -0,0 +1,89 @@ +//! Camellia-CBC encryption and decryption, streaming stdin to stdout. +//! +//! Only the cipher wiring lives here: the IV convention, key loading and stdin framing are all +//! in [`crate::helpers::block_mode_helpers`], shared with the `aes*-cbc` and `aes*-ecb` +//! commands. See that module for the command-line contract. Input is padded with PKCS7, so it +//! may be any length. +//! +//! `camellia128-cbc` / `camellia192-cbc` / `camellia256-cbc` are the same command as `aes*-cbc` +//! over the Camellia permutation (RFC 3713; 16-, 24- or 32-byte key, 16-byte block -- the +//! `id-camellia*-cbc` algorithms of RFC 3713 Sec 3), so every remark there applies unchanged. CBC +//! (NIST SP 800-38A Sec 6.2) provides confidentiality only: neither the ciphertext nor the IV is +//! authenticated. Do not decrypt data you have not authenticated separately. + +use crate::helpers::block_mode_helpers::{ + CipherDirection, decrypt_stream, encrypt_stream, load_iv, load_key_object, start_encryptor, +}; +use bouncycastle::camellia::{BLOCK_LEN, Camellia128Key, Camellia192Key, Camellia256Key}; +use bouncycastle::cipher::modes::CBC; +use bouncycastle::cipher::padding::PKCS7; +use bouncycastle::core::symmetric_key::{SymmetricDecryptionKey, SymmetricEncryptionKey}; + +pub(crate) fn camellia128_cbc_cmd( + action: &CipherDirection, + key: &Option, + key_file: &Option, + iv: &Option, + iv_file: &Option, + output_hex: bool, +) { + run::<_, 16>( + action, + &load_key_object::>, 16>(key, key_file, "Camellia-128"), + load_iv::(iv, iv_file), + output_hex, + ); +} + +pub(crate) fn camellia192_cbc_cmd( + action: &CipherDirection, + key: &Option, + key_file: &Option, + iv: &Option, + iv_file: &Option, + output_hex: bool, +) { + run::<_, 24>( + action, + &load_key_object::>, 24>(key, key_file, "Camellia-192"), + load_iv::(iv, iv_file), + output_hex, + ); +} + +pub(crate) fn camellia256_cbc_cmd( + action: &CipherDirection, + key: &Option, + key_file: &Option, + iv: &Option, + iv_file: &Option, + output_hex: bool, +) { + run::<_, 32>( + action, + &load_key_object::>, 32>(key, key_file, "Camellia-256"), + load_iv::(iv, iv_file), + output_hex, + ); +} + +/// Dispatches to the shared streaming loops under the key's padded CBC mode. +fn run( + action: &CipherDirection, + key: &K, + iv: Option<[u8; BLOCK_LEN]>, + output_hex: bool, +) where + K: SymmetricEncryptionKey + + SymmetricDecryptionKey, +{ + match action { + CipherDirection::Encrypt => { + let (enc, generated_iv) = start_encryptor(iv, |rng| key.create_encryptor(rng)); + encrypt_stream::<_, BLOCK_LEN>(enc, generated_iv.as_ref(), output_hex, None) + } + CipherDirection::Decrypt => { + decrypt_stream::<_, BLOCK_LEN>(iv, |iv| key.create_decryptor(iv), output_hex, None) + } + } +} diff --git a/cli/src/camellia_ccm_cmd.rs b/cli/src/camellia_ccm_cmd.rs new file mode 100644 index 000000000..faf0b60c5 --- /dev/null +++ b/cli/src/camellia_ccm_cmd.rs @@ -0,0 +1,101 @@ +//! Camellia-CCM authenticated encryption and decryption: the `aes*-ccm` commands over the Camellia +//! permutation (RFC 3713; the Camellia-CCM of RFC 5528), with the same contract -- the whole +//! input read first, the nonce supplied rather than generated, `ciphertext || tag` out. See +//! [`crate::aes_ccm_cmd`] for why CCM cannot stream and for the nonce and length rules; this +//! file only names the Camellia key types for that module's runner. + +use crate::aes_ccm_cmd::{CcmKeys, run}; +use crate::helpers::block_mode_helpers::{CipherDirection, load_key}; +use bouncycastle::camellia::{Camellia128Key, Camellia192Key, Camellia256Key}; +use bouncycastle::cipher::modes::CCM; + +struct Aria128; +struct Aria192; +struct Aria256; + +impl CcmKeys<16> for Aria128 { + type Key = Camellia128Key>; +} + +impl CcmKeys<24> for Aria192 { + type Key = Camellia192Key>; +} + +impl CcmKeys<32> for Aria256 { + type Key = Camellia256Key>; +} + +/// Camellia-128 CCM. See the module docs and the subcommand help. +#[allow(clippy::too_many_arguments)] +pub(crate) fn camellia128_ccm_cmd( + action: &CipherDirection, + key: &Option, + key_file: &Option, + nonce: &Option, + nonce_file: &Option, + aad: &Option, + aad_file: &Option, + tag_len: usize, + output_hex: bool, +) { + run::( + action, + &load_key::<16>(key, key_file, "Camellia-128"), + nonce, + nonce_file, + aad, + aad_file, + tag_len, + output_hex, + ); +} + +/// Camellia-192 CCM. See [`camellia128_ccm_cmd`]. +#[allow(clippy::too_many_arguments)] +pub(crate) fn camellia192_ccm_cmd( + action: &CipherDirection, + key: &Option, + key_file: &Option, + nonce: &Option, + nonce_file: &Option, + aad: &Option, + aad_file: &Option, + tag_len: usize, + output_hex: bool, +) { + run::( + action, + &load_key::<24>(key, key_file, "Camellia-192"), + nonce, + nonce_file, + aad, + aad_file, + tag_len, + output_hex, + ); +} + +/// Camellia-256 CCM. See [`camellia128_ccm_cmd`]. +#[allow(clippy::too_many_arguments)] +pub(crate) fn camellia256_ccm_cmd( + action: &CipherDirection, + key: &Option, + key_file: &Option, + nonce: &Option, + nonce_file: &Option, + aad: &Option, + aad_file: &Option, + tag_len: usize, + output_hex: bool, +) { + run::( + action, + &load_key::<32>(key, key_file, "Camellia-256"), + nonce, + nonce_file, + aad, + aad_file, + tag_len, + output_hex, + ); +} diff --git a/cli/src/camellia_cfb8_cmd.rs b/cli/src/camellia_cfb8_cmd.rs new file mode 100644 index 000000000..83de882aa --- /dev/null +++ b/cli/src/camellia_cfb8_cmd.rs @@ -0,0 +1,88 @@ +//! Camellia-CFB8 encryption and decryption, streaming stdin to stdout. +//! +//! Only the cipher wiring lives here: the IV convention, key loading and stdin framing are in +//! [`crate::helpers::stream_mode_helpers`] (and [`crate::helpers::block_mode_helpers`] for the +//! key and IV loaders), shared with the `aes*-cfb8` commands. See those modules for the +//! command-line contract. +//! +//! `camellia128-cfb8` / `camellia192-cfb8` / `camellia256-cfb8` are the same command as `aes*-cfb8` +//! over the Camellia permutation (RFC 3713; 16-, 24- or 32-byte key, 16-byte block), so every +//! remark there applies unchanged. The segment size is one byte (NIST SP 800-38A Sec 6.3 with +//! `s = 8`): a DIFFERENT, NON-INTEROPERABLE mode from the CFB128 of `camellia*-cfb`, costing a full +//! Camellia call per byte, sixteen times the work. Prefer `camellia*-cfb` unless a byte-granular +//! self-synchronising stream is required or the format demands CFB8. +//! +//! # Warning +//! +//! CFB8 provides confidentiality only. It does not detect tampering, and neither the ciphertext nor +//! the IV is authenticated. Do not decrypt data you have not authenticated separately. + +use crate::helpers::block_mode_helpers::{CipherDirection, load_iv, load_key_object}; +use crate::helpers::stream_mode_helpers::run_stream_mode; +use bouncycastle::camellia::{BLOCK_LEN, Camellia128Key, Camellia192Key, Camellia256Key}; +use bouncycastle::cipher::modes::CFB8; +use bouncycastle::core::symmetric_key::{SymmetricDecryptionKey, SymmetricEncryptionKey}; +use bouncycastle::core::traits::{StreamCipherDecryptor, StreamCipherEncryptor}; + +pub(crate) fn camellia128_cfb8_cmd( + action: &CipherDirection, + key: &Option, + key_file: &Option, + iv: &Option, + iv_file: &Option, + output_hex: bool, +) { + run::<_, 16>( + action, + &load_key_object::, 16>(key, key_file, "Camellia-128"), + load_iv::(iv, iv_file), + output_hex, + ); +} + +pub(crate) fn camellia192_cfb8_cmd( + action: &CipherDirection, + key: &Option, + key_file: &Option, + iv: &Option, + iv_file: &Option, + output_hex: bool, +) { + run::<_, 24>( + action, + &load_key_object::, 24>(key, key_file, "Camellia-192"), + load_iv::(iv, iv_file), + output_hex, + ); +} + +pub(crate) fn camellia256_cfb8_cmd( + action: &CipherDirection, + key: &Option, + key_file: &Option, + iv: &Option, + iv_file: &Option, + output_hex: bool, +) { + run::<_, 32>( + action, + &load_key_object::, 32>(key, key_file, "Camellia-256"), + load_iv::(iv, iv_file), + output_hex, + ); +} + +/// Dispatches to the shared streaming loops with `Cfb8` filled in as the mode. +fn run<'k, K, const KEY_LEN: usize>( + action: &CipherDirection, + key: &'k K, + iv: Option<[u8; BLOCK_LEN]>, + output_hex: bool, +) where + K: SymmetricEncryptionKey + + SymmetricDecryptionKey, + K::Encryptor<'k>: StreamCipherEncryptor, + K::Decryptor<'k>: StreamCipherDecryptor, +{ + run_stream_mode::(action, key, iv, output_hex) +} diff --git a/cli/src/camellia_cfb_cmd.rs b/cli/src/camellia_cfb_cmd.rs new file mode 100644 index 000000000..82f2606f2 --- /dev/null +++ b/cli/src/camellia_cfb_cmd.rs @@ -0,0 +1,93 @@ +//! Camellia-CFB128 encryption and decryption, streaming stdin to stdout. +//! +//! Only the cipher wiring lives here: the IV convention, key loading and stdin framing are in +//! [`crate::helpers::stream_mode_helpers`] (and [`crate::helpers::block_mode_helpers`] for the +//! key and IV loaders), shared with the `aes*-cfb` commands. See those modules for the +//! command-line contract. +//! +//! `camellia128-cfb` / `camellia192-cfb` / `camellia256-cfb` are the same command as `aes*-cfb` +//! over the Camellia permutation (RFC 3713; 16-, 24- or 32-byte key, 16-byte block), so every +//! remark there applies unchanged. The segment size is the full block, i.e. **CFB128** +//! (NIST SP 800-38A Sec 6.3 with `s = b`); the `s = 8` variant is a different, non-interoperable +//! mode and has its own commands, `camellia*-cfb8`. +//! +//! CFB is a stream cipher, so these commands accept input of any length and pad nothing; the +//! ciphertext is exactly as long as the plaintext. +//! +//! # Warning +//! +//! CFB provides confidentiality only. It does not detect tampering, and neither the ciphertext nor +//! the IV is authenticated. Flipping a ciphertext bit flips the *same* bit of the plaintext in the +//! *same* block (SP 800-38A Appendix D, Table D.2), at the cost of randomising the next one, so an +//! attacker edits the block they aimed at. Do not decrypt data you have not authenticated +//! separately. + +use crate::helpers::block_mode_helpers::{CipherDirection, load_iv, load_key_object}; +use crate::helpers::stream_mode_helpers::run_stream_mode; +use bouncycastle::camellia::{BLOCK_LEN, Camellia128Key, Camellia192Key, Camellia256Key}; +use bouncycastle::cipher::modes::CFB; +use bouncycastle::core::symmetric_key::{SymmetricDecryptionKey, SymmetricEncryptionKey}; +use bouncycastle::core::traits::{StreamCipherDecryptor, StreamCipherEncryptor}; + +pub(crate) fn camellia128_cfb_cmd( + action: &CipherDirection, + key: &Option, + key_file: &Option, + iv: &Option, + iv_file: &Option, + output_hex: bool, +) { + run::<_, 16>( + action, + &load_key_object::, 16>(key, key_file, "Camellia-128"), + load_iv::(iv, iv_file), + output_hex, + ); +} + +pub(crate) fn camellia192_cfb_cmd( + action: &CipherDirection, + key: &Option, + key_file: &Option, + iv: &Option, + iv_file: &Option, + output_hex: bool, +) { + run::<_, 24>( + action, + &load_key_object::, 24>(key, key_file, "Camellia-192"), + load_iv::(iv, iv_file), + output_hex, + ); +} + +pub(crate) fn camellia256_cfb_cmd( + action: &CipherDirection, + key: &Option, + key_file: &Option, + iv: &Option, + iv_file: &Option, + output_hex: bool, +) { + run::<_, 32>( + action, + &load_key_object::, 32>(key, key_file, "Camellia-256"), + load_iv::(iv, iv_file), + output_hex, + ); +} + +/// Dispatches to the shared streaming loops with `Cfb` filled in as the mode. +fn run<'k, K, const KEY_LEN: usize>( + action: &CipherDirection, + key: &'k K, + iv: Option<[u8; BLOCK_LEN]>, + output_hex: bool, +) where + K: SymmetricEncryptionKey + + SymmetricDecryptionKey, + K::Encryptor<'k>: StreamCipherEncryptor, + K::Decryptor<'k>: StreamCipherDecryptor, +{ + run_stream_mode::(action, key, iv, output_hex) +} diff --git a/cli/src/camellia_ctr_cmd.rs b/cli/src/camellia_ctr_cmd.rs new file mode 100644 index 000000000..632c155c2 --- /dev/null +++ b/cli/src/camellia_ctr_cmd.rs @@ -0,0 +1,97 @@ +//! Camellia-CTR encryption and decryption, streaming stdin to stdout. +//! +//! Only the cipher wiring lives here: the nonce convention, key loading and stdin framing are in +//! [`crate::helpers::stream_mode_helpers`] (and [`crate::helpers::block_mode_helpers`] for the +//! key and nonce loaders), shared with the `aes*-ctr` commands. See those modules for the +//! command-line contract. +//! +//! `camellia128-ctr` / `camellia192-ctr` / `camellia256-ctr` are the same command as `aes*-ctr` +//! over the Camellia permutation (RFC 3713; 16-, 24- or 32-byte key, 16-byte block), so every +//! remark there applies unchanged, including the split of the counter block: the nonce is **12 +//! bytes** and the counter the remaining 4, giving 2^32 blocks -- 64 GiB -- in a single message. +//! That is NIST SP 800-38A Appendix B.2's construction, not RFC 5528's, which divides the same +//! block into a 4-octet nonce, an 8-octet IV and a counter starting at one; ciphertexts are not +//! interchangeable with an RFC 5528 implementation. +//! +//! `encrypt` writes that 12-byte nonce as the first bytes of its output and `decrypt` reads it +//! back, exactly as the other modes do with their IVs; note that it is 12 bytes here, not 16. +//! +//! # Warning +//! +//! CTR provides confidentiality only and is the most malleable mode here: flipping any ciphertext +//! bit flips exactly the corresponding plaintext bit and affects nothing else (SP 800-38A +//! Appendix D, Table D.2), so an attacker can edit the plaintext at will with no garbling to give +//! it away. A repeated nonce under one key is fatal rather than merely unwise -- the same keystream +//! twice leaks the XOR of the two messages -- which is why the nonce is drawn from the OS-backed +//! DRBG unless `--iv` / `--iv-file` supplies one, and then its uniqueness under the key is the +//! caller's to keep. Do not decrypt data you have not authenticated separately. + +use crate::helpers::block_mode_helpers::{CipherDirection, load_iv, load_key_object}; +use crate::helpers::stream_mode_helpers::run_stream_mode; +use bouncycastle::camellia::{CTR_NONCE_LEN, Camellia128Key, Camellia192Key, Camellia256Key}; +use bouncycastle::cipher::modes::CTR; +use bouncycastle::core::symmetric_key::{SymmetricDecryptionKey, SymmetricEncryptionKey}; +use bouncycastle::core::traits::{StreamCipherDecryptor, StreamCipherEncryptor}; + +pub(crate) fn camellia128_ctr_cmd( + action: &CipherDirection, + key: &Option, + key_file: &Option, + iv: &Option, + iv_file: &Option, + output_hex: bool, +) { + run::<_, 16>( + action, + &load_key_object::, 16>(key, key_file, "Camellia-128"), + load_iv::(iv, iv_file), + output_hex, + ); +} + +pub(crate) fn camellia192_ctr_cmd( + action: &CipherDirection, + key: &Option, + key_file: &Option, + iv: &Option, + iv_file: &Option, + output_hex: bool, +) { + run::<_, 24>( + action, + &load_key_object::, 24>(key, key_file, "Camellia-192"), + load_iv::(iv, iv_file), + output_hex, + ); +} + +pub(crate) fn camellia256_ctr_cmd( + action: &CipherDirection, + key: &Option, + key_file: &Option, + iv: &Option, + iv_file: &Option, + output_hex: bool, +) { + run::<_, 32>( + action, + &load_key_object::, 32>(key, key_file, "Camellia-256"), + load_iv::(iv, iv_file), + output_hex, + ); +} + +/// Dispatches to the shared streaming loops with `Ctr` filled in as the mode. +fn run<'k, K, const KEY_LEN: usize>( + action: &CipherDirection, + key: &'k K, + iv: Option<[u8; CTR_NONCE_LEN]>, + output_hex: bool, +) where + K: SymmetricEncryptionKey + + SymmetricDecryptionKey, + K::Encryptor<'k>: StreamCipherEncryptor, + K::Decryptor<'k>: StreamCipherDecryptor, +{ + run_stream_mode::(action, key, iv, output_hex) +} diff --git a/cli/src/camellia_gcm_cmd.rs b/cli/src/camellia_gcm_cmd.rs new file mode 100644 index 000000000..3c5a8b709 --- /dev/null +++ b/cli/src/camellia_gcm_cmd.rs @@ -0,0 +1,90 @@ +//! Camellia-GCM authenticated encryption and decryption, streaming stdin to stdout: the `aes*-gcm` +//! commands over the Camellia permutation (RFC 3713; the Camellia-GCM of RFC 6367), with the same +//! `IV || ciphertext || tag` contract, AAD flags and warnings. See `aes_gcm_cmd` and +//! [`crate::helpers::aead_cipher_helpers`] for the command-line contract. + +use crate::helpers::aead_cipher_helpers::{decrypt_aead, encrypt_aead, load_aad}; +use crate::helpers::block_mode_helpers::{CipherDirection, load_iv, load_key_object}; +use bouncycastle::camellia::{Camellia128Key, Camellia192Key, Camellia256Key}; +use bouncycastle::cipher::modes::GCM; +use bouncycastle::core::symmetric_key::{AeadDecryptionKey, AeadEncryptionKey}; + +#[allow(clippy::too_many_arguments)] // one flag per input, each inline or from a file +pub(crate) fn camellia128_gcm_cmd( + action: &CipherDirection, + key: &Option, + key_file: &Option, + iv: &Option, + iv_file: &Option, + aad: &Option, + aad_file: &Option, + output_hex: bool, +) { + run::, 16>( + action, + &load_key_object::<_, 16>(key, key_file, "Camellia-128"), + load_iv::<12>(iv, iv_file), + &load_aad(aad, aad_file), + output_hex, + ); +} + +#[allow(clippy::too_many_arguments)] // one flag per input, each inline or from a file +pub(crate) fn camellia192_gcm_cmd( + action: &CipherDirection, + key: &Option, + key_file: &Option, + iv: &Option, + iv_file: &Option, + aad: &Option, + aad_file: &Option, + output_hex: bool, +) { + run::, 24>( + action, + &load_key_object::<_, 24>(key, key_file, "Camellia-192"), + load_iv::<12>(iv, iv_file), + &load_aad(aad, aad_file), + output_hex, + ); +} + +#[allow(clippy::too_many_arguments)] // one flag per input, each inline or from a file +pub(crate) fn camellia256_gcm_cmd( + action: &CipherDirection, + key: &Option, + key_file: &Option, + iv: &Option, + iv_file: &Option, + aad: &Option, + aad_file: &Option, + output_hex: bool, +) { + run::, 32>( + action, + &load_key_object::<_, 32>(key, key_file, "Camellia-256"), + load_iv::<12>(iv, iv_file), + &load_aad(aad, aad_file), + output_hex, + ); +} + +/// Dispatches to the shared AEAD streaming loops with `Gcm`'s 128-bit tag. +fn run( + action: &CipherDirection, + key: &K, + nonce: Option<[u8; 12]>, + aad: &[u8], + output_hex: bool, +) where + K: AeadEncryptionKey + AeadDecryptionKey, +{ + match action { + CipherDirection::Encrypt => { + encrypt_aead::(key, nonce, aad, output_hex) + } + CipherDirection::Decrypt => { + decrypt_aead::(key, nonce, aad, output_hex) + } + } +} diff --git a/cli/src/camellia_kw_cmd.rs b/cli/src/camellia_kw_cmd.rs new file mode 100644 index 000000000..ab1bad42d --- /dev/null +++ b/cli/src/camellia_kw_cmd.rs @@ -0,0 +1,54 @@ +//! Camellia key wrap: `camellia{128,192,256}-kw -d encrypt|decrypt`, stdin to stdout. +//! +//! They are the `aes*-kw` commands over the Camellia permutation (RFC 3657 Sec 3, the +//! `id-camellia*-wrap` algorithms), so everything in [`crate::aes_kw_cmd`] -- the whole-input +//! reading, the absence of an IV, the input-length rules and the fail-closed unwrap -- applies +//! unchanged; only the key type differs. RFC 3657 specifies no padded form, so there is no +//! `camellia*-kwp`. + +use crate::aes_kw_cmd::run; +use crate::helpers::block_mode_helpers::{CipherDirection, load_key_object}; +use bouncycastle::camellia::{Camellia128Key, Camellia192Key, Camellia256Key}; +use bouncycastle::cipher::modes::KW; + +pub(crate) fn camellia128_kw_cmd( + direction: &CipherDirection, + key: &Option, + key_file: &Option, + output_hex: bool, +) { + run::<_, 16>( + direction, + &load_key_object::, 16>(key, key_file, "Camellia-128-KW"), + output_hex, + "Camellia-128-KW", + ); +} + +pub(crate) fn camellia192_kw_cmd( + direction: &CipherDirection, + key: &Option, + key_file: &Option, + output_hex: bool, +) { + run::<_, 24>( + direction, + &load_key_object::, 24>(key, key_file, "Camellia-192-KW"), + output_hex, + "Camellia-192-KW", + ); +} + +pub(crate) fn camellia256_kw_cmd( + direction: &CipherDirection, + key: &Option, + key_file: &Option, + output_hex: bool, +) { + run::<_, 32>( + direction, + &load_key_object::, 32>(key, key_file, "Camellia-256-KW"), + output_hex, + "Camellia-256-KW", + ); +} diff --git a/cli/src/main.rs b/cli/src/main.rs index ff4c0e98f..4980ca804 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -9,6 +9,13 @@ mod aes_ecb_cmd; mod aes_gcm_cmd; mod aes_kw_cmd; mod ascon_cmd; +mod camellia_cbc_cmd; +mod camellia_ccm_cmd; +mod camellia_cfb8_cmd; +mod camellia_cfb_cmd; +mod camellia_ctr_cmd; +mod camellia_gcm_cmd; +mod camellia_kw_cmd; mod chacha20_cmd; mod chacha20_poly1305_cmd; mod encoders_cmd; @@ -2343,6 +2350,73 @@ enum Subcommands { x: bool, }, + /// Camellia-128 Key Wrap (RFC 3657 `id-camellia128-wrap`; NIST SP 800-38F Sec 6.2 over the + /// Camellia permutation): `-d encrypt` wraps stdin to stdout, `-d decrypt` unwraps it. + /// + /// The same command as `aes128-kw` over Camellia: see it for the input-length rules, the + /// absence of an IV, the authenticated `decrypt` and the non-streaming note. RFC 3657 defines + /// no padded form, so there is no `camellia*-kwp`. + CAMELLIA128_KW { + #[arg(short, long)] + direction: CipherDirection, + + /// The 16-byte Camellia key-encryption key in hex. + /// The `key_file` option is preferred to avoid leaving key material in command history. + #[arg(long)] + key: Option, + + /// A file containing the 16-byte Camellia key-encryption key (raw bytes; hex with --hex-input). + /// If both key and key_file options are provided, the file will be used. + #[arg(short, long)] + key_file: Option, + + #[arg(short)] + /// Output in hex format. + x: bool, + }, + + /// Camellia-192 Key Wrap (RFC 3657 `id-camellia192-wrap`). See `camellia128-kw`; only the key + /// length differs. + CAMELLIA192_KW { + #[arg(short, long)] + direction: CipherDirection, + + /// The 24-byte Camellia key-encryption key in hex. + /// The `key_file` option is preferred to avoid leaving key material in command history. + #[arg(long)] + key: Option, + + /// A file containing the 24-byte Camellia key-encryption key (raw bytes; hex with --hex-input). + /// If both key and key_file options are provided, the file will be used. + #[arg(short, long)] + key_file: Option, + + #[arg(short)] + /// Output in hex format. + x: bool, + }, + + /// Camellia-256 Key Wrap (RFC 3657 `id-camellia256-wrap`). See `camellia128-kw`; only the key + /// length differs. + CAMELLIA256_KW { + #[arg(short, long)] + direction: CipherDirection, + + /// The 32-byte Camellia key-encryption key in hex. + /// The `key_file` option is preferred to avoid leaving key material in command history. + #[arg(long)] + key: Option, + + /// A file containing the 32-byte Camellia key-encryption key (raw bytes; hex with --hex-input). + /// If both key and key_file options are provided, the file will be used. + #[arg(short, long)] + key_file: Option, + + #[arg(short)] + /// Output in hex format. + x: bool, + }, + /// The ML-KEM-512 key encapsulation algorithm. MLKEM512 { action: mlkem_cmd::MLKEMAction, @@ -2539,120 +2613,869 @@ enum Subcommands { /// as its entropy input instead of the operating system, so the same file gives the /// same stream. For reproducible test data only; the output is as secret as the file. #[arg(long)] - seed_file: Option, + seed_file: Option, + + #[arg(short)] + /// Output in hex format. + x: bool, + }, + + /// Perform SHA3-224 of the content provided on stdin. + /// Supports streaming update for low memory footprint. + SHA3_224 { + #[arg(short)] + /// Output the hashes in hex format. + x: bool, + }, + + /// Perform SHA3-256 of the content provided on stdin. + /// Supports streaming update for low memory footprint. + SHA3_256 { + #[arg(short)] + /// Output the hashes in hex format. + x: bool, + }, + + /// Perform SHA3-384 of the content provided on stdin. + /// Supports streaming update for low memory footprint. + SHA3_384 { + #[arg(short)] + /// Output the hashes in hex format. + x: bool, + }, + + /// Perform SHA3-512 of the content provided on stdin. + /// Supports streaming update for low memory footprint. + SHA3_512 { + #[arg(short)] + /// Output the hashes in hex format. + x: bool, + }, + + /// Perform SHA224 of the content provided on stdin. + /// Supports streaming update for low memory footprint. + SHA224 { + #[arg(short)] + /// Output the hashes in hex format. + x: bool, + }, + + /// Perform SHA256 of the content provided on stdin. + /// Supports streaming update for low memory footprint. + SHA256 { + #[arg(short)] + /// Output the hashes in hex format. + x: bool, + }, + + /// Perform SHA384 of the content provided on stdin. + /// Supports streaming update for low memory footprint. + SHA384 { + #[arg(short)] + /// Output the hashes in hex format. + x: bool, + }, + + /// Perform SHA512 of the content provided on stdin. + /// Supports streaming update for low memory footprint. + SHA512 { + #[arg(short)] + /// Output the hashes in hex format. + x: bool, + }, + + /// Perform SHA512/224 of the content provided on stdin. + /// Supports streaming update for low memory footprint. + SHA512_224 { + #[arg(short)] + /// Output the hashes in hex format. + x: bool, + }, + + /// Perform SHA512/256 of the content provided on stdin. + /// Supports streaming update for low memory footprint. + SHA512_256 { + #[arg(short)] + /// Output the hashes in hex format. + x: bool, + }, + + /// Perform SHAKE128 of the content provided on stdin. Requires the output length in bytes. + /// Supports streaming update for low memory footprint. + SHAKE128 { + /// Length of the output in bytes. + length: usize, + + #[arg(short)] + /// Output the hashes in hex format. + x: bool, + }, + + /// Perform SHAKE256 of the content provided on stdin. Requires the output length in bytes. + /// Supports streaming update for low memory footprint. + SHAKE256 { + /// Length of the output in bytes. + length: usize, + + #[arg(short)] + /// Output the hashes in hex format. + x: bool, + }, + + /// Perform SM3 of the content provided on stdin. + /// Supports streaming update for low memory footprint. + SM3 { + #[arg(short)] + /// Output the hashes in hex format. + x: bool, + }, + + /// Camellia-128 in CBC mode (RFC 3713 block cipher; NIST SP 800-38A Sec 6.2 mode) with PKCS7 + /// padding, streaming stdin to stdout. + /// + /// On `encrypt`, a fresh unpredictable IV is generated and written as the FIRST 16 BYTES of + /// the output; on `decrypt` it is read back from the first 16 bytes of the input, so the two + /// compose directly in a pipeline. With `--iv` (hex) or `--iv-file` (raw bytes), the IV is + /// supplied instead: `encrypt` uses it and writes ONLY the ciphertext, and `decrypt` reads + /// ONLY ciphertext from stdin. + /// + /// Input may be any length: it is padded with PKCS7 to a whole number of 16-byte blocks. + /// + /// See `aes128-cbc` for the full IV convention, the padding rule and the warnings; the key + /// and block are both 16 bytes, as for AES-128. + CAMELLIA128_CBC { + #[arg(short, long)] + direction: CipherDirection, + + /// The 16-byte Camellia key in hex. + /// The `key_file` option is preferred to avoid leaving key material in command history. + #[arg(long)] + key: Option, + + /// A file containing the 16-byte Camellia key (raw bytes; hex with --hex-input). + /// If both key and key_file options are provided, the file will be used. + #[arg(short, long)] + key_file: Option, + + /// The 16-byte IV in hex. Supplied instead of generated: `encrypt` then writes no IV and + /// `decrypt` reads none. See the IV paragraph above. + #[arg(long)] + iv: Option, + + /// A file containing the 16-byte IV, (raw bytes; hex with --hex-input). + /// If both iv and iv_file options are provided, the file will be used. + #[arg(long)] + iv_file: Option, + + #[arg(short)] + /// Output in hex format. + x: bool, + }, + /// Camellia-192 in CBC mode (RFC 3713 block cipher; NIST SP 800-38A Sec 6.2 mode) with PKCS7 + /// padding, streaming stdin to stdout. + /// + /// See `camellia128-cbc` for the IV convention, the padding rule and the warnings; only the + /// key length differs. + CAMELLIA192_CBC { + #[arg(short, long)] + direction: CipherDirection, + + /// The 24-byte Camellia key in hex. + /// The `key_file` option is preferred to avoid leaving key material in command history. + #[arg(long)] + key: Option, + + /// A file containing the 24-byte Camellia key (raw bytes; hex with --hex-input). + /// If both key and key_file options are provided, the file will be used. + #[arg(short, long)] + key_file: Option, + + /// The 16-byte IV in hex. Supplied instead of generated: `encrypt` then writes no IV and + /// `decrypt` reads none. See the IV paragraph above. + #[arg(long)] + iv: Option, + + /// A file containing the 16-byte IV, (raw bytes; hex with --hex-input). + /// If both iv and iv_file options are provided, the file will be used. + #[arg(long)] + iv_file: Option, + + #[arg(short)] + /// Output in hex format. + x: bool, + }, + /// Camellia-256 in CBC mode (RFC 3713 block cipher; NIST SP 800-38A Sec 6.2 mode) with PKCS7 + /// padding, streaming stdin to stdout. + /// + /// See `camellia128-cbc` for the IV convention, the padding rule and the warnings; only the + /// key length differs. + CAMELLIA256_CBC { + #[arg(short, long)] + direction: CipherDirection, + + /// The 32-byte Camellia key in hex. + /// The `key_file` option is preferred to avoid leaving key material in command history. + #[arg(long)] + key: Option, + + /// A file containing the 32-byte Camellia key (raw bytes; hex with --hex-input). + /// If both key and key_file options are provided, the file will be used. + #[arg(short, long)] + key_file: Option, + + /// The 16-byte IV in hex. Supplied instead of generated: `encrypt` then writes no IV and + /// `decrypt` reads none. See the IV paragraph above. + #[arg(long)] + iv: Option, + + /// A file containing the 16-byte IV, (raw bytes; hex with --hex-input). + /// If both iv and iv_file options are provided, the file will be used. + #[arg(long)] + iv_file: Option, + + #[arg(short)] + /// Output in hex format. + x: bool, + }, + /// Camellia-128 in CCM mode (NIST SP 800-38C): authenticated encryption of stdin to stdout. + /// + /// CCM is an AEAD: it protects both confidentiality and authenticity, and `decrypt` either + /// writes the plaintext or fails, unlike aes*-cbc/-cfb/-ctr, which cannot detect tampering. + /// + /// The output of `encrypt` is `ciphertext || tag` -- SP 800-38C Sec 6.1 step 8's own layout -- + /// so it is `--tag-len` bytes longer than the input, and `decrypt` reads the tag back off the + /// end. Both directions authenticate `--aad` as well as the payload. + /// + /// THE NONCE IS SUPPLIED, NOT GENERATED, and this is the only cipher command here that takes + /// one. The other modes need an unpredictable IV, so they generate it; CCM needs the nonce to + /// be UNIQUE but not unpredictable (Sec 5.3: "The nonce is not required to be random"), and a + /// caller with a message counter can guarantee uniqueness better than a random draw. The nonce + /// is NOT written to the output, so `decrypt` needs the same `--nonce` as `encrypt`. + /// + /// WARNING: never reuse a nonce under one key. For CCM a repeat is worse than for CTR: it + /// reuses the keystream AND lets an attacker who can replay the nonce flip any chosen bit of + /// the payload (Appendix B.1). Use a counter, or a random value long enough that a collision is + /// negligible. + /// + /// Nonce length must be 7 to 13 bytes and `--tag-len` one of 4, 6, 8, 10, 12, 14, 16 + /// (Appendix A.1). The two are linked to the payload limit and the forgery bound respectively: + /// a nonce of n bytes caps the payload at 2^(8*(15-n)) - 1 bytes, so 13 bytes allows only + /// 64 KiB - 1 while 7 bytes is effectively unlimited; and Sec B.2 says a tag shorter than + /// 8 bytes "shall not be used without a careful analysis of the risks". A 12-byte nonce with a + /// 16-byte tag is the usual choice; `--tag-len` defaults to 16, while the nonce must be given. + /// + /// UNLIKE EVERY OTHER CIPHER COMMAND HERE, THIS ONE DOES NOT STREAM: it reads all of stdin + /// before doing any work, so memory use is proportional to the input. That is inherent to CCM, + /// not a limitation of this implementation -- Sec 3: "CCM is not designed to support partial + /// processing or stream processing", because Appendix A.2.1 puts the payload length inside the + /// first block the MAC covers. It does buy one thing: on `decrypt` NO plaintext is written + /// until the tag has verified, so unlike `ascon-aead128` a non-zero exit leaves nothing to + /// discard. For large inputs use `ascon-aead128`, which streams. The AAD is read whole as well. + /// + /// Input may be any length: CCM pads internally and the payload is not block-aligned. + /// + /// Note: in production uses, secrets should not be passed on the command-line because they get + /// logged in shell history. Use the file-based input instead. + CAMELLIA128_CCM { + #[arg(short, long)] + direction: CipherDirection, + + /// The 16-byte Camellia key in hex. + /// The `key_file` option is preferred to avoid leaving key material in command history. + #[arg(long)] + key: Option, + + /// A file containing the 16-byte Camellia key (raw bytes; hex with --hex-input). + /// If both key and key_file options are provided, the file will be used. + #[arg(short, long)] + key_file: Option, + + /// The nonce in hex, 7 to 13 bytes. MUST be unique per encryption under a given key. + #[arg(long)] + nonce: Option, + + /// A file containing the nonce, (raw bytes; hex with --hex-input). + #[arg(long)] + nonce_file: Option, + + /// Associated data in hex: authenticated but not encrypted. Must match on decrypt. + #[arg(long)] + aad: Option, + + /// A file containing the associated data (raw bytes; hex with --hex-input). If both aad and + /// aad_file options are provided, the file will be used. + #[arg(long)] + aad_file: Option, + + /// Tag length in bytes: one of 4, 6, 8, 10, 12, 14, 16. Must match on decrypt. + #[arg(long, default_value_t = 16)] + tag_len: usize, + + #[arg(short)] + /// Output in hex format. + x: bool, + }, + + /// Camellia-128 in CFB128 mode (RFC 3713 block cipher; NIST SP 800-38A Sec 6.3 mode), + /// streaming stdin to stdout. + /// + /// The segment size is the full block, i.e. CFB128. The 8-bit variant is a different, + /// non-interoperable mode; use `camellia128-cfb8` for that. + /// + /// On `encrypt`, a fresh unpredictable IV is generated and written as the FIRST 16 BYTES of + /// the output; on `decrypt` it is read back from the first 16 bytes of the input. With `--iv` + /// (hex) or `--iv-file` (raw bytes; hex with --hex-input), the IV is supplied instead and only ciphertext is written + /// or read. Input may be ANY length: nothing is padded. + /// + /// See `aes128-cfb` for the full IV convention, input-length rule and warnings; the key and + /// block are both 16 bytes, as for AES-128. + CAMELLIA128_CFB { + #[arg(short, long)] + direction: CipherDirection, + + /// The 16-byte Camellia key in hex. + /// The `key_file` option is preferred to avoid leaving key material in command history. + #[arg(long)] + key: Option, + + /// A file containing the 16-byte Camellia key (raw bytes; hex with --hex-input). + /// If both key and key_file options are provided, the file will be used. + #[arg(short, long)] + key_file: Option, + + /// The 16-byte IV in hex. Supplied instead of generated: `encrypt` then writes no IV and + /// `decrypt` reads none. See the IV paragraph above. + #[arg(long)] + iv: Option, + + /// A file containing the 16-byte IV, (raw bytes; hex with --hex-input). + /// If both iv and iv_file options are provided, the file will be used. + #[arg(long)] + iv_file: Option, + + #[arg(short)] + /// Output in hex format. + x: bool, + }, + /// Camellia-192 in CCM mode (NIST SP 800-38C), authenticated encryption of stdin to stdout. + /// + /// See `aes128-ccm` for the nonce convention, the length rules, the non-streaming note and the + /// warnings; only the key length differs. + CAMELLIA192_CCM { + #[arg(short, long)] + direction: CipherDirection, + + /// The 24-byte Camellia key in hex. + /// The `key_file` option is preferred to avoid leaving key material in command history. + #[arg(long)] + key: Option, + + /// A file containing the 24-byte Camellia key (raw bytes; hex with --hex-input). + /// If both key and key_file options are provided, the file will be used. + #[arg(short, long)] + key_file: Option, + + /// The nonce in hex, 7 to 13 bytes. MUST be unique per encryption under a given key. + #[arg(long)] + nonce: Option, + + /// A file containing the nonce, (raw bytes; hex with --hex-input). + #[arg(long)] + nonce_file: Option, + + /// Associated data in hex: authenticated but not encrypted. Must match on decrypt. + #[arg(long)] + aad: Option, + + /// A file containing the associated data (raw bytes; hex with --hex-input). If both aad and + /// aad_file options are provided, the file will be used. + #[arg(long)] + aad_file: Option, + + /// Tag length in bytes: one of 4, 6, 8, 10, 12, 14, 16. Must match on decrypt. + #[arg(long, default_value_t = 16)] + tag_len: usize, + + #[arg(short)] + /// Output in hex format. + x: bool, + }, + + /// Camellia-192 in CFB128 mode (RFC 3713 block cipher; NIST SP 800-38A Sec 6.3 mode), + /// streaming stdin to stdout. + /// + /// See `camellia128-cfb` for the IV convention, input-length rule and warnings; only the key + /// length differs. + CAMELLIA192_CFB { + #[arg(short, long)] + direction: CipherDirection, + + /// The 24-byte Camellia key in hex. + /// The `key_file` option is preferred to avoid leaving key material in command history. + #[arg(long)] + key: Option, + + /// A file containing the 24-byte Camellia key (raw bytes; hex with --hex-input). + /// If both key and key_file options are provided, the file will be used. + #[arg(short, long)] + key_file: Option, + + /// The 16-byte IV in hex. Supplied instead of generated: `encrypt` then writes no IV and + /// `decrypt` reads none. See the IV paragraph above. + #[arg(long)] + iv: Option, + + /// A file containing the 16-byte IV, (raw bytes; hex with --hex-input). + /// If both iv and iv_file options are provided, the file will be used. + #[arg(long)] + iv_file: Option, + + #[arg(short)] + /// Output in hex format. + x: bool, + }, + /// Camellia-256 in CCM mode (NIST SP 800-38C), authenticated encryption of stdin to stdout. + /// + /// See `aes128-ccm` for the nonce convention, the length rules, the non-streaming note and the + /// warnings; only the key length differs. + CAMELLIA256_CCM { + #[arg(short, long)] + direction: CipherDirection, + + /// The 32-byte Camellia key in hex. + /// The `key_file` option is preferred to avoid leaving key material in command history. + #[arg(long)] + key: Option, + + /// A file containing the 32-byte Camellia key (raw bytes; hex with --hex-input). + /// If both key and key_file options are provided, the file will be used. + #[arg(short, long)] + key_file: Option, + + /// The nonce in hex, 7 to 13 bytes. MUST be unique per encryption under a given key. + #[arg(long)] + nonce: Option, + + /// A file containing the nonce, (raw bytes; hex with --hex-input). + #[arg(long)] + nonce_file: Option, + + /// Associated data in hex: authenticated but not encrypted. Must match on decrypt. + #[arg(long)] + aad: Option, + + /// A file containing the associated data (raw bytes; hex with --hex-input). If both aad and + /// aad_file options are provided, the file will be used. + #[arg(long)] + aad_file: Option, + + /// Tag length in bytes: one of 4, 6, 8, 10, 12, 14, 16. Must match on decrypt. + #[arg(long, default_value_t = 16)] + tag_len: usize, + + #[arg(short)] + /// Output in hex format. + x: bool, + }, + + /// Camellia-256 in CFB128 mode (RFC 3713 block cipher; NIST SP 800-38A Sec 6.3 mode), + /// streaming stdin to stdout. + /// + /// See `camellia128-cfb` for the IV convention, input-length rule and warnings; only the key + /// length differs. + CAMELLIA256_CFB { + #[arg(short, long)] + direction: CipherDirection, + + /// The 32-byte Camellia key in hex. + /// The `key_file` option is preferred to avoid leaving key material in command history. + #[arg(long)] + key: Option, + + /// A file containing the 32-byte Camellia key (raw bytes; hex with --hex-input). + /// If both key and key_file options are provided, the file will be used. + #[arg(short, long)] + key_file: Option, + + /// The 16-byte IV in hex. Supplied instead of generated: `encrypt` then writes no IV and + /// `decrypt` reads none. See the IV paragraph above. + #[arg(long)] + iv: Option, + + /// A file containing the 16-byte IV, (raw bytes; hex with --hex-input). + /// If both iv and iv_file options are provided, the file will be used. + #[arg(long)] + iv_file: Option, + + #[arg(short)] + /// Output in hex format. + x: bool, + }, + /// Camellia-128 in CFB8 mode (RFC 3713 block cipher; NIST SP 800-38A Sec 6.3 mode, s = 8), + /// streaming stdin to stdout. + /// + /// The segment size is one byte. This is a DIFFERENT, NON-INTEROPERABLE mode from the CFB128 of + /// `camellia128-cfb`: the two ciphertexts agree only on their first byte. It also costs one + /// Camellia call per byte, sixteen times the work, so prefer `camellia128-cfb` unless a + /// byte-granular self-synchronising stream is required or the format demands CFB8. + /// + /// On `encrypt`, a fresh unpredictable IV is generated and written as the FIRST 16 BYTES of + /// the output; on `decrypt` it is read back from the first 16 bytes of the input. With `--iv` + /// (hex) or `--iv-file` (raw bytes; hex with --hex-input), the IV is supplied instead and only ciphertext is written + /// or read. Input may be ANY length: nothing is padded. + /// + /// See `aes128-cfb8` for the full IV convention, input-length rule and warnings; the key and + /// block are both 16 bytes, as for AES-128. + CAMELLIA128_CFB8 { + #[arg(short, long)] + direction: CipherDirection, + + /// The 16-byte Camellia key in hex. + /// The `key_file` option is preferred to avoid leaving key material in command history. + #[arg(long)] + key: Option, + + /// A file containing the 16-byte Camellia key (raw bytes; hex with --hex-input). + /// If both key and key_file options are provided, the file will be used. + #[arg(short, long)] + key_file: Option, + + /// The 16-byte IV in hex. Supplied instead of generated: `encrypt` then writes no IV and + /// `decrypt` reads none. See the IV paragraph above. + #[arg(long)] + iv: Option, + + /// A file containing the 16-byte IV, (raw bytes; hex with --hex-input). + /// If both iv and iv_file options are provided, the file will be used. + #[arg(long)] + iv_file: Option, + + #[arg(short)] + /// Output in hex format. + x: bool, + }, + /// Camellia-192 in CFB8 mode (RFC 3713 block cipher; NIST SP 800-38A Sec 6.3 mode, s = 8), + /// streaming stdin to stdout. + /// + /// See `camellia128-cfb8` for the IV convention, input-length rule and warnings; only the key + /// length differs. + CAMELLIA192_CFB8 { + #[arg(short, long)] + direction: CipherDirection, + + /// The 24-byte Camellia key in hex. + /// The `key_file` option is preferred to avoid leaving key material in command history. + #[arg(long)] + key: Option, + + /// A file containing the 24-byte Camellia key (raw bytes; hex with --hex-input). + /// If both key and key_file options are provided, the file will be used. + #[arg(short, long)] + key_file: Option, + + /// The 16-byte IV in hex. Supplied instead of generated: `encrypt` then writes no IV and + /// `decrypt` reads none. See the IV paragraph above. + #[arg(long)] + iv: Option, + + /// A file containing the 16-byte IV, (raw bytes; hex with --hex-input). + /// If both iv and iv_file options are provided, the file will be used. + #[arg(long)] + iv_file: Option, + + #[arg(short)] + /// Output in hex format. + x: bool, + }, + /// Camellia-256 in CFB8 mode (RFC 3713 block cipher; NIST SP 800-38A Sec 6.3 mode, s = 8), + /// streaming stdin to stdout. + /// + /// See `camellia128-cfb8` for the IV convention, input-length rule and warnings; only the key + /// length differs. + CAMELLIA256_CFB8 { + #[arg(short, long)] + direction: CipherDirection, + + /// The 32-byte Camellia key in hex. + /// The `key_file` option is preferred to avoid leaving key material in command history. + #[arg(long)] + key: Option, + + /// A file containing the 32-byte Camellia key (raw bytes; hex with --hex-input). + /// If both key and key_file options are provided, the file will be used. + #[arg(short, long)] + key_file: Option, + + /// The 16-byte IV in hex. Supplied instead of generated: `encrypt` then writes no IV and + /// `decrypt` reads none. See the IV paragraph above. + #[arg(long)] + iv: Option, + + /// A file containing the 16-byte IV, (raw bytes; hex with --hex-input). + /// If both iv and iv_file options are provided, the file will be used. + #[arg(long)] + iv_file: Option, + + #[arg(short)] + /// Output in hex format. + x: bool, + }, + /// Camellia-128 in CTR mode (RFC 3713 block cipher; NIST SP 800-38A Sec 6.5 mode), streaming + /// stdin to stdout. + /// + /// The counter block is a 12-byte nonce followed by a 4-byte counter starting at zero, so one + /// message can be up to 2^32 blocks (64 GiB); past that the command errors rather than + /// repeating keystream. On `encrypt` the nonce is written as the FIRST 12 BYTES of the output + /// and on `decrypt` it is read back from there -- 12, not the 16 the other modes write. With + /// `--iv` (hex) or `--iv-file` (raw bytes), the 12-byte nonce is supplied instead and only + /// ciphertext is written or read; it MUST then be unique per message under one key. This is + /// SP 800-38A Appendix B.2's construction, not RFC 5528's, so ciphertexts do not interoperate + /// with an RFC 5528 implementation. + /// + /// See `aes128-ctr` for the full nonce convention, input-length rule and warnings, including + /// why a repeated nonce is fatal and why CTR is the most malleable mode here. + CAMELLIA128_CTR { + #[arg(short, long)] + direction: CipherDirection, + + /// The 16-byte Camellia key in hex. + /// The `key_file` option is preferred to avoid leaving key material in command history. + #[arg(long)] + key: Option, + + /// A file containing the 16-byte Camellia key (raw bytes; hex with --hex-input). + /// If both key and key_file options are provided, the file will be used. + #[arg(short, long)] + key_file: Option, + + /// The 12-byte nonce in hex. Supplied instead of generated: `encrypt` then writes none + /// and `decrypt` reads none. See the nonce paragraph above. + #[arg(long)] + iv: Option, + + /// A file containing the 12-byte nonce, as raw bytes exactly as they are (no hex + /// decoding). If both iv and iv_file options are provided, the file will be used. + #[arg(long)] + iv_file: Option, + + #[arg(short)] + /// Output in hex format. + x: bool, + }, + + /// Camellia-128 in GCM (NIST SP 800-38D), streaming stdin to stdout. + /// + /// AUTHENTICATED, unlike the other Camellia modes here: tampering with the ciphertext, the AAD or + /// the IV is detected rather than merely producing wrong plaintext. + /// + /// On `encrypt`, a fresh 12-byte IV is generated and written as the FIRST 12 BYTES of the + /// output, the ciphertext follows, and the 16-byte tag is written last. `decrypt` reads the IV + /// back from the first 12 bytes of input and streams the rest, checking the tag once input is + /// exhausted. (SP 800-38D calls this value the IV, and defines it as a nonce.) + /// + /// With `--iv` (hex) or `--iv-file` (raw bytes; hex with --hex-input), the IV is supplied instead: `encrypt` uses it + /// and writes ONLY `ciphertext || tag`, and `decrypt` reads ONLY that from stdin. The IV MUST + /// be unique per message under one key (Sec 8), and a repeat is worse here than merely + /// unwise: it lets an attacker recover the hash subkey (Appendix A). The default takes care of + /// that; with `--iv` it is on the caller. + /// + /// `--aad` (hex) or `--aad-file` (raw bytes; hex with --hex-input) supply the additional authenticated data, + /// which is covered by the tag but not encrypted; if neither is given, AAD is empty. + /// + /// Input may be ANY length: GCM needs no padding. + /// + /// WARNING: on `decrypt`, a tag failure may be reported only after plaintext has already been + /// written to stdout, because this command streams the inline decryptor. A script MUST check + /// the exit code before trusting anything already written; on failure this command prints + /// `Error: authentication failed` and exits non-zero. + /// + /// Note: in production uses, secrets should not be passed on the command-line because they get + /// logged in shell history. Use the file-based input instead. + CAMELLIA128_GCM { + #[arg(short, long)] + direction: CipherDirection, + + /// The 16-byte Camellia key in hex. + /// The `key_file` option is preferred to avoid leaving key material in command history. + #[arg(long)] + key: Option, + + /// A file containing the 16-byte Camellia key (raw bytes; hex with --hex-input). + /// If both key and key_file options are provided, the file will be used. + #[arg(short, long)] + key_file: Option, + + /// The 12-byte IV in hex. Supplied instead of generated: `encrypt` then writes none and + /// `decrypt` reads none. See the IV paragraph above. + #[arg(long)] + iv: Option, + + /// A file containing the 12-byte IV, (raw bytes; hex with --hex-input). + /// If both iv and iv_file options are provided, the file will be used. + #[arg(long)] + iv_file: Option, + + /// The additional authenticated data, in hex. Covered by the tag but not encrypted. + #[arg(long)] + aad: Option, + + /// A file containing the additional authenticated data (raw bytes; hex with --hex-input). + /// If both aad and aad_file options are provided, the file will be used. + #[arg(long)] + aad_file: Option, + + #[arg(short)] + /// Output in hex format. + x: bool, + }, + /// Camellia-192 in CTR mode (RFC 3713 block cipher; NIST SP 800-38A Sec 6.5 mode), streaming + /// stdin to stdout. + /// + /// See `camellia128-ctr` for the nonce convention, input-length rule and warnings; only the key + /// length differs. + CAMELLIA192_CTR { + #[arg(short, long)] + direction: CipherDirection, + + /// The 24-byte Camellia key in hex. + /// The `key_file` option is preferred to avoid leaving key material in command history. + #[arg(long)] + key: Option, + + /// A file containing the 24-byte Camellia key (raw bytes; hex with --hex-input). + /// If both key and key_file options are provided, the file will be used. + #[arg(short, long)] + key_file: Option, + + /// The 12-byte nonce in hex. Supplied instead of generated: `encrypt` then writes none + /// and `decrypt` reads none. See the nonce paragraph above. + #[arg(long)] + iv: Option, + + /// A file containing the 12-byte nonce, as raw bytes exactly as they are (no hex + /// decoding). If both iv and iv_file options are provided, the file will be used. + #[arg(long)] + iv_file: Option, #[arg(short)] /// Output in hex format. x: bool, }, - /// Perform SHA3-224 of the content provided on stdin. - /// Supports streaming update for low memory footprint. - SHA3_224 { - #[arg(short)] - /// Output the hashes in hex format. - x: bool, - }, + /// Camellia-192 in GCM (NIST SP 800-38D), streaming stdin to stdout. + /// + /// See `aes128-gcm` for the IV/tag framing, the AAD flags and the warnings; only the key + /// length differs. + CAMELLIA192_GCM { + #[arg(short, long)] + direction: CipherDirection, - /// Perform SHA3-256 of the content provided on stdin. - /// Supports streaming update for low memory footprint. - SHA3_256 { - #[arg(short)] - /// Output the hashes in hex format. - x: bool, - }, + /// The 24-byte Camellia key in hex. + /// The `key_file` option is preferred to avoid leaving key material in command history. + #[arg(long)] + key: Option, - /// Perform SHA3-384 of the content provided on stdin. - /// Supports streaming update for low memory footprint. - SHA3_384 { - #[arg(short)] - /// Output the hashes in hex format. - x: bool, - }, + /// A file containing the 24-byte Camellia key (raw bytes; hex with --hex-input). + /// If both key and key_file options are provided, the file will be used. + #[arg(short, long)] + key_file: Option, - /// Perform SHA3-512 of the content provided on stdin. - /// Supports streaming update for low memory footprint. - SHA3_512 { - #[arg(short)] - /// Output the hashes in hex format. - x: bool, - }, + /// The 12-byte IV in hex. Supplied instead of generated: `encrypt` then writes none and + /// `decrypt` reads none. See the IV paragraph above. + #[arg(long)] + iv: Option, - /// Perform SHA224 of the content provided on stdin. - /// Supports streaming update for low memory footprint. - SHA224 { - #[arg(short)] - /// Output the hashes in hex format. - x: bool, - }, + /// A file containing the 12-byte IV, (raw bytes; hex with --hex-input). + /// If both iv and iv_file options are provided, the file will be used. + #[arg(long)] + iv_file: Option, - /// Perform SHA256 of the content provided on stdin. - /// Supports streaming update for low memory footprint. - SHA256 { - #[arg(short)] - /// Output the hashes in hex format. - x: bool, - }, + /// The additional authenticated data, in hex. Covered by the tag but not encrypted. + #[arg(long)] + aad: Option, - /// Perform SHA384 of the content provided on stdin. - /// Supports streaming update for low memory footprint. - SHA384 { - #[arg(short)] - /// Output the hashes in hex format. - x: bool, - }, + /// A file containing the additional authenticated data (raw bytes; hex with --hex-input). + /// If both aad and aad_file options are provided, the file will be used. + #[arg(long)] + aad_file: Option, - /// Perform SHA512 of the content provided on stdin. - /// Supports streaming update for low memory footprint. - SHA512 { #[arg(short)] - /// Output the hashes in hex format. + /// Output in hex format. x: bool, }, + /// Camellia-256 in CTR mode (RFC 3713 block cipher; NIST SP 800-38A Sec 6.5 mode), streaming + /// stdin to stdout. + /// + /// See `camellia128-ctr` for the nonce convention, input-length rule and warnings; only the key + /// length differs. + CAMELLIA256_CTR { + #[arg(short, long)] + direction: CipherDirection, - /// Perform SHA512/224 of the content provided on stdin. - /// Supports streaming update for low memory footprint. - SHA512_224 { - #[arg(short)] - /// Output the hashes in hex format. - x: bool, - }, + /// The 32-byte Camellia key in hex. + /// The `key_file` option is preferred to avoid leaving key material in command history. + #[arg(long)] + key: Option, - /// Perform SHA512/256 of the content provided on stdin. - /// Supports streaming update for low memory footprint. - SHA512_256 { - #[arg(short)] - /// Output the hashes in hex format. - x: bool, - }, + /// A file containing the 32-byte Camellia key (raw bytes; hex with --hex-input). + /// If both key and key_file options are provided, the file will be used. + #[arg(short, long)] + key_file: Option, - /// Perform SHAKE128 of the content provided on stdin. Requires the output length in bytes. - /// Supports streaming update for low memory footprint. - SHAKE128 { - /// Length of the output in bytes. - length: usize, + /// The 12-byte nonce in hex. Supplied instead of generated: `encrypt` then writes none + /// and `decrypt` reads none. See the nonce paragraph above. + #[arg(long)] + iv: Option, + + /// A file containing the 12-byte nonce, as raw bytes exactly as they are (no hex + /// decoding). If both iv and iv_file options are provided, the file will be used. + #[arg(long)] + iv_file: Option, #[arg(short)] - /// Output the hashes in hex format. + /// Output in hex format. x: bool, }, - /// Perform SHAKE256 of the content provided on stdin. Requires the output length in bytes. - /// Supports streaming update for low memory footprint. - SHAKE256 { - /// Length of the output in bytes. - length: usize, + /// Camellia-256 in GCM (NIST SP 800-38D), streaming stdin to stdout. + /// + /// See `aes128-gcm` for the IV/tag framing, the AAD flags and the warnings; only the key + /// length differs. + CAMELLIA256_GCM { + #[arg(short, long)] + direction: CipherDirection, - #[arg(short)] - /// Output the hashes in hex format. - x: bool, - }, + /// The 32-byte Camellia key in hex. + /// The `key_file` option is preferred to avoid leaving key material in command history. + #[arg(long)] + key: Option, + + /// A file containing the 32-byte Camellia key (raw bytes; hex with --hex-input). + /// If both key and key_file options are provided, the file will be used. + #[arg(short, long)] + key_file: Option, + + /// The 12-byte IV in hex. Supplied instead of generated: `encrypt` then writes none and + /// `decrypt` reads none. See the IV paragraph above. + #[arg(long)] + iv: Option, + + /// A file containing the 12-byte IV, (raw bytes; hex with --hex-input). + /// If both iv and iv_file options are provided, the file will be used. + #[arg(long)] + iv_file: Option, + + /// The additional authenticated data, in hex. Covered by the tag but not encrypted. + #[arg(long)] + aad: Option, + + /// A file containing the additional authenticated data (raw bytes; hex with --hex-input). + /// If both aad and aad_file options are provided, the file will be used. + #[arg(long)] + aad_file: Option, - /// Perform SM3 of the content provided on stdin. - /// Supports streaming update for low memory footprint. - SM3 { #[arg(short)] - /// Output the hashes in hex format. + /// Output in hex format. x: bool, }, @@ -3187,6 +4010,15 @@ fn run() { Some(Subcommands::AES256_KWP { direction, key, key_file, x }) => { aes_kw_cmd::aes256_kwp_cmd(direction, key, key_file, *x); } + Some(Subcommands::CAMELLIA128_KW { direction, key, key_file, x }) => { + camellia_kw_cmd::camellia128_kw_cmd(direction, key, key_file, *x); + } + Some(Subcommands::CAMELLIA192_KW { direction, key, key_file, x }) => { + camellia_kw_cmd::camellia192_kw_cmd(direction, key, key_file, *x); + } + Some(Subcommands::CAMELLIA256_KW { direction, key, key_file, x }) => { + camellia_kw_cmd::camellia256_kw_cmd(direction, key, key_file, *x); + } Some(Subcommands::MLKEM512 { action, skfile, pkfile, ctfile, x }) => { mlkem_cmd::mlkem_cmd(&mlkem_cmd::MLKEM512_SET, action, skfile, pkfile, ctfile, *x); } @@ -3261,6 +4093,129 @@ fn run() { Some(Subcommands::SM3 { x }) => { sm3_cmd::sm3_cmd(*x); } + Some(Subcommands::CAMELLIA128_CBC { direction, key, key_file, iv, iv_file, x }) => { + camellia_cbc_cmd::camellia128_cbc_cmd(direction, key, key_file, iv, iv_file, *x); + } + Some(Subcommands::CAMELLIA192_CBC { direction, key, key_file, iv, iv_file, x }) => { + camellia_cbc_cmd::camellia192_cbc_cmd(direction, key, key_file, iv, iv_file, *x); + } + Some(Subcommands::CAMELLIA256_CBC { direction, key, key_file, iv, iv_file, x }) => { + camellia_cbc_cmd::camellia256_cbc_cmd(direction, key, key_file, iv, iv_file, *x); + } + Some(Subcommands::CAMELLIA128_CCM { + direction, + key, + key_file, + nonce, + nonce_file, + aad, + aad_file, + tag_len, + x, + }) => { + camellia_ccm_cmd::camellia128_ccm_cmd( + direction, key, key_file, nonce, nonce_file, aad, aad_file, *tag_len, *x, + ); + } + Some(Subcommands::CAMELLIA128_CFB { direction, key, key_file, iv, iv_file, x }) => { + camellia_cfb_cmd::camellia128_cfb_cmd(direction, key, key_file, iv, iv_file, *x); + } + Some(Subcommands::CAMELLIA192_CCM { + direction, + key, + key_file, + nonce, + nonce_file, + aad, + aad_file, + tag_len, + x, + }) => { + camellia_ccm_cmd::camellia192_ccm_cmd( + direction, key, key_file, nonce, nonce_file, aad, aad_file, *tag_len, *x, + ); + } + Some(Subcommands::CAMELLIA192_CFB { direction, key, key_file, iv, iv_file, x }) => { + camellia_cfb_cmd::camellia192_cfb_cmd(direction, key, key_file, iv, iv_file, *x); + } + Some(Subcommands::CAMELLIA256_CCM { + direction, + key, + key_file, + nonce, + nonce_file, + aad, + aad_file, + tag_len, + x, + }) => { + camellia_ccm_cmd::camellia256_ccm_cmd( + direction, key, key_file, nonce, nonce_file, aad, aad_file, *tag_len, *x, + ); + } + Some(Subcommands::CAMELLIA256_CFB { direction, key, key_file, iv, iv_file, x }) => { + camellia_cfb_cmd::camellia256_cfb_cmd(direction, key, key_file, iv, iv_file, *x); + } + Some(Subcommands::CAMELLIA128_CFB8 { direction, key, key_file, iv, iv_file, x }) => { + camellia_cfb8_cmd::camellia128_cfb8_cmd(direction, key, key_file, iv, iv_file, *x); + } + Some(Subcommands::CAMELLIA192_CFB8 { direction, key, key_file, iv, iv_file, x }) => { + camellia_cfb8_cmd::camellia192_cfb8_cmd(direction, key, key_file, iv, iv_file, *x); + } + Some(Subcommands::CAMELLIA256_CFB8 { direction, key, key_file, iv, iv_file, x }) => { + camellia_cfb8_cmd::camellia256_cfb8_cmd(direction, key, key_file, iv, iv_file, *x); + } + Some(Subcommands::CAMELLIA128_CTR { direction, key, key_file, iv, iv_file, x }) => { + camellia_ctr_cmd::camellia128_ctr_cmd(direction, key, key_file, iv, iv_file, *x); + } + Some(Subcommands::CAMELLIA128_GCM { + direction, + key, + key_file, + iv, + iv_file, + aad, + aad_file, + x, + }) => { + camellia_gcm_cmd::camellia128_gcm_cmd( + direction, key, key_file, iv, iv_file, aad, aad_file, *x, + ); + } + Some(Subcommands::CAMELLIA192_CTR { direction, key, key_file, iv, iv_file, x }) => { + camellia_ctr_cmd::camellia192_ctr_cmd(direction, key, key_file, iv, iv_file, *x); + } + Some(Subcommands::CAMELLIA192_GCM { + direction, + key, + key_file, + iv, + iv_file, + aad, + aad_file, + x, + }) => { + camellia_gcm_cmd::camellia192_gcm_cmd( + direction, key, key_file, iv, iv_file, aad, aad_file, *x, + ); + } + Some(Subcommands::CAMELLIA256_CTR { direction, key, key_file, iv, iv_file, x }) => { + camellia_ctr_cmd::camellia256_ctr_cmd(direction, key, key_file, iv, iv_file, *x); + } + Some(Subcommands::CAMELLIA256_GCM { + direction, + key, + key_file, + iv, + iv_file, + aad, + aad_file, + x, + }) => { + camellia_gcm_cmd::camellia256_gcm_cmd( + direction, key, key_file, iv, iv_file, aad, aad_file, *x, + ); + } Some(Subcommands::TUPLEHASH128 { length, elements, diff --git a/cli/tests/camellia_cbc_cli_tests.rs b/cli/tests/camellia_cbc_cli_tests.rs new file mode 100644 index 000000000..cf769405c --- /dev/null +++ b/cli/tests/camellia_cbc_cli_tests.rs @@ -0,0 +1,242 @@ +//! Tests for the `camellia128-cbc`, `camellia192-cbc` and `camellia256-cbc` subcommands. +//! +//! They share their key and IV loaders, streaming loops and error paths with the `aes*-cbc` +//! commands (`cli/src/helpers/block_mode_helpers.rs`), and `test_aes_cbc.sh` covers those +//! exhaustively. This file pins what is specific to Camellia: the known-answer vectors in both +//! directions, the three key lengths, and that the commands exist and round-trip. +//! +//! Vectors are the `CAMELLIA-*-CBC` entries of OpenSSL's `evpciph_camellia.txt` (OpenSSL 3.6.2): +//! for each key length the first three entries chain into one three-block message under the IV +//! `000102..0f`; see `crypto/camellia/tests/openssl_cbc_tests.rs`. They are unpadded, so under +//! the commands' PKCS7 framing the three blocks are followed by one block of padding, computed +//! here from the permutation. + +use std::io::{ErrorKind, Write}; +use std::process::{Command, Output, Stdio}; + +/// The path to the binary under test, resolved by cargo. +const BC_RUST: &str = env!("CARGO_BIN_EXE_bc-rust"); + +/// The IV of the first entry of every chain. +const IV: &str = "000102030405060708090a0b0c0d0e0f"; + +/// The three chained plaintext blocks. +const PLAINTEXT: &str = concat!( + "6bc1bee22e409f96e93d7e117393172a", + "ae2d8a571e03ac9c9eb76fac45af8e51", + "30c81c46a35ce411e5fbc1191a0a52ef", +); + +const KEY_128: &str = "2b7e151628aed2a6abf7158809cf4f3c"; +const CT_128: &str = concat!( + "1607cf494b36bbf00daeb0b503c831ab", + "a2f2cf671629ef7840c5a5dfb5074887", + "0f06165008cf8b8b5a63586362543e54", +); + +const KEY_192: &str = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"; +const CT_192: &str = concat!( + "2a4830ab5ac4a1a2405955fd2195cf93", + "5d5a869bd14ce54264f892a6dd2ec3d5", + "37d359c3349836d884e310addf68c449", +); + +const KEY_256: &str = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"; +const CT_256: &str = concat!( + "e6cfa35fc02b134a4d2c0b6737ac3eda", + "36cbeb73bd504b4070b1b7de2b21eb50", + "e31a6055297d96ca3330cdf1b1860a83", +); + +/// Runs `bc-rust ` with `stdin_bytes` on stdin and returns the completed output. +fn run(args: &[&str], stdin_bytes: &[u8]) -> Output { + let mut child = Command::new(BC_RUST) + .args(args) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + .expect("failed to spawn bc-rust"); + + // The error-path tests hand a rejected key to a command that `exit`s before it ever reads + // stdin, so this write races the child's exit and sometimes loses -- reliably so on a loaded + // CI runner. That is an expected outcome, not a harness failure: `wait_with_output` still + // returns the exit status and stderr, which is all those tests assert on. Any other write + // error is a real problem and still panics. + match child.stdin.as_mut().expect("stdin piped").write_all(stdin_bytes) { + Ok(()) => {} + Err(e) if e.kind() == ErrorKind::BrokenPipe => {} + Err(e) => panic!("failed to write to stdin: {e}"), + } + + child.wait_with_output().expect("failed to wait for bc-rust") +} + +/// Runs a command that is expected to succeed, returning stdout. +fn run_ok(args: &[&str], stdin_bytes: &[u8]) -> Vec { + let out = run(args, stdin_bytes); + assert!( + out.status.success(), + "expected success from {args:?}, got {:?}\nstderr: {}", + out.status, + String::from_utf8_lossy(&out.stderr) + ); + out.stdout +} + +/// Runs a command that is expected to fail, returning stderr as a string. +fn run_err(args: &[&str], stdin_bytes: &[u8]) -> String { + let out = run(args, stdin_bytes); + assert!( + !out.status.success(), + "expected failure from {args:?}, but it succeeded\nstdout: {:?}", + String::from_utf8_lossy(&out.stdout) + ); + String::from_utf8_lossy(&out.stderr).into_owned() +} + +fn unhex(s: &str) -> Vec { + assert!(s.len().is_multiple_of(2), "hex string must have even length"); + (0..s.len()) + .step_by(2) + .map(|i| u8::from_str_radix(&s[i..i + 2], 16).expect("valid hex")) + .collect() +} + +fn tohex(bytes: &[u8]) -> String { + bytes.iter().map(|b| format!("{b:02x}")).collect() +} + +const VARIANTS: [(&str, &str, &str); 3] = [ + ("camellia128-cbc", KEY_128, CT_128), + ("camellia192-cbc", KEY_192, CT_192), + ("camellia256-cbc", KEY_256, CT_256), +]; + +/// The CBC ciphertext block that a full block of PKCS7 padding (sixteen `0x10` bytes) encrypts +/// to under `key_hex` after the ciphertext block `prev_hex`: `E_K(prev xor 10..10)`, from the +/// permutation of the key's length. Appended to an unpadded known-answer ciphertext whose +/// plaintext is block-aligned, it gives the PKCS7 ciphertext of the same plaintext, which is how +/// the commands frame it. +fn pkcs7_block(key_hex: &str, prev_hex: &str) -> String { + use bouncycastle::camellia::hazmat::{ + Camellia128Internal, Camellia192Internal, Camellia256Internal, + }; + use bouncycastle::core::hazmat::{BlockPermutation, ElectronicCodeBook}; + use bouncycastle::core::key_material::{KeyMaterial, KeyType}; + + fn material(key_hex: &str) -> KeyMaterial { + let key_bytes: [u8; N] = unhex(key_hex).try_into().expect("the right key length"); + KeyMaterial::::from_bytes_as_type(&key_bytes, KeyType::SymmetricCipherKey) + .expect("a valid symmetric cipher key") + } + let mut block: [u8; 16] = unhex(prev_hex).try_into().expect("a 16-byte block"); + block.iter_mut().for_each(|b| *b ^= 0x10); + match key_hex.len() / 2 { + 16 => Camellia128Internal::new(&material::<16>(key_hex)).unwrap().encrypt_block(&mut block), + 24 => Camellia192Internal::new(&material::<24>(key_hex)).unwrap().encrypt_block(&mut block), + 32 => Camellia256Internal::new(&material::<32>(key_hex)).unwrap().encrypt_block(&mut block), + _ => panic!("not a Camellia key length"), + } + tohex(&block) +} + +/// `encrypt --iv` reproduces the OpenSSL ciphertext followed by the PKCS7 block, for all three +/// key lengths, and `decrypt --iv` takes that back to the plaintext. +#[test] +fn encrypt_matches_the_openssl_vectors() { + for (cmd, key, ct) in VARIANTS { + let out = run_ok(&[cmd, "-d", "encrypt", "--key", key, "--iv", IV], &unhex(PLAINTEXT)); + let want = format!("{ct}{}", pkcs7_block(key, &ct[64..])); + assert_eq!(tohex(&out), want, "{cmd} encrypt --iv should give the ciphertext"); + + let back = run_ok(&[cmd, "-d", "decrypt", "--key", key, "--iv", IV], &out); + assert_eq!(tohex(&back), PLAINTEXT, "{cmd}: and decrypt --iv takes it back"); + } +} + +/// `decrypt` reproduces the plaintext when handed the IV followed by the ciphertext and the +/// PKCS7 block, for all three key lengths. +#[test] +fn decrypt_matches_the_openssl_vectors() { + for (cmd, key, ct) in VARIANTS { + let input = unhex(&format!("{IV}{ct}{}", pkcs7_block(key, &ct[64..]))); + let out = run_ok(&[cmd, "-d", "decrypt", "--key", key], &input); + assert_eq!(tohex(&out), PLAINTEXT, "{cmd} decrypt should give the plaintext"); + } +} + +/// The same with `-x`: identical answer in hex plus a trailing newline. +#[test] +fn hex_output_matches_binary_output() { + let input = unhex(&format!("{IV}{CT_256}{}", pkcs7_block(KEY_256, &CT_256[64..]))); + let out = run_ok(&["camellia256-cbc", "-d", "decrypt", "--key", KEY_256, "-x"], &input); + assert_eq!(String::from_utf8_lossy(&out), format!("{PLAINTEXT}\n")); +} + +/// `encrypt | decrypt` composes: the IV rides in the first block, and the plaintext comes back. +#[test] +fn encrypt_then_decrypt_round_trips() { + let plaintext: Vec = (0..4096u32).map(|i| (i.wrapping_mul(31) >> 3) as u8).collect(); + + for (cmd, key, _) in VARIANTS { + let ciphertext = run_ok(&[cmd, "-d", "encrypt", "--key", key], &plaintext); + assert_eq!( + ciphertext.len(), + 16 + plaintext.len() + 16, + "{cmd}: IV, the blocks, a padding block" + ); + assert_ne!(&ciphertext[16..], &plaintext[..]); + + let recovered = run_ok(&[cmd, "-d", "decrypt", "--key", key], &ciphertext); + assert_eq!(recovered, plaintext, "{cmd}"); + } +} + +/// Each command wants exactly its key length. The 256-bit key to the 128-bit command, and the +/// 128-bit key to the 192-bit command, are errors naming the algorithm. +#[test] +fn a_key_of_the_wrong_length_is_rejected() { + let err = run_err(&["camellia128-cbc", "-d", "encrypt", "--key", KEY_256], &[0u8; 16]); + assert!(err.contains("Camellia-128 needs a 16-byte key, got 32 bytes"), "stderr was: {err}"); + let err = run_err(&["camellia192-cbc", "-d", "encrypt", "--key", KEY_128], &[0u8; 16]); + assert!(err.contains("Camellia-192 needs a 24-byte key, got 16 bytes"), "stderr was: {err}"); + let err = run_err(&["camellia256-cbc", "-d", "encrypt", "--key", KEY_192], &[0u8; 16]); + assert!(err.contains("Camellia-256 needs a 32-byte key, got 24 bytes"), "stderr was: {err}"); +} + +/// The harness above must survive a write that loses the race with the child's exit. This pins it +/// deterministically: the key is rejected so `camellia128-cbc` exits before reading a byte, and +/// the payload is far larger than any pipe buffer, so the write is certain to get EPIPE rather +/// than merely likely to. +#[test] +fn a_large_payload_on_an_error_path_does_not_break_the_harness() { + let err = run_err( + &["camellia128-cbc", "-d", "encrypt", "--key", KEY_256], + &vec![0u8; 4 * 1024 * 1024], + ); + assert!(err.contains("Camellia-128 needs a 16-byte key"), "stderr was: {err}"); +} + +/// Any length is accepted and padded to the next whole block, as for the AES commands. +#[test] +fn any_input_length_is_accepted_and_padded() { + for len in [0usize, 1, 15, 16, 17, 33] { + let plaintext = vec![0x5Au8; len]; + let ciphertext = + run_ok(&["camellia128-cbc", "-d", "encrypt", "--key", KEY_128], &plaintext); + assert_eq!(ciphertext.len(), 16 + (len / 16 + 1) * 16, "len {len}: IV plus padded body"); + let recovered = + run_ok(&["camellia128-cbc", "-d", "decrypt", "--key", KEY_128], &ciphertext); + assert_eq!(recovered, plaintext, "len {len}: round trip"); + } +} + +/// A ciphertext without PKCS7 padding is rejected: the bare OpenSSL ciphertext ends in a block +/// that does not unpad. +#[test] +fn a_ciphertext_without_pkcs7_padding_is_rejected() { + let input = unhex(&format!("{IV}{CT_128}")); + let err = run_err(&["camellia128-cbc", "-d", "decrypt", "--key", KEY_128], &input); + assert!(err.contains("decryption failed"), "stderr was: {err}"); +} diff --git a/cli/tests/camellia_ccm_cli_tests.rs b/cli/tests/camellia_ccm_cli_tests.rs new file mode 100644 index 000000000..a48ec3031 --- /dev/null +++ b/cli/tests/camellia_ccm_cli_tests.rs @@ -0,0 +1,161 @@ +//! Tests for the `camellia128-ccm`, `camellia192-ccm` and `camellia256-ccm` subcommands. +//! +//! They are the `aes*-ccm` commands' runner over the Camellia keys (`cli/src/aes_ccm_cmd.rs`), and +//! `test_aes_ccm.sh` covers the nonce and tag-length rules, the AAD flags and the error paths. +//! This file pins what is specific to Camellia: a Wycheproof known answer in both directions at two +//! key lengths, the tag check, and that the commands exist and round-trip. +//! +//! The known answers are Project Wycheproof's `testvectors_v1/camellia_ccm_test.json` tcId 12 +//! (Camellia-128) and tcId 168 (Camellia-256), both with a 12-byte nonce, a 16-byte tag, 8 bytes of AAD +//! and a 16-byte message; the crate's `ccm_wycheproof.rs` runs them with the rest of the file. + +use std::io::{ErrorKind, Write}; +use std::process::{Command, Output, Stdio}; + +const BC_RUST: &str = env!("CARGO_BIN_EXE_bc-rust"); + +/// (command, key, nonce, aad, msg, ct, tag) +const VECTORS: [(&str, &str, &str, &str, &str, &str, &str); 2] = [ + ( + "camellia128-ccm", + "9415f925bcb41dc25e86c826dbc8bf68", + "bdffaa763b916ff0ee3f3ce4", + "705d676cd8a94451", + "feb36167eafc02c8e2bd6e13817686ba", + "5e9f70ff539eb2bc8dd347885a364fe4", + "bda220f3fb6e62b4b72b0cf59fb66436", + ), + ( + "camellia256-ccm", + "b907a45075513fe8a8019edee3f2591487b2a030b03c6e1d771c862571d2ea1e", + "118a6964c2d3e380071f5266", + "034585621af8d7ff", + "55a465644f5b650928cbee7c063214d6", + "577955b16fd98bc26040d52c574b5377", + "009906b169bb506d524a0a11f758b465", + ), +]; + +fn run(args: &[&str], stdin_bytes: &[u8]) -> Output { + let mut child = Command::new(BC_RUST) + .args(args) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + .expect("failed to spawn bc-rust"); + match child.stdin.as_mut().expect("stdin piped").write_all(stdin_bytes) { + Ok(()) => {} + Err(e) if e.kind() == ErrorKind::BrokenPipe => {} + Err(e) => panic!("failed to write to stdin: {e}"), + } + child.wait_with_output().expect("failed to wait for bc-rust") +} + +fn run_ok(args: &[&str], stdin_bytes: &[u8]) -> Vec { + let out = run(args, stdin_bytes); + assert!( + out.status.success(), + "expected success from {args:?}, got {:?}\nstderr: {}", + out.status, + String::from_utf8_lossy(&out.stderr) + ); + out.stdout +} + +fn run_err(args: &[&str], stdin_bytes: &[u8]) -> String { + let out = run(args, stdin_bytes); + assert!(!out.status.success(), "expected failure from {args:?}, but it succeeded"); + String::from_utf8_lossy(&out.stderr).into_owned() +} + +fn unhex(s: &str) -> Vec { + (0..s.len()).step_by(2).map(|i| u8::from_str_radix(&s[i..i + 2], 16).expect("hex")).collect() +} + +fn tohex(bytes: &[u8]) -> String { + bytes.iter().map(|b| format!("{b:02x}")).collect() +} + +/// `encrypt` reproduces the Wycheproof ciphertext and tag, as `ciphertext || tag`, and +/// `decrypt` takes them back to the message, at both key lengths. +#[test] +fn encrypt_and_decrypt_match_the_wycheproof_vectors() { + for (cmd, key, nonce, aad, msg, ct, tag) in VECTORS { + let args = [cmd, "--key", key, "--nonce", nonce, "--aad", aad]; + let out = run_ok(&[&args[..], &["-d", "encrypt"]].concat(), &unhex(msg)); + assert_eq!(tohex(&out), format!("{ct}{tag}"), "{cmd}: ciphertext || tag"); + let back = run_ok(&[&args[..], &["-d", "decrypt"]].concat(), &out); + assert_eq!(tohex(&back), msg, "{cmd}"); + } +} + +/// A flipped ciphertext bit, a flipped tag bit, other AAD or another nonce fails the tag check, +/// and nothing is written. +#[test] +fn tampering_fails_the_tag_check() { + let (cmd, key, nonce, aad, _msg, ct, tag) = VECTORS[0]; + let mut bytes = unhex(&format!("{ct}{tag}")); + let args = [cmd, "-d", "decrypt", "--key", key, "--nonce", nonce, "--aad", aad]; + run_ok(&args, &bytes); + bytes[0] ^= 1; + assert!(run_err(&args, &bytes).contains("authentic")); + bytes[0] ^= 1; + let last = bytes.len() - 1; + bytes[last] ^= 1; + let out = run(&args, &bytes); + assert!(!out.status.success()); + assert!(out.stdout.is_empty(), "no plaintext before the tag has verified"); + bytes[last] ^= 1; + let other_aad = + [cmd, "-d", "decrypt", "--key", key, "--nonce", nonce, "--aad", "705d676cd8a94450"]; + assert!(run_err(&other_aad, &bytes).contains("authentic")); + let other_nonce = + [cmd, "-d", "decrypt", "--key", key, "--nonce", "bdffaa763b916ff0ee3f3ce5", "--aad", aad]; + assert!(run_err(&other_nonce, &bytes).contains("authentic")); +} + +/// Any length round-trips at every key length, with the default 16-byte tag and a shorter one. +#[test] +fn encrypt_then_decrypt_round_trips_at_every_key_length() { + let message: Vec = (0..3000u32).map(|i| (i % 251) as u8).collect(); + for (cmd, key) in [ + ("camellia128-ccm", "000102030405060708090a0b0c0d0e0f"), + ("camellia192-ccm", "000102030405060708090a0b0c0d0e0f1011121314151617"), + ("camellia256-ccm", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"), + ] { + for tag_len in ["16", "8"] { + let nonce = "000102030405060708090a0b"; + let base = [cmd, "--key", key, "--nonce", nonce, "--tag-len", tag_len]; + let ct = run_ok(&[&base[..], &["-d", "encrypt"]].concat(), &message); + assert_eq!(ct.len(), message.len() + tag_len.parse::().unwrap(), "{cmd}"); + let back = run_ok(&[&base[..], &["-d", "decrypt"]].concat(), &ct); + assert_eq!(back, message, "{cmd}"); + } + } +} + +#[test] +fn a_key_of_the_wrong_length_is_rejected() { + let err = run_err( + &[ + "camellia128-ccm", + "-d", + "encrypt", + "--key", + "0011", + "--nonce", + "000102030405060708090a0b", + ], + b"x", + ); + assert!(err.contains("16-byte key"), "{err}"); +} + +#[test] +fn the_subcommands_are_listed_in_help() { + let help = String::from_utf8(run_ok(&["--help"], b"")).unwrap(); + for name in ["camellia128-ccm", "camellia192-ccm", "camellia256-ccm"] { + assert!(help.contains(name), "--help should list {name}"); + } +} diff --git a/cli/tests/camellia_cfb8_cli_tests.rs b/cli/tests/camellia_cfb8_cli_tests.rs new file mode 100644 index 000000000..5b9f95a2e --- /dev/null +++ b/cli/tests/camellia_cfb8_cli_tests.rs @@ -0,0 +1,259 @@ +//! Tests for the `camellia128-cfb8`, `camellia192-cfb8` and `camellia256-cfb8` subcommands. +//! +//! They share their key and IV loaders, streaming loops and error paths with the `aes*-cfb8` +//! commands (`cli/src/helpers/stream_mode_helpers.rs`), and `test_aes_cfb8.sh` covers those +//! exhaustively. This file pins what is specific to Camellia: the three key lengths, that the +//! commands exist and round-trip at any length, and that what comes out really is CFB8 over +//! Camellia. +//! +//! There is no published Camellia CFB8 vector -- OpenSSL's `evpciph_camellia.txt` says in as many +//! words that it does not carry `CFB{1,8}-CAMELLIAxxx` -- so instead the commands are required to +//! agree with `bouncycastle_cipher::modes::Cfb8` over the Camellia permutation, which +//! `crypto/camellia/tests/stream_mode_tests.rs` pins against the SP 800-38A Sec 6.3 equations at +//! `s = 8`. + +use std::io::{ErrorKind, Write}; +use std::process::{Command, Output, Stdio}; + +/// The path to the binary under test, resolved by cargo. +const BC_RUST: &str = env!("CARGO_BIN_EXE_bc-rust"); + +const KEY_128: &str = "2b7e151628aed2a6abf7158809cf4f3c"; +const KEY_192: &str = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"; +const KEY_256: &str = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"; + +/// Runs `bc-rust ` with `stdin_bytes` on stdin and returns the completed output. +fn run(args: &[&str], stdin_bytes: &[u8]) -> Output { + let mut child = Command::new(BC_RUST) + .args(args) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + .expect("failed to spawn bc-rust"); + + // The error-path tests hand a rejected key to a command that `exit`s before it ever reads + // stdin, so this write races the child's exit and sometimes loses -- reliably so on a loaded + // CI runner. That is an expected outcome, not a harness failure: `wait_with_output` still + // returns the exit status and stderr, which is all those tests assert on. Any other write + // error is a real problem and still panics. + match child.stdin.as_mut().expect("stdin piped").write_all(stdin_bytes) { + Ok(()) => {} + Err(e) if e.kind() == ErrorKind::BrokenPipe => {} + Err(e) => panic!("failed to write to stdin: {e}"), + } + + child.wait_with_output().expect("failed to wait for bc-rust") +} + +/// Runs a command that is expected to succeed, returning stdout. +fn run_ok(args: &[&str], stdin_bytes: &[u8]) -> Vec { + let out = run(args, stdin_bytes); + assert!( + out.status.success(), + "expected success from {args:?}, got {:?}\nstderr: {}", + out.status, + String::from_utf8_lossy(&out.stderr) + ); + out.stdout +} + +/// Runs a command that is expected to fail, returning stderr as a string. +fn run_err(args: &[&str], stdin_bytes: &[u8]) -> String { + let out = run(args, stdin_bytes); + assert!( + !out.status.success(), + "expected failure from {args:?}, but it succeeded\nstdout: {:?}", + String::from_utf8_lossy(&out.stdout) + ); + String::from_utf8_lossy(&out.stderr).into_owned() +} + +fn unhex(s: &str) -> Vec { + assert!(s.len().is_multiple_of(2), "hex string must have even length"); + (0..s.len()) + .step_by(2) + .map(|i| u8::from_str_radix(&s[i..i + 2], 16).expect("valid hex")) + .collect() +} + +/// Deterministic pseudo-random bytes, so the tests do not depend on an RNG. +fn pseudo_random(len: usize, seed: u32) -> Vec { + let mut state = seed.wrapping_mul(2_654_435_761).wrapping_add(1); + (0..len) + .map(|_| { + state ^= state << 13; + state ^= state >> 17; + state ^= state << 5; + (state >> 24) as u8 + }) + .collect() +} + +/// The library's answer for the same key, init data and ciphertext, so the CLI can be held to +/// it: the key object's in-place decryption. +fn library_cfb8_decrypt<'k, const KEY_LEN: usize, K>(key: &'k K, init: &[u8], data: &mut [u8]) +where + K: bouncycastle::core::symmetric_key::SymmetricDecryptionKey, + K::Decryptor<'k>: bouncycastle::core::traits::StreamCipherDecryptor<16>, +{ + let init: [u8; 16] = init.try_into().expect("the mode's init data length"); + key.decrypt_inplace(&init, data).expect("decryption"); +} + +/// The key object for `key_hex`, under the mode the command uses. +fn key_object(key_hex: &str) -> K +where + K: bouncycastle::core::symmetric_key::FromKeyMaterial, +{ + use bouncycastle::core::key_material::{KeyMaterial, KeyType}; + let key_bytes: [u8; KEY_LEN] = unhex(key_hex).try_into().expect("the right key length"); + let key = KeyMaterial::::from_bytes_as_type(&key_bytes, KeyType::SymmetricCipherKey) + .expect("a valid symmetric cipher key"); + K::from_key_material(&key).expect("a valid key") +} + +/// What each command emits must be exactly what `Cfb8` over the matching permutation produces: +/// take the IV the CLI generated, hand the body to the library, and the plaintext must come back. +#[test] +fn the_commands_are_cfb8_over_camellia() { + use bouncycastle::camellia::{Camellia128Key, Camellia192Key, Camellia256Key}; + use bouncycastle::cipher::modes::CFB8; + + for len in [1usize, 5, 16, 17, 64] { + let plaintext = pseudo_random(len, len as u32); + + let out = run_ok(&["camellia128-cfb8", "-d", "encrypt", "--key", KEY_128], &plaintext); + let (iv, body) = out.split_at(16); + let mut recovered = body.to_vec(); + library_cfb8_decrypt::<16, _>( + &key_object::<16, Camellia128Key>(KEY_128), + iv, + &mut recovered, + ); + assert_eq!(recovered, plaintext, "camellia128-cfb8, len {len}"); + + let out = run_ok(&["camellia192-cfb8", "-d", "encrypt", "--key", KEY_192], &plaintext); + let (iv, body) = out.split_at(16); + let mut recovered = body.to_vec(); + library_cfb8_decrypt::<24, _>( + &key_object::<24, Camellia192Key>(KEY_192), + iv, + &mut recovered, + ); + assert_eq!(recovered, plaintext, "camellia192-cfb8, len {len}"); + + let out = run_ok(&["camellia256-cfb8", "-d", "encrypt", "--key", KEY_256], &plaintext); + let (iv, body) = out.split_at(16); + let mut recovered = body.to_vec(); + library_cfb8_decrypt::<32, _>( + &key_object::<32, Camellia256Key>(KEY_256), + iv, + &mut recovered, + ); + assert_eq!(recovered, plaintext, "camellia256-cfb8, len {len}"); + } +} + +/// With `--iv` the output is the ciphertext alone, and it is still `Cfb8` over Camellia under +/// that IV. +#[test] +fn a_supplied_iv_is_used_and_not_written() { + use bouncycastle::camellia::Camellia128Key; + use bouncycastle::cipher::modes::CFB8; + + let iv = "000102030405060708090a0b0c0d0e0f"; + let plaintext = pseudo_random(37, 5); + let out = + run_ok(&["camellia128-cfb8", "-d", "encrypt", "--key", KEY_128, "--iv", iv], &plaintext); + assert_eq!(out.len(), plaintext.len(), "ciphertext only, no IV in band"); + + let mut recovered = out.clone(); + library_cfb8_decrypt::<16, _>( + &key_object::<16, Camellia128Key>(KEY_128), + &unhex(iv), + &mut recovered, + ); + assert_eq!(recovered, plaintext, "the CLI should agree with the library under that IV"); + + let back = run_ok(&["camellia128-cfb8", "-d", "decrypt", "--key", KEY_128, "--iv", iv], &out); + assert_eq!(back, plaintext); +} + +/// `encrypt | decrypt` composes at any length, with nothing padded. +#[test] +fn any_input_length_is_accepted_and_round_trips() { + for cmd in ["camellia128-cfb8", "camellia192-cfb8", "camellia256-cfb8"] { + let key = match cmd { + "camellia128-cfb8" => KEY_128, + "camellia192-cfb8" => KEY_192, + _ => KEY_256, + }; + for len in [0usize, 1, 15, 17, 33, 1024] { + let plaintext = pseudo_random(len, len as u32); + let ciphertext = run_ok(&[cmd, "-d", "encrypt", "--key", key], &plaintext); + assert_eq!( + ciphertext.len(), + 16 + len, + "{cmd}, len {len}: IV plus an equal-length body" + ); + let recovered = run_ok(&[cmd, "-d", "decrypt", "--key", key], &ciphertext); + assert_eq!(recovered, plaintext, "{cmd}, len {len}: round trip"); + } + } +} + +/// CFB8 and CFB128 are different modes, and `camellia128-cfb8` must not be a second name for +/// `camellia128-cfb`: handed the same IV and ciphertext, the two commands disagree past the first +/// byte. +#[test] +fn cfb8_is_not_cfb() { + let iv = "000102030405060708090a0b0c0d0e0f"; + let body = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51"; + let input = unhex(&format!("{iv}{body}")); + + let as_cfb8 = run_ok(&["camellia128-cfb8", "-d", "decrypt", "--key", KEY_128], &input); + let as_cfb = run_ok(&["camellia128-cfb", "-d", "decrypt", "--key", KEY_128], &input); + + assert_eq!( + as_cfb8[0], as_cfb[0], + "both XOR the first byte with MSB_8 of the same output block" + ); + assert_ne!(as_cfb8[1..], as_cfb[1..], "and they diverge from the second byte on"); +} + +/// Each command wants exactly its key length. The 256-bit key to the 128-bit command, and so on, +/// are errors naming the algorithm. +#[test] +fn a_key_of_the_wrong_length_is_rejected() { + let err = run_err(&["camellia128-cfb8", "-d", "encrypt", "--key", KEY_256], &[0u8; 16]); + assert!(err.contains("Camellia-128 needs a 16-byte key, got 32 bytes"), "stderr was: {err}"); + let err = run_err(&["camellia192-cfb8", "-d", "encrypt", "--key", KEY_128], &[0u8; 16]); + assert!(err.contains("Camellia-192 needs a 24-byte key, got 16 bytes"), "stderr was: {err}"); + let err = run_err(&["camellia256-cfb8", "-d", "encrypt", "--key", KEY_192], &[0u8; 16]); + assert!(err.contains("Camellia-256 needs a 32-byte key, got 24 bytes"), "stderr was: {err}"); +} + +/// The harness above must survive a write that loses the race with the child's exit. This pins it +/// deterministically: the key is rejected so `camellia128-cfb8` exits before reading a byte, and +/// the payload is far larger than any pipe buffer, so the write is certain to get EPIPE rather +/// than merely likely to. It guards the `run` helper that every test in this file -- and, copy +/// for copy, the sibling cfb and ctr suites -- depends on. +#[test] +fn a_large_payload_on_an_error_path_does_not_break_the_harness() { + let err = run_err( + &["camellia128-cfb8", "-d", "encrypt", "--key", KEY_256], + &vec![0u8; 4 * 1024 * 1024], + ); + assert!(err.contains("Camellia-128 needs a 16-byte key"), "stderr was: {err}"); +} + +/// The subcommands are discoverable. +#[test] +fn the_subcommands_are_listed_in_help() { + let out = run_ok(&["--help"], &[]); + let help = String::from_utf8_lossy(&out); + for cmd in ["camellia128-cfb8", "camellia192-cfb8", "camellia256-cfb8"] { + assert!(help.contains(cmd), "`--help` should list {cmd}"); + } +} diff --git a/cli/tests/camellia_cfb_cli_tests.rs b/cli/tests/camellia_cfb_cli_tests.rs new file mode 100644 index 000000000..aaa0b9c82 --- /dev/null +++ b/cli/tests/camellia_cfb_cli_tests.rs @@ -0,0 +1,211 @@ +//! Tests for the `camellia128-cfb`, `camellia192-cfb` and `camellia256-cfb` subcommands. +//! +//! They share their key and IV loaders, streaming loops and error paths with the `aes*-cfb` +//! commands (`cli/src/helpers/stream_mode_helpers.rs`), and `test_aes_cfb.sh` covers those +//! exhaustively. This file pins what is specific to Camellia: the known-answer vectors in both +//! directions, the three key lengths, and that the commands exist and round-trip at any length. +//! +//! Vectors are the `CAMELLIA-*-CFB` entries of OpenSSL's `evpciph_camellia.txt` (OpenSSL 3.6.2): +//! for each key length the four entries chain into one four-block CFB128 message under the IV +//! `000102..0f`; see `crypto/camellia/tests/stream_mode_tests.rs`. + +use std::io::{ErrorKind, Write}; +use std::process::{Command, Output, Stdio}; + +/// The path to the binary under test, resolved by cargo. +const BC_RUST: &str = env!("CARGO_BIN_EXE_bc-rust"); + +/// The IV of the first entry of every chain. +const IV: &str = "000102030405060708090a0b0c0d0e0f"; + +/// The four chained plaintext blocks (SP 800-38A Appendix F's). +const PLAINTEXT: &str = concat!( + "6bc1bee22e409f96e93d7e117393172a", + "ae2d8a571e03ac9c9eb76fac45af8e51", + "30c81c46a35ce411e5fbc1191a0a52ef", + "f69f2445df4f9b17ad2b417be66c3710", +); + +const KEY_128: &str = "2b7e151628aed2a6abf7158809cf4f3c"; +const KEY_192: &str = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"; +const KEY_256: &str = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"; + +const CT_128: &str = concat!( + "14f7646187817eb586599146b82bd719", + "a53d28bb82df741103ea4f921a44880b", + "9c2157a664626d1def9ea420fde69b96", + "742a25f0542340c7baef24ca8482bb09", +); +const CT_192: &str = concat!( + "c832bb9780677daa82d9b6860dcd565e", + "86f8491627906d780c7a6d46ea331f98", + "69511cce594cf710cb98bb63d7221f01", + "d5b5378a3abed55803f25565d8907b84", +); +const CT_256: &str = concat!( + "cf6107bb0cea7d7fb1bd31f5e7b06c93", + "89bedb4ccdd864ea11ba4cbe849b5e2b", + "555fc3f34bdd2d54c62d9e3bf338c1c4", + "5953adce14db8c7f39f1bd39f359bffa", +); + +/// Runs `bc-rust ` with `stdin_bytes` on stdin and returns the completed output. +fn run(args: &[&str], stdin_bytes: &[u8]) -> Output { + let mut child = Command::new(BC_RUST) + .args(args) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + .expect("failed to spawn bc-rust"); + + // The error-path tests hand a rejected key to a command that `exit`s before it ever reads + // stdin, so this write races the child's exit and sometimes loses -- reliably so on a loaded + // CI runner. That is an expected outcome, not a harness failure: `wait_with_output` still + // returns the exit status and stderr, which is all those tests assert on. Any other write + // error is a real problem and still panics. + match child.stdin.as_mut().expect("stdin piped").write_all(stdin_bytes) { + Ok(()) => {} + Err(e) if e.kind() == ErrorKind::BrokenPipe => {} + Err(e) => panic!("failed to write to stdin: {e}"), + } + + child.wait_with_output().expect("failed to wait for bc-rust") +} + +/// Runs a command that is expected to succeed, returning stdout. +fn run_ok(args: &[&str], stdin_bytes: &[u8]) -> Vec { + let out = run(args, stdin_bytes); + assert!( + out.status.success(), + "expected success from {args:?}, got {:?}\nstderr: {}", + out.status, + String::from_utf8_lossy(&out.stderr) + ); + out.stdout +} + +/// Runs a command that is expected to fail, returning stderr as a string. +fn run_err(args: &[&str], stdin_bytes: &[u8]) -> String { + let out = run(args, stdin_bytes); + assert!( + !out.status.success(), + "expected failure from {args:?}, but it succeeded\nstdout: {:?}", + String::from_utf8_lossy(&out.stdout) + ); + String::from_utf8_lossy(&out.stderr).into_owned() +} + +fn unhex(s: &str) -> Vec { + assert!(s.len().is_multiple_of(2), "hex string must have even length"); + (0..s.len()) + .step_by(2) + .map(|i| u8::from_str_radix(&s[i..i + 2], 16).expect("valid hex")) + .collect() +} + +fn tohex(bytes: &[u8]) -> String { + bytes.iter().map(|b| format!("{b:02x}")).collect() +} + +/// Deterministic pseudo-random bytes, so the tests do not depend on an RNG. +fn pseudo_random(len: usize, seed: u32) -> Vec { + let mut state = seed.wrapping_mul(2_654_435_761).wrapping_add(1); + (0..len) + .map(|_| { + state ^= state << 13; + state ^= state >> 17; + state ^= state << 5; + (state >> 24) as u8 + }) + .collect() +} + +const VARIANTS: [(&str, &str, &str); 3] = [ + ("camellia128-cfb", KEY_128, CT_128), + ("camellia192-cfb", KEY_192, CT_192), + ("camellia256-cfb", KEY_256, CT_256), +]; + +/// `encrypt --iv` reproduces the OpenSSL ciphertext, and nothing but the ciphertext, for all +/// three key lengths; `decrypt --iv` takes it back. +#[test] +fn encrypt_matches_the_openssl_vectors() { + for (cmd, key, ct) in VARIANTS { + let out = run_ok(&[cmd, "-d", "encrypt", "--key", key, "--iv", IV], &unhex(PLAINTEXT)); + assert_eq!(tohex(&out), ct, "{cmd} encrypt --iv should give the ciphertext"); + + let back = run_ok(&[cmd, "-d", "decrypt", "--key", key, "--iv", IV], &out); + assert_eq!(tohex(&back), PLAINTEXT, "{cmd}: and decrypt --iv takes it back"); + } +} + +/// `decrypt` reproduces the plaintext when handed the IV followed by the ciphertext, for all three +/// key lengths. +#[test] +fn decrypt_matches_the_openssl_vectors() { + for (cmd, key, ct) in VARIANTS { + let input = unhex(&format!("{IV}{ct}")); + let out = run_ok(&[cmd, "-d", "decrypt", "--key", key], &input); + assert_eq!(tohex(&out), PLAINTEXT, "{cmd} decrypt should give the plaintext"); + } +} + +/// The same with `-x`: identical answer in hex plus a trailing newline. +#[test] +fn hex_output_matches_binary_output() { + let input = unhex(&format!("{IV}{CT_256}")); + let out = run_ok(&["camellia256-cfb", "-d", "decrypt", "--key", KEY_256, "-x"], &input); + assert_eq!(String::from_utf8_lossy(&out), format!("{PLAINTEXT}\n")); +} + +/// `encrypt | decrypt` composes: the IV rides in the first block, and the plaintext comes back. +#[test] +fn encrypt_then_decrypt_round_trips() { + let plaintext = pseudo_random(4096, 0xC0FFEE); + + for (cmd, key, _) in VARIANTS { + let ciphertext = run_ok(&[cmd, "-d", "encrypt", "--key", key], &plaintext); + assert_eq!(ciphertext.len(), 16 + plaintext.len(), "{cmd}: IV plus an equal-length body"); + assert_ne!(&ciphertext[16..], &plaintext[..]); + + let recovered = run_ok(&[cmd, "-d", "decrypt", "--key", key], &ciphertext); + assert_eq!(recovered, plaintext, "{cmd}"); + } +} + +/// Unlike `camellia*-cbc`, any length is accepted and nothing is padded: CFB is a stream cipher. +#[test] +fn any_input_length_is_accepted() { + for len in [0usize, 1, 15, 17, 33] { + let plaintext = pseudo_random(len, len as u32); + let ciphertext = + run_ok(&["camellia128-cfb", "-d", "encrypt", "--key", KEY_128], &plaintext); + assert_eq!(ciphertext.len(), 16 + len, "len {len}: IV plus an equal-length body"); + let recovered = + run_ok(&["camellia128-cfb", "-d", "decrypt", "--key", KEY_128], &ciphertext); + assert_eq!(recovered, plaintext, "len {len}: round trip"); + } +} + +/// Each command wants exactly its key length. The 256-bit key to the 128-bit command, and so on, +/// are errors naming the algorithm. +#[test] +fn a_key_of_the_wrong_length_is_rejected() { + let err = run_err(&["camellia128-cfb", "-d", "encrypt", "--key", KEY_256], &[0u8; 16]); + assert!(err.contains("Camellia-128 needs a 16-byte key, got 32 bytes"), "stderr was: {err}"); + let err = run_err(&["camellia192-cfb", "-d", "encrypt", "--key", KEY_128], &[0u8; 16]); + assert!(err.contains("Camellia-192 needs a 24-byte key, got 16 bytes"), "stderr was: {err}"); + let err = run_err(&["camellia256-cfb", "-d", "encrypt", "--key", KEY_192], &[0u8; 16]); + assert!(err.contains("Camellia-256 needs a 32-byte key, got 24 bytes"), "stderr was: {err}"); +} + +/// The subcommands are discoverable. +#[test] +fn the_subcommands_are_listed_in_help() { + let out = run_ok(&["--help"], &[]); + let help = String::from_utf8_lossy(&out); + for cmd in ["camellia128-cfb", "camellia192-cfb", "camellia256-cfb"] { + assert!(help.contains(cmd), "`--help` should list {cmd}"); + } +} diff --git a/cli/tests/camellia_ctr_cli_tests.rs b/cli/tests/camellia_ctr_cli_tests.rs new file mode 100644 index 000000000..4b414fcb4 --- /dev/null +++ b/cli/tests/camellia_ctr_cli_tests.rs @@ -0,0 +1,273 @@ +//! Tests for the `camellia128-ctr`, `camellia192-ctr` and `camellia256-ctr` subcommands. +//! +//! They share their key and nonce loaders, streaming loops and error paths with the `aes*-ctr` +//! commands (`cli/src/helpers/stream_mode_helpers.rs`), and `test_aes_ctr.sh` covers those +//! exhaustively. This file pins what is specific to Camellia: the three key lengths, the +//! **12-byte** nonce, and that what comes out really is CTR over Camellia. +//! +//! RFC 5528's nine Camellia-CTR vectors divide the counter block differently -- a 4-octet nonce, an +//! 8-octet IV and a counter starting at one -- so they are not ones these commands can produce (see +//! the `Camellia_CTR_128` docs). Instead the commands are required to agree with +//! `bouncycastle_cipher::modes::Ctr` over the Camellia permutation, which +//! `crypto/camellia/tests/stream_mode_tests.rs` pins against the SP 800-38A Sec 6.5 equations, RFC +//! 5528's vectors included. + +use std::io::{ErrorKind, Write}; +use std::process::{Command, Output, Stdio}; + +/// The path to the binary under test, resolved by cargo. +const BC_RUST: &str = env!("CARGO_BIN_EXE_bc-rust"); + +/// CTR writes a 12-byte nonce, not the 16-byte IV the other modes write. +const NONCE_LEN: usize = 12; + +const KEY_128: &str = "2b7e151628aed2a6abf7158809cf4f3c"; +const KEY_192: &str = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"; +const KEY_256: &str = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"; + +/// Runs `bc-rust ` with `stdin_bytes` on stdin and returns the completed output. +fn run(args: &[&str], stdin_bytes: &[u8]) -> Output { + let mut child = Command::new(BC_RUST) + .args(args) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + .expect("failed to spawn bc-rust"); + + // The error-path tests hand a rejected key to a command that `exit`s before it ever reads + // stdin, so this write races the child's exit and sometimes loses -- reliably so on a loaded + // CI runner. That is an expected outcome, not a harness failure: `wait_with_output` still + // returns the exit status and stderr, which is all those tests assert on. Any other write + // error is a real problem and still panics. + match child.stdin.as_mut().expect("stdin piped").write_all(stdin_bytes) { + Ok(()) => {} + Err(e) if e.kind() == ErrorKind::BrokenPipe => {} + Err(e) => panic!("failed to write to stdin: {e}"), + } + + child.wait_with_output().expect("failed to wait for bc-rust") +} + +/// Runs a command that is expected to succeed, returning stdout. +fn run_ok(args: &[&str], stdin_bytes: &[u8]) -> Vec { + let out = run(args, stdin_bytes); + assert!( + out.status.success(), + "expected success from {args:?}, got {:?}\nstderr: {}", + out.status, + String::from_utf8_lossy(&out.stderr) + ); + out.stdout +} + +/// Runs a command that is expected to fail, returning stderr as a string. +fn run_err(args: &[&str], stdin_bytes: &[u8]) -> String { + let out = run(args, stdin_bytes); + assert!( + !out.status.success(), + "expected failure from {args:?}, but it succeeded\nstdout: {:?}", + String::from_utf8_lossy(&out.stdout) + ); + String::from_utf8_lossy(&out.stderr).into_owned() +} + +fn unhex(s: &str) -> Vec { + assert!(s.len().is_multiple_of(2), "hex string must have even length"); + (0..s.len()) + .step_by(2) + .map(|i| u8::from_str_radix(&s[i..i + 2], 16).expect("valid hex")) + .collect() +} + +fn tohex(bytes: &[u8]) -> String { + bytes.iter().map(|b| format!("{b:02x}")).collect() +} + +/// Deterministic pseudo-random bytes, so the tests do not depend on an RNG. +fn pseudo_random(len: usize, seed: u32) -> Vec { + let mut state = seed.wrapping_mul(2_654_435_761).wrapping_add(1); + (0..len) + .map(|_| { + state ^= state << 13; + state ^= state >> 17; + state ^= state << 5; + (state >> 24) as u8 + }) + .collect() +} + +/// The library's answer for the same key, init data and ciphertext, so the CLI can be held to +/// it: the key object's in-place decryption. +fn library_ctr_decrypt<'k, const KEY_LEN: usize, K>(key: &'k K, init: &[u8], data: &mut [u8]) +where + K: bouncycastle::core::symmetric_key::SymmetricDecryptionKey, + K::Decryptor<'k>: bouncycastle::core::traits::StreamCipherDecryptor, +{ + let init: [u8; NONCE_LEN] = init.try_into().expect("the mode's init data length"); + key.decrypt_inplace(&init, data).expect("decryption"); +} + +/// The key object for `key_hex`, under the mode the command uses. +fn key_object(key_hex: &str) -> K +where + K: bouncycastle::core::symmetric_key::FromKeyMaterial, +{ + use bouncycastle::core::key_material::{KeyMaterial, KeyType}; + let key_bytes: [u8; KEY_LEN] = unhex(key_hex).try_into().expect("the right key length"); + let key = KeyMaterial::::from_bytes_as_type(&key_bytes, KeyType::SymmetricCipherKey) + .expect("a valid symmetric cipher key"); + K::from_key_material(&key).expect("a valid key") +} + +/// With `--iv` the 12-byte nonce is supplied, the output is the ciphertext alone, and it is still +/// `Ctr` over Camellia under that nonce. +#[test] +fn a_supplied_nonce_is_used_and_not_written() { + use bouncycastle::camellia::Camellia128Key; + use bouncycastle::cipher::modes::CTR; + + let nonce = "000102030405060708090a0b"; + let plaintext = pseudo_random(37, 5); + let out = + run_ok(&["camellia128-ctr", "-d", "encrypt", "--key", KEY_128, "--iv", nonce], &plaintext); + assert_eq!(out.len(), plaintext.len(), "ciphertext only, no nonce in band"); + + let mut recovered = out.clone(); + library_ctr_decrypt::<16, _>( + &key_object::<16, Camellia128Key>(KEY_128), + &unhex(nonce), + &mut recovered, + ); + assert_eq!(recovered, plaintext, "the CLI should agree with the library under that nonce"); + + let back = run_ok(&["camellia128-ctr", "-d", "decrypt", "--key", KEY_128, "--iv", nonce], &out); + assert_eq!(back, plaintext); +} + +/// What each command emits must be exactly what `Ctr` over the matching permutation produces. +#[test] +fn the_commands_are_ctr_over_camellia() { + use bouncycastle::camellia::{Camellia128Key, Camellia192Key, Camellia256Key}; + use bouncycastle::cipher::modes::CTR; + + for len in [1usize, 5, 16, 17, 64] { + let plaintext = pseudo_random(len, len as u32); + + let out = run_ok(&["camellia128-ctr", "-d", "encrypt", "--key", KEY_128], &plaintext); + let (nonce, body) = out.split_at(NONCE_LEN); + let mut recovered = body.to_vec(); + library_ctr_decrypt::<16, _>( + &key_object::<16, Camellia128Key>(KEY_128), + nonce, + &mut recovered, + ); + assert_eq!(recovered, plaintext, "camellia128-ctr, len {len}"); + + let out = run_ok(&["camellia192-ctr", "-d", "encrypt", "--key", KEY_192], &plaintext); + let (nonce, body) = out.split_at(NONCE_LEN); + let mut recovered = body.to_vec(); + library_ctr_decrypt::<24, _>( + &key_object::<24, Camellia192Key>(KEY_192), + nonce, + &mut recovered, + ); + assert_eq!(recovered, plaintext, "camellia192-ctr, len {len}"); + + let out = run_ok(&["camellia256-ctr", "-d", "encrypt", "--key", KEY_256], &plaintext); + let (nonce, body) = out.split_at(NONCE_LEN); + let mut recovered = body.to_vec(); + library_ctr_decrypt::<32, _>( + &key_object::<32, Camellia256Key>(KEY_256), + nonce, + &mut recovered, + ); + assert_eq!(recovered, plaintext, "camellia256-ctr, len {len}"); + } +} + +/// CTR writes a **12-byte** nonce where the other Camellia modes write a 16-byte IV, so the output +/// is 12 bytes longer than the input rather than 16. Getting this wrong would shift every byte of +/// the payload. +#[test] +fn the_nonce_is_twelve_bytes_not_sixteen() { + let plaintext = pseudo_random(64, 7); + let out = run_ok(&["camellia128-ctr", "-d", "encrypt", "--key", KEY_128], &plaintext); + assert_eq!(out.len(), plaintext.len() + NONCE_LEN, "a 12-byte nonce plus the ciphertext"); + + let via_cfb = run_ok(&["camellia128-cfb", "-d", "encrypt", "--key", KEY_128], &plaintext); + assert_eq!(via_cfb.len(), plaintext.len() + 16, "camellia128-cfb writes a 16-byte IV"); + + let back = run_ok(&["camellia128-ctr", "-d", "decrypt", "--key", KEY_128], &out); + assert_eq!(back, plaintext); +} + +/// `encrypt | decrypt` composes at any length, with nothing padded. +#[test] +fn any_input_length_is_accepted_and_round_trips() { + for (cmd, key) in + [("camellia128-ctr", KEY_128), ("camellia192-ctr", KEY_192), ("camellia256-ctr", KEY_256)] + { + for len in [0usize, 1, 15, 17, 33, 4096] { + let plaintext = pseudo_random(len, len as u32); + let ciphertext = run_ok(&[cmd, "-d", "encrypt", "--key", key], &plaintext); + assert_eq!(ciphertext.len(), NONCE_LEN + len, "{cmd}, len {len}: nonce plus body"); + let recovered = run_ok(&[cmd, "-d", "decrypt", "--key", key], &ciphertext); + assert_eq!(recovered, plaintext, "{cmd}, len {len}: round trip"); + } + } +} + +/// A fresh nonce per invocation. For CTR this is the whole security argument: a repeated nonce +/// under one key repeats the keystream and leaks the XOR of the two messages. +#[test] +fn each_invocation_uses_a_fresh_nonce() { + let plaintext = pseudo_random(64, 11); + let mut seen = std::collections::BTreeSet::new(); + + for _ in 0..8 { + let ciphertext = + run_ok(&["camellia128-ctr", "-d", "encrypt", "--key", KEY_128], &plaintext); + assert!(seen.insert(ciphertext[..NONCE_LEN].to_vec()), "the CLI reused a nonce"); + let recovered = + run_ok(&["camellia128-ctr", "-d", "decrypt", "--key", KEY_128], &ciphertext); + assert_eq!(recovered, plaintext); + } +} + +/// The same with `-x`: identical answer in hex plus a trailing newline. +#[test] +fn hex_output_matches_binary_output() { + let plaintext = pseudo_random(32, 3); + let ciphertext = run_ok(&["camellia256-ctr", "-d", "encrypt", "--key", KEY_256], &plaintext); + + let binary = run_ok(&["camellia256-ctr", "-d", "decrypt", "--key", KEY_256], &ciphertext); + let hex_out = + run_ok(&["camellia256-ctr", "-d", "decrypt", "--key", KEY_256, "-x"], &ciphertext); + let hex_str = String::from_utf8(hex_out).expect("hex output is text"); + + assert_eq!(hex_str, format!("{}\n", tohex(&binary))); + assert_eq!(binary, plaintext); +} + +/// Each command wants exactly its key length. The 256-bit key to the 128-bit command, and so on, +/// are errors naming the algorithm. +#[test] +fn a_key_of_the_wrong_length_is_rejected() { + let err = run_err(&["camellia128-ctr", "-d", "encrypt", "--key", KEY_256], &[0u8; 16]); + assert!(err.contains("Camellia-128 needs a 16-byte key, got 32 bytes"), "stderr was: {err}"); + let err = run_err(&["camellia192-ctr", "-d", "encrypt", "--key", KEY_128], &[0u8; 16]); + assert!(err.contains("Camellia-192 needs a 24-byte key, got 16 bytes"), "stderr was: {err}"); + let err = run_err(&["camellia256-ctr", "-d", "encrypt", "--key", KEY_192], &[0u8; 16]); + assert!(err.contains("Camellia-256 needs a 32-byte key, got 24 bytes"), "stderr was: {err}"); +} + +/// The subcommands are discoverable. +#[test] +fn the_subcommands_are_listed_in_help() { + let out = run_ok(&["--help"], &[]); + let help = String::from_utf8_lossy(&out); + for cmd in ["camellia128-ctr", "camellia192-ctr", "camellia256-ctr"] { + assert!(help.contains(cmd), "`--help` should list {cmd}"); + } +} diff --git a/cli/tests/camellia_gcm_cli_tests.rs b/cli/tests/camellia_gcm_cli_tests.rs new file mode 100644 index 000000000..1f4f4cff3 --- /dev/null +++ b/cli/tests/camellia_gcm_cli_tests.rs @@ -0,0 +1,216 @@ +//! Tests for the `camellia128-gcm`, `camellia192-gcm` and `camellia256-gcm` subcommands. +//! +//! They share their key, IV and AAD loaders, streaming loops and error paths with the `aes*-gcm` +//! commands (`cli/src/helpers/aead_cipher_helpers.rs`), and `test_aes_gcm.sh` covers those +//! exhaustively. This file pins what is specific to Camellia: a known answer in both directions +//! at each key length, the three key lengths, the tag check, and that the commands exist and +//! round-trip. +//! +//! No standard or vector suite publishes a Camellia-GCM answer (the crate's `gcm_authors_tests.rs` +//! has the Camellia authors' cases, at 128 and 256 bits), so the known answers here, at all three +//! key lengths, are Bouncy Castle Java's, produced as `gcm_bc_java_tests.rs` describes (bc-java 1.87's +//! `GCMBlockCipher` over `CamelliaEngine`, the RFC 3713 keys, a counting nonce, AAD and message); +//! the generated-nonce output is held to the library's own `Camellia128Key` as well. + +use std::io::{ErrorKind, Write}; +use std::process::{Command, Output, Stdio}; + +const BC_RUST: &str = env!("CARGO_BIN_EXE_bc-rust"); + +const KEY: &str = "28ff3def08179311e2734c6d1c4e2871"; +const NONCE_LEN: usize = 12; +const TAG_LEN: usize = 16; + +fn run(args: &[&str], stdin_bytes: &[u8]) -> Output { + let mut child = Command::new(BC_RUST) + .args(args) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + .expect("failed to spawn bc-rust"); + match child.stdin.as_mut().expect("stdin piped").write_all(stdin_bytes) { + Ok(()) => {} + Err(e) if e.kind() == ErrorKind::BrokenPipe => {} + Err(e) => panic!("failed to write to stdin: {e}"), + } + child.wait_with_output().expect("failed to wait for bc-rust") +} + +fn run_ok(args: &[&str], stdin_bytes: &[u8]) -> Vec { + let out = run(args, stdin_bytes); + assert!( + out.status.success(), + "expected success from {args:?}, got {:?}\nstderr: {}", + out.status, + String::from_utf8_lossy(&out.stderr) + ); + out.stdout +} + +fn run_err(args: &[&str], stdin_bytes: &[u8]) -> String { + let out = run(args, stdin_bytes); + assert!(!out.status.success(), "expected failure from {args:?}, but it succeeded"); + String::from_utf8_lossy(&out.stderr).into_owned() +} + +fn unhex(s: &str) -> Vec { + (0..s.len()).step_by(2).map(|i| u8::from_str_radix(&s[i..i + 2], 16).expect("hex")).collect() +} + +fn pseudo_random(len: usize, seed: u32) -> Vec { + let mut state = seed.wrapping_mul(2_654_435_761).wrapping_add(1); + (0..len) + .map(|_| { + state ^= state << 13; + state ^= state >> 17; + state ^= state << 5; + (state >> 24) as u8 + }) + .collect() +} + +/// The library's answer for the same key, nonce, AAD and inline `ciphertext || tag`: the key +/// object's inline one-shot under `GCM`. +fn library_gcm_decrypt(key_hex: &str, nonce: &[u8], aad: &[u8], ciphertext: &[u8]) -> Vec { + use bouncycastle::camellia::Camellia128Key; + use bouncycastle::cipher::modes::GCM; + use bouncycastle::core::key_material::{KeyMaterial, KeyType}; + use bouncycastle::core::symmetric_key::{AeadDecryptionKey, FromKeyMaterial}; + + let key_bytes: [u8; 16] = unhex(key_hex).try_into().expect("a 16-byte key"); + let material = KeyMaterial::<16>::from_bytes_as_type(&key_bytes, KeyType::SymmetricCipherKey) + .expect("a valid symmetric cipher key"); + let key = Camellia128Key::::from_key_material(&material).expect("a valid key"); + let nonce: [u8; NONCE_LEN] = nonce.try_into().expect("a 12-byte nonce"); + key.decrypt_with_aad(&nonce, aad, ciphertext).expect("the tag verifies") +} + +/// (command, key, ct, tag) over the shared nonce, AAD and message below, from bc-java 1.87. +const VECTORS: [(&str, &str, &str, &str); 3] = [ + ( + "camellia128-gcm", + "0123456789abcdeffedcba9876543210", + "7a49673f1fc95a61bdbd4fd9991e69ce66e11221900db3fe0477c8db0fde7c3f86f9fb95ddcfd29d32fba91dc8", + "254bc51b6e3af975424eab7b4cf3bd25", + ), + ( + "camellia192-gcm", + "0123456789abcdeffedcba98765432100011223344556677", + "ed112533b2cfe17a9db68a9c230c10a83cc3abef4991ee76baf0faf8d14bd0c87091ad693bd85a062f022c3fc2", + "157cb0bc12aed1c6a327cc7d0d7d93ca", + ), + ( + "camellia256-gcm", + "0123456789abcdeffedcba987654321000112233445566778899aabbccddeeff", + "a8f62afcade453f94e2773f6d2318693ea4d48319cd2ee0268ba9bd4c5c88f57b78226b445b5440e3006df2118", + "e66a02576a8bad35da49a0c073cae837", + ), +]; +const VECTOR_NONCE: &str = "101112131415161718191a1b"; +const VECTOR_AAD: &str = "202122232425262728292a2b2c2d2e2f30313233"; +const VECTOR_MSG: &str = + "404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c"; + +/// `encrypt` under `--iv` reproduces bc-java's ciphertext and tag, as `ciphertext || tag`, and +/// `decrypt` takes them back to the message, at each key length. +#[test] +fn encrypt_and_decrypt_match_the_bc_java_vectors() { + for (cmd, key, ct, tag) in VECTORS { + let args = [cmd, "--key", key, "--iv", VECTOR_NONCE, "--aad", VECTOR_AAD]; + let expected = unhex(&format!("{ct}{tag}")); + let out = run_ok(&[&args[..], &["-d", "encrypt"]].concat(), &unhex(VECTOR_MSG)); + assert_eq!(out, expected, "{cmd}: ciphertext || tag"); + let back = run_ok(&[&args[..], &["-d", "decrypt"]].concat(), &expected); + assert_eq!(back, unhex(VECTOR_MSG), "{cmd}: decrypt"); + } +} + +/// What the command emits must be exactly what the library's `GCM` key produces: the generated +/// nonce leads, the body is as long as the input, and the tag follows. +#[test] +fn the_command_is_gcm_over_camellia() { + for len in [0usize, 1, 5, 16, 17, 64, 1000] { + let plaintext = pseudo_random(len, len as u32); + let out = run_ok( + &["camellia128-gcm", "-d", "encrypt", "--key", KEY, "--aad", "deadbeef"], + &plaintext, + ); + assert_eq!(out.len(), NONCE_LEN + len + TAG_LEN, "len {len}: nonce, body and tag"); + let (nonce, body) = out.split_at(NONCE_LEN); + let recovered = library_gcm_decrypt(KEY, nonce, &unhex("deadbeef"), body); + assert_eq!(recovered, plaintext, "len {len}: the CLI should agree with the library"); + let back = + run_ok(&["camellia128-gcm", "-d", "decrypt", "--key", KEY, "--aad", "deadbeef"], &out); + assert_eq!(back, plaintext, "len {len}: round trip"); + } +} + +/// A flipped ciphertext bit, a flipped tag bit, other AAD or another key fails the tag check. +#[test] +fn tampering_fails_the_tag_check() { + let plaintext = pseudo_random(69, 9); + let iv = "32bcb9b569e3b852d37c766a"; + let args = ["camellia128-gcm", "-d", "decrypt", "--key", KEY, "--iv", iv, "--aad", "c3"]; + let mut ct = run_ok( + &["camellia128-gcm", "-d", "encrypt", "--key", KEY, "--iv", iv, "--aad", "c3"], + &plaintext, + ); + assert_eq!(run_ok(&args, &ct), plaintext); + ct[0] ^= 1; + assert!(run_err(&args, &ct).contains("authentication failed")); + ct[0] ^= 1; + let last = ct.len() - 1; + ct[last] ^= 1; + assert!(run_err(&args, &ct).contains("authentication failed")); + ct[last] ^= 1; + let other_aad = ["camellia128-gcm", "-d", "decrypt", "--key", KEY, "--iv", iv, "--aad", "c4"]; + assert!(run_err(&other_aad, &ct).contains("authentication failed")); + let other_key = [ + "camellia128-gcm", + "-d", + "decrypt", + "--key", + "28ff3def08179311e2734c6d1c4e2870", + "--iv", + iv, + "--aad", + "c3", + ]; + assert!(run_err(&other_key, &ct).contains("authentication failed")); +} + +/// Without `--iv` the command draws one and writes it first; the round trip works at every key +/// length and the output is 12 + len + 16 bytes. +#[test] +fn encrypt_then_decrypt_round_trips_at_every_key_length() { + let message: Vec = (0..3000u32).map(|i| (i % 251) as u8).collect(); + for (cmd, key) in [ + ("camellia128-gcm", "000102030405060708090a0b0c0d0e0f"), + ("camellia192-gcm", "000102030405060708090a0b0c0d0e0f1011121314151617"), + ("camellia256-gcm", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"), + ] { + let ct = run_ok(&[cmd, "-d", "encrypt", "--key", key], &message); + assert_eq!(ct.len(), 12 + message.len() + 16, "{cmd}: IV || ciphertext || tag"); + let back = run_ok(&[cmd, "-d", "decrypt", "--key", key], &ct); + assert_eq!(back, message, "{cmd}"); + let again = run_ok(&[cmd, "-d", "encrypt", "--key", key], &message); + assert_ne!(again[..12], ct[..12], "{cmd}: a fresh IV each time"); + } +} + +#[test] +fn a_key_of_the_wrong_length_is_rejected() { + let err = run_err(&["camellia128-gcm", "-d", "encrypt", "--key", "0011"], b"x"); + assert!(err.contains("16-byte key"), "{err}"); + let err = run_err(&["camellia256-gcm", "-d", "encrypt", "--key", KEY], b"x"); + assert!(err.contains("32-byte key"), "{err}"); +} + +#[test] +fn the_subcommands_are_listed_in_help() { + let help = String::from_utf8(run_ok(&["--help"], b"")).unwrap(); + for name in ["camellia128-gcm", "camellia192-gcm", "camellia256-gcm"] { + assert!(help.contains(name), "--help should list {name}"); + } +} diff --git a/cli/tests/camellia_kw_cli_tests.rs b/cli/tests/camellia_kw_cli_tests.rs new file mode 100644 index 000000000..6f0d8e5c8 --- /dev/null +++ b/cli/tests/camellia_kw_cli_tests.rs @@ -0,0 +1,128 @@ +//! Tests for the `camellia{128,192,256}-kw` subcommands. +//! +//! They share everything but the key type with the `aes*-kw` commands, whose `test_aes_kw.sh` +//! covers the command-line contract exhaustively. This file pins what is specific to Camellia: +//! a known answer at each key length in both directions, and that the commands exist, fail closed +//! and are listed. +//! +//! The known answers are the first pseudorandom (`Normal`) 32-byte case at each key length of +//! Wycheproof's `camellia_wrap_test.json` (tcId 7, 48, 101); the full set runs in +//! `crypto/camellia/tests/kw_wycheproof.rs`. + +use std::io::{ErrorKind, Write}; +use std::process::{Command, Output, Stdio}; + +/// The path to the binary under test, resolved by cargo. +const BC_RUST: &str = env!("CARGO_BIN_EXE_bc-rust"); + +/// `(subcommand, kek, plaintext, ciphertext)`. +const VECTORS: [(&str, &str, &str, &str); 3] = [ + ( + "camellia128-kw", + "c2b9d23f2831ddcdeb456853d4014db9", + "f4cfea98e58b939cc859554385cf3a6c7f8217f728efb431c964786de8274907", + "b66e781a42e0f1ac440d9a9c6ee726cd5303ab52e3aa48f3b970069ed13b43eca328d0abae9cc8c3", + ), + ( + "camellia192-kw", + "1639f9f81e53e2eeb677a249e5eced3af108971301601a7b", + "ec3c6a1f1a9585327fe658490c74635e5300876da5846a629398984fb551d691", + "f9b7811aed1727dbb386efdd6a1268239f3034d6a5c219970ca814b8100e418ce62a31f4770c0c2a", + ), + ( + "camellia256-kw", + "38e1b1d075d9d852b9a6c01c8ff6965af01bac457a4e339ae3e1d7b2ffacc0cd", + "80ad6820f1c90981e2ca42b817a345c1179d0a11d8e23a8adc0505e13d87295a", + "ce84390d0920ec3d0d15ab8f4c5b3a75253b2403539da6d94fddd2c26d0fb1abe296c188b62b9c15", + ), +]; + +/// Runs `bc-rust ` with `stdin_bytes` on stdin and returns the completed output. +fn run(args: &[&str], stdin_bytes: &[u8]) -> Output { + let mut child = Command::new(BC_RUST) + .args(args) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + .expect("failed to spawn bc-rust"); + // A command that exits before reading stdin makes this write race its exit; that is the + // expected outcome for the error-path tests, which assert on the status and stderr only. + match child.stdin.as_mut().expect("stdin piped").write_all(stdin_bytes) { + Ok(()) => {} + Err(e) if e.kind() == ErrorKind::BrokenPipe => {} + Err(e) => panic!("failed to write to stdin: {e}"), + } + child.wait_with_output().expect("failed to wait for bc-rust") +} + +fn run_ok(args: &[&str], stdin_bytes: &[u8]) -> Vec { + let out = run(args, stdin_bytes); + assert!( + out.status.success(), + "expected success from {args:?}, got {:?}\nstderr: {}", + out.status, + String::from_utf8_lossy(&out.stderr) + ); + out.stdout +} + +fn run_err(args: &[&str], stdin_bytes: &[u8]) -> String { + let out = run(args, stdin_bytes); + assert!( + !out.status.success(), + "expected failure from {args:?}, but it succeeded\nstdout: {:?}", + String::from_utf8_lossy(&out.stdout) + ); + assert!(out.stdout.is_empty(), "a rejected unwrap must write nothing: {args:?}"); + String::from_utf8_lossy(&out.stderr).into_owned() +} + +fn unhex(s: &str) -> Vec { + (0..s.len()).step_by(2).map(|i| u8::from_str_radix(&s[i..i + 2], 16).expect("hex")).collect() +} + +fn tohex(bytes: &[u8]) -> String { + bytes.iter().map(|b| format!("{b:02x}")).collect() +} + +#[test] +fn the_wycheproof_answers_in_both_directions() { + for (cmd, kek, pt, ct) in VECTORS { + let wrapped = run_ok(&[cmd, "-d", "encrypt", "--key", kek], &unhex(pt)); + assert_eq!(tohex(&wrapped), ct, "{cmd} wrap"); + let hex = run_ok(&[cmd, "-d", "encrypt", "--key", kek, "-x"], &unhex(pt)); + assert_eq!(String::from_utf8_lossy(&hex).trim(), ct, "{cmd} wrap -x"); + let unwrapped = run_ok(&[cmd, "-d", "decrypt", "--key", kek], &unhex(ct)); + assert_eq!(tohex(&unwrapped), pt, "{cmd} unwrap"); + } +} + +#[test] +fn a_tampered_ciphertext_and_the_wrong_kek_are_rejected() { + for (cmd, kek, _, ct) in VECTORS { + let mut bad = unhex(ct); + bad[13] ^= 0x01; + let err = run_err(&[cmd, "-d", "decrypt", "--key", kek], &bad); + assert!(err.contains("not an authentic"), "{cmd}: {err}"); + let mut wrong = unhex(kek); + wrong[0] ^= 0x01; + let err = run_err(&[cmd, "-d", "decrypt", "--key", &tohex(&wrong)], &unhex(ct)); + assert!(err.contains("not an authentic"), "{cmd}: {err}"); + } +} + +#[test] +fn unaligned_input_is_refused() { + let (cmd, kek, _, _) = VECTORS[0]; + let err = run_err(&[cmd, "-d", "encrypt", "--key", kek], &[0x5Au8; 20]); + assert!(err.contains("20 bytes rejected"), "{err}"); +} + +#[test] +fn the_subcommands_are_listed_in_help() { + let help = String::from_utf8(run_ok(&["--help"], b"")).unwrap(); + for cmd in VECTORS.map(|v| v.0) { + assert!(help.contains(cmd), "--help should list {cmd}"); + } +} diff --git a/crypto/camellia/Cargo.toml b/crypto/camellia/Cargo.toml new file mode 100644 index 000000000..178d399d2 --- /dev/null +++ b/crypto/camellia/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "bouncycastle-camellia" +version.workspace = true +edition.workspace = true + +[dependencies] +bouncycastle-core.workspace = true +bouncycastle-utils.workspace = true +# The modes the keys hand out, the `ModeNames` impls and the `Camellia_*` aliases; the engines +# themselves do not use it. +bouncycastle-cipher.workspace = true + +[dev-dependencies] +bouncycastle-core-test-framework.workspace = true +bouncycastle-hex.workspace = true +bouncycastle-rng.workspace = true +criterion.workspace = true +serde_json = "1.0" + +[[bench]] +name = "camellia_benches" +harness = false diff --git a/crypto/camellia/benches/camellia_benches.rs b/crypto/camellia/benches/camellia_benches.rs new file mode 100644 index 000000000..1e868db82 --- /dev/null +++ b/crypto/camellia/benches/camellia_benches.rs @@ -0,0 +1,135 @@ +//! Criterion benchmarks for the bit-sliced Camellia engine. +//! +//! The comparison that matters is `encrypt_block` against `encrypt_2blocks` and `encrypt_4blocks` +//! over the same number of bytes. The S-box circuit always processes four lanes, so a single-block +//! call does four blocks' worth of work and the four-block path (what the CBC mode's decryption +//! uses) should be close to four times the throughput; the two-block path sits at half. Decryption +//! costs the same as encryption (the same rounds with the subkeys read in the swapped order). +//! Camellia-192 and Camellia-256 share the 24-round schedule, so only the 256-bit variant is +//! benchmarked alongside the 18-round Camellia-128. + +use bouncycastle_camellia::hazmat::{Camellia128Internal, Camellia256Internal}; +use bouncycastle_camellia::{BLOCK_LEN, LANES}; +use bouncycastle_core::hazmat::{BlockPermutation, ElectronicCodeBook}; +use bouncycastle_core::key_material::{KeyMaterial, KeyType}; +use bouncycastle_core::traits::RNG; +use bouncycastle_rng as rng; +use criterion::{Criterion, Throughput, criterion_group, criterion_main}; +use std::hint::black_box; + +/// 16 KiB of data, i.e. 1024 Camellia blocks. +const NUM_BLOCKS: usize = 1024; +const DATA_LEN: usize = NUM_BLOCKS * BLOCK_LEN; + +fn random_blocks() -> Vec<[u8; BLOCK_LEN]> { + let mut blocks = vec![[0u8; BLOCK_LEN]; NUM_BLOCKS]; + let mut generator = rng::DefaultRNG::default(); + for block in blocks.iter_mut() { + generator.next_bytes_out(block).unwrap(); + } + blocks +} + +fn key() -> KeyMaterial { + let mut bytes = [0u8; KEY_LEN]; + rng::DefaultRNG::default().next_bytes_out(&mut bytes).unwrap(); + KeyMaterial::::from_bytes_as_type(&bytes, KeyType::SymmetricCipherKey).unwrap() +} + +fn bench_key_expansion(c: &mut Criterion) { + let mut group = c.benchmark_group("camellia::key expansion"); + + let key128 = key::<16>(); + group.bench_function("Camellia128Internal::new()", |b| { + b.iter(|| black_box(Camellia128Internal::new(black_box(&key128)).unwrap())) + }); + let key256 = key::<32>(); + group.bench_function("Camellia256Internal::new()", |b| { + b.iter(|| black_box(Camellia256Internal::new(black_box(&key256)).unwrap())) + }); + + group.finish(); +} + +fn bench_camellia128(c: &mut Criterion) { + let camellia = Camellia128Internal::new(&key::<16>()).unwrap(); + let blocks = random_blocks(); + + let mut group = c.benchmark_group("camellia::Camellia128Internal"); + group.throughput(Throughput::Bytes(DATA_LEN as u64)); + + group.bench_function("16KiB -- .encrypt_block() x1024", |b| { + b.iter(|| { + let mut buf = blocks.clone(); + for block in buf.iter_mut() { + camellia.encrypt_block(black_box(block)); + } + black_box(&buf); + }) + }); + + group.bench_function("16KiB -- .encrypt_2blocks() x512", |b| { + b.iter(|| { + let mut buf = blocks.clone(); + for pair in buf.as_chunks_mut::<2>().0 { + camellia.encrypt_2blocks(black_box(pair)); + } + black_box(&buf); + }) + }); + + group.bench_function("16KiB -- .encrypt_4blocks() x256", |b| { + b.iter(|| { + let mut buf = blocks.clone(); + for four in buf.as_chunks_mut::().0 { + camellia.encrypt_4blocks(black_box(four)); + } + black_box(&buf); + }) + }); + + group.bench_function("16KiB -- .decrypt_block() x1024", |b| { + b.iter(|| { + let mut buf = blocks.clone(); + for block in buf.iter_mut() { + camellia.decrypt_block(black_box(block)); + } + black_box(&buf); + }) + }); + + group.finish(); +} + +fn bench_camellia256(c: &mut Criterion) { + let camellia = Camellia256Internal::new(&key::<32>()).unwrap(); + let blocks = random_blocks(); + + let mut group = c.benchmark_group("camellia::Camellia256Internal"); + group.throughput(Throughput::Bytes(DATA_LEN as u64)); + + group.bench_function("16KiB -- .encrypt_block() x1024", |b| { + b.iter(|| { + let mut buf = blocks.clone(); + for block in buf.iter_mut() { + camellia.encrypt_block(black_box(block)); + } + black_box(&buf); + }) + }); + + group.bench_function("16KiB -- .encrypt_4blocks() x256", |b| { + b.iter(|| { + let mut buf = blocks.clone(); + for four in buf.as_chunks_mut::().0 { + camellia.encrypt_4blocks(black_box(four)); + } + black_box(&buf); + }) + }); + + group.finish(); +} + +criterion_group!(benches, bench_key_expansion, bench_camellia128, bench_camellia256); +criterion_main!(benches); diff --git a/crypto/camellia/src/bitslice.rs b/crypto/camellia/src/bitslice.rs new file mode 100644 index 000000000..61b8b32fd --- /dev/null +++ b/crypto/camellia/src/bitslice.rs @@ -0,0 +1,105 @@ +//! Bit-plane transposition for the constant-time S-box layer. +//! +//! # Layout +//! +//! The F-function substitutes the eight bytes of one 64-bit word per round (RFC 3713 Sec 2.4.1, +//! `t1 .. t8`). To evaluate the S-boxes as a Boolean circuit, the 64-bit inputs of four blocks +//! are split into 32-bit halves -- eight words -- and transposed so that plane `q[k]` holds bit +//! `k` of every one of the 32 bytes: +//! +//! ```text +//! before ortho: q[w] bit (8L + k) == bit k of byte L of word w +//! after ortho: q[k] bit (8L + w) == bit k of byte L of word w +//! ``` +//! +//! That is, within each byte-lane `L` of the eight words, the 8x8 bit matrix indexed by +//! (word, bit-within-lane) is transposed. Byte `L` is bits `8L .. 8L+7` of the word. The S-box +//! layer in [`crate::sbox`] loads word `b` with the high half (`t1 .. t4`) of block `b`'s input +//! and word `4 + b` with the low half (`t5 .. t8`), so that within a plane the bits `8L .. 8L+3` +//! are byte `L` of the four high halves and `8L+4 .. 8L+7` byte `L` of the four low halves. Which +//! of the four S-boxes a byte position gets is therefore a public 32-bit mask. +//! +//! `test_layout_matches_the_documented_table` pins the identity above exhaustively. +//! +//! # Why 32-bit planes +//! +//! Eight `u64` planes would hold the whole input of eight blocks and double the throughput on a +//! 64-bit machine, at the cost of doubling every buffer in the round: the working state, the +//! planes, and their copy during the byte rotations. This crate takes the smaller working set -- +//! that is what "lowmemory" means here -- and processes four blocks per pass. +//! +//! # Provenance +//! +//! The three-stage masked-swap transpose is the same one `bouncycastle-aes` uses, both +//! translated from BearSSL `src/symcipher/aes_ct.c` (`br_aes_ct_ortho`) by Thomas Pornin, MIT +//! licensed. It is duplicated rather than shared because it is each crate's private detail and +//! neither should depend on the other. + +/// The eight bit-planes holding the two 32-bit halves of one word from each of four blocks. See +/// the module docs. +pub(crate) type Planes = [u32; 8]; + +/// Transposes bytes into bit-planes, and back -- it is its own inverse. +/// +/// Three stages of masked swaps exchange bit-fields of width 1, 2 and 4 between pairs of words, +/// which together transpose the 8x8 bit matrix inside each byte-lane. +pub(crate) fn ortho(q: &mut Planes) { + /// One masked swap: exchanges the `cl`-selected fields of `y` into `x` and the `ch`-selected + /// fields of `x` into `y`, moving them by `s` bit positions. + /// + /// `cl` and `ch` are complementary, and `s` is exactly the field width, so in each returned + /// word the two combined operands occupy disjoint bits: `(x & cl)` and `(y & cl) << s` cannot + /// both be set in the same position. `|` and `^` therefore compute the same function here, + /// which is why `cargo mutants` reports the `| -> ^` mutants in this function as surviving -- + /// they are equivalent programs. `test_ortho_is_an_involution` and + /// `test_layout_matches_the_documented_table` are what actually pin this code. + #[inline(always)] + fn swap(cl: u32, ch: u32, s: u32, x: u32, y: u32) -> (u32, u32) { + ((x & cl) | ((y & cl) << s), ((x & ch) >> s) | (y & ch)) + } + + // Stage 1: swap single bits between adjacent words (0x55 = even bits, 0xAA = odd bits). + for (a, b) in [(0, 1), (2, 3), (4, 5), (6, 7)] { + (q[a], q[b]) = swap(0x5555_5555, 0xAAAA_AAAA, 1, q[a], q[b]); + } + // Stage 2: swap 2-bit fields between words two apart. + for (a, b) in [(0, 2), (1, 3), (4, 6), (5, 7)] { + (q[a], q[b]) = swap(0x3333_3333, 0xCCCC_CCCC, 2, q[a], q[b]); + } + // Stage 3: swap nibbles between words four apart. + for (a, b) in [(0, 4), (1, 5), (2, 6), (3, 7)] { + (q[a], q[b]) = swap(0x0F0F_0F0F, 0xF0F0_F0F0, 4, q[a], q[b]); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_ortho_is_an_involution() { + let mut q: Planes = core::array::from_fn(|i| 0x0123_4567u32.wrapping_mul(i as u32 + 3)); + let original = q; + ortho(&mut q); + assert_ne!(q, original, "ortho must actually move bits"); + ortho(&mut q); + assert_eq!(q, original); + } + + #[test] + fn test_layout_matches_the_documented_table() { + // A single set bit at (word w, byte-lane L, bit k) must land at (plane k, lane L, bit w). + for w in 0..8 { + for lane in 0..4 { + for k in 0..8 { + let mut q: Planes = [0; 8]; + q[w] = 1 << (8 * lane + k); + ortho(&mut q); + let mut expected: Planes = [0; 8]; + expected[k] = 1 << (8 * lane + w); + assert_eq!(q, expected, "word {w}, lane {lane}, bit {k}"); + } + } + } + } +} diff --git a/crypto/camellia/src/cbc.rs b/crypto/camellia/src/cbc.rs new file mode 100644 index 000000000..92de23930 --- /dev/null +++ b/crypto/camellia/src/cbc.rs @@ -0,0 +1,127 @@ +//! Type aliases for Camellia (RFC 3713) in CBC mode (NIST SP 800-38A Sec 6.2), with padding. The +//! docs are on [`Camellia_CBC_128`], which the crate root re-exports. + +use crate::BLOCK_LEN; +use crate::hazmat::{Camellia128Internal, Camellia192Internal, Camellia256Internal}; +use bouncycastle_cipher::Direction; +use bouncycastle_cipher::modes::Cbc; +use bouncycastle_cipher::padding::{PaddedBlockCipherDecryptor, PaddedBlockCipherEncryptor}; +use bouncycastle_cipher::{Decrypting, Encrypting}; + +// Imports needed for docs +#[allow(unused_imports)] +use bouncycastle_cipher::padding::{NoPadding, PKCS7}; +#[allow(unused_imports)] +use bouncycastle_core::symmetric_key::{SymmetricDecryptionKey, SymmetricEncryptionKey}; +// end of imports needed for docs + +/// Camellia-128 in CBC mode with a padding scheme: what an +/// [`Camellia128Key`](crate::Camellia128Key) under `CBC` hands out. `Dir` is [`Encrypting`] or +/// [`Decrypting`] and `Pad` is [`PKCS7`] or [`NoPadding`]; the wrong direction is a compile error, +/// not a runtime check. +/// +/// See `bouncycastle_cipher::modes::cbc` for the construction. The aliases name the padded +/// workers, which accept input of any size; `NoPadding` accepts only whole blocks but goes through +/// the same adapter. The workers come from a key: +/// [`Camellia128Key>`](crate::Camellia128Key) +/// (or `CBC`) hands them out through the [`SymmetricEncryptionKey`] / +/// [`SymmetricDecryptionKey`] pair, and `Camellia128Key>` hands out the unpadded `Cbc` +/// itself through the block pair. +/// +/// CBC is defined only on whole blocks (SP 800-38A Sec 5.2), so CBC on data of any other length is +/// always CBC *plus a padding scheme*, and the scheme changes the ciphertext and must be agreed by +/// both ends. Naming it in the key's mode makes that choice explicit and makes a mismatched pair a +/// compile error. +/// +/// ``` +/// use bouncycastle_camellia::Camellia128Key; +/// use bouncycastle_cipher::modes::CBC; +/// use bouncycastle_cipher::padding::PKCS7; +/// use bouncycastle_core::key_material::{KeyMaterial, KeyType}; +/// use bouncycastle_core::symmetric_key::{FromKeyMaterial, SymmetricDecryptionKey}; +/// use bouncycastle_core::symmetric_key::SymmetricEncryptionKey; +/// use bouncycastle_rng::HashDRBG_SHA512; +/// +/// let mut rng = HashDRBG_SHA512::new_from_os(); +/// let material = KeyMaterial::<16>::from_bytes_as_type(&[0x42; 16], KeyType::SymmetricCipherKey) +/// .expect("a 16-byte symmetric cipher key"); +/// let key = Camellia128Key::>::from_key_material(&material) +/// .expect("a valid Camellia-128 key"); +/// let message = b"a message of no particular length"; +/// +/// // The IV is drawn from `rng` and returned; there is no API for supplying one. +/// let (iv, ciphertext) = key.encrypt(&mut rng, message).expect("encryption"); +/// let recovered = key.decrypt(&iv, &ciphertext).expect("decryption"); +/// assert_eq!(recovered, message); +/// ``` +/// +/// With [`NoPadding`] nothing is added, and a message that is not a whole number of blocks is an +/// error rather than something silently padded: +/// +/// ``` +/// use bouncycastle_camellia::Camellia128Key; +/// use bouncycastle_cipher::modes::CBC; +/// use bouncycastle_cipher::padding::NoPadding; +/// use bouncycastle_core::key_material::{KeyMaterial, KeyType}; +/// use bouncycastle_core::symmetric_key::{FromKeyMaterial, SymmetricEncryptionKey}; +/// use bouncycastle_rng::HashDRBG_SHA512; +/// +/// let mut rng = HashDRBG_SHA512::new_from_os(); +/// let material = KeyMaterial::<16>::from_bytes_as_type(&[0x42; 16], KeyType::SymmetricCipherKey) +/// .unwrap(); +/// let key = Camellia128Key::>::from_key_material(&material).unwrap(); +/// +/// let mut out = [0u8; 16]; +/// let (written, _iv) = key.encrypt_out(&mut rng, &[0u8; 16], &mut out).expect("aligned"); +/// assert_eq!(written, 16); +/// assert!(key.encrypt_out(&mut rng, b"hello", &mut out).is_err()); +/// ``` +#[allow(non_camel_case_types)] +pub type Camellia_CBC_128<'k, Dir, Pad> = ::Select< + PaddedBlockCipherEncryptor< + Cbc<'k, Camellia128Internal, Encrypting, BLOCK_LEN>, + Pad, + BLOCK_LEN, + BLOCK_LEN, + >, + PaddedBlockCipherDecryptor< + Cbc<'k, Camellia128Internal, Decrypting, BLOCK_LEN>, + Pad, + BLOCK_LEN, + BLOCK_LEN, + >, +>; + +/// Camellia-192 in CBC mode with a padding scheme. See [`Camellia_CBC_128`]. +#[allow(non_camel_case_types)] +pub type Camellia_CBC_192<'k, Dir, Pad> = ::Select< + PaddedBlockCipherEncryptor< + Cbc<'k, Camellia192Internal, Encrypting, BLOCK_LEN>, + Pad, + BLOCK_LEN, + BLOCK_LEN, + >, + PaddedBlockCipherDecryptor< + Cbc<'k, Camellia192Internal, Decrypting, BLOCK_LEN>, + Pad, + BLOCK_LEN, + BLOCK_LEN, + >, +>; + +/// Camellia-256 in CBC mode with a padding scheme. See [`Camellia_CBC_128`]. +#[allow(non_camel_case_types)] +pub type Camellia_CBC_256<'k, Dir, Pad> = ::Select< + PaddedBlockCipherEncryptor< + Cbc<'k, Camellia256Internal, Encrypting, BLOCK_LEN>, + Pad, + BLOCK_LEN, + BLOCK_LEN, + >, + PaddedBlockCipherDecryptor< + Cbc<'k, Camellia256Internal, Decrypting, BLOCK_LEN>, + Pad, + BLOCK_LEN, + BLOCK_LEN, + >, +>; diff --git a/crypto/camellia/src/ccm.rs b/crypto/camellia/src/ccm.rs new file mode 100644 index 000000000..75992e893 --- /dev/null +++ b/crypto/camellia/src/ccm.rs @@ -0,0 +1,89 @@ +//! Type aliases for Camellia in CCM mode (NIST SP 800-38C). The docs are on [`Camellia_CCM_128`], which +//! the crate root re-exports. + +use crate::BLOCK_LEN; +use crate::hazmat::{Camellia128Internal, Camellia192Internal, Camellia256Internal}; +use bouncycastle_cipher::Direction; +use bouncycastle_cipher::modes::{CcmPacketDecryptor, CcmPacketEncryptor}; + +/// The nonce length to use unless there is a reason not to: 12 bytes, which leaves `q = 3` and +/// so a payload of up to 16 MiB - 1 bytes. The same choice as `bouncycastle-aes`'s. +pub const CCM_NONCE_LEN: usize = 12; + +/// The tag length to use unless there is a reason not to: the full 16 bytes, the largest +/// Appendix A.1 permits. +pub const CCM_TAG_LEN: usize = 16; + +/// Camellia-128 in CCM mode for frames of exactly `DATA_LEN` payload bytes, as an +/// `AEADCipherEncryptor` or `AEADCipherDecryptor` by `Dir`: the fixed-frame pair of +/// `bouncycastle-cipher`'s CCM over the Camellia permutation, from an +/// `Camellia128Key>`. A message of any length goes +/// through `Camellia128Key>` and its declared-length pair instead. The +/// construction, the parameter rules (`NONCE_LEN` in `7..=13`, `TAG_LEN` one of 4, 6, .., 16), +/// the API and its security considerations are those of [`bouncycastle_cipher::modes::ccm`] and, +/// alias for alias, of `AES_CCM_128` in `bouncycastle-aes`; only the permutation differs. RFC 5528 +/// defines Camellia in CCM. +/// +/// # Usage Examples +/// +/// ``` +/// use bouncycastle_camellia::{Camellia128Key, CCM_NONCE_LEN, CCM_TAG_LEN}; +/// use bouncycastle_cipher::modes::CCM; +/// use bouncycastle_core::key_material::{KeyMaterial, KeyType}; +/// use bouncycastle_core::symmetric_key::{ +/// AeadDeclaredDecryptionKey, AeadDeclaredEncryptionKey, FromKeyMaterial, +/// }; +/// use bouncycastle_rng::HashDRBG_SHA512; +/// +/// let mut rng = HashDRBG_SHA512::new_from_os(); +/// let material = KeyMaterial::<16>::from_bytes_as_type(&[0x42; 16], KeyType::SymmetricCipherKey) +/// .expect("a 16-byte symmetric cipher key"); +/// let key = Camellia128Key::>::from_key_material(&material) +/// .expect("a valid Camellia-128 key"); +/// +/// let aad = b"header"; +/// let mut buf = *b"a message of no particular length"; +/// let (nonce, tag) = key.encrypt_detached_in_place(&mut rng, aad, &mut buf).expect("encryption"); +/// key.decrypt_detached_in_place(&nonce, aad, &mut buf, &tag).expect("decryption"); +/// assert_eq!(&buf, b"a message of no particular length"); +/// ``` +#[allow(non_camel_case_types)] +pub type Camellia_CCM_128< + 'k, + Dir, + const NONCE_LEN: usize, + const TAG_LEN: usize, + const AAD_LEN: usize, + const DATA_LEN: usize, +> = ::Select< + CcmPacketEncryptor<'k, Camellia128Internal, BLOCK_LEN, NONCE_LEN, TAG_LEN, AAD_LEN, DATA_LEN>, + CcmPacketDecryptor<'k, Camellia128Internal, BLOCK_LEN, NONCE_LEN, TAG_LEN, AAD_LEN, DATA_LEN>, +>; + +/// Camellia-192 in CCM mode. See [`Camellia_CCM_128`]. +#[allow(non_camel_case_types)] +pub type Camellia_CCM_192< + 'k, + Dir, + const NONCE_LEN: usize, + const TAG_LEN: usize, + const AAD_LEN: usize, + const DATA_LEN: usize, +> = ::Select< + CcmPacketEncryptor<'k, Camellia192Internal, BLOCK_LEN, NONCE_LEN, TAG_LEN, AAD_LEN, DATA_LEN>, + CcmPacketDecryptor<'k, Camellia192Internal, BLOCK_LEN, NONCE_LEN, TAG_LEN, AAD_LEN, DATA_LEN>, +>; + +/// Camellia-256 in CCM mode. See [`Camellia_CCM_128`]. +#[allow(non_camel_case_types)] +pub type Camellia_CCM_256< + 'k, + Dir, + const NONCE_LEN: usize, + const TAG_LEN: usize, + const AAD_LEN: usize, + const DATA_LEN: usize, +> = ::Select< + CcmPacketEncryptor<'k, Camellia256Internal, BLOCK_LEN, NONCE_LEN, TAG_LEN, AAD_LEN, DATA_LEN>, + CcmPacketDecryptor<'k, Camellia256Internal, BLOCK_LEN, NONCE_LEN, TAG_LEN, AAD_LEN, DATA_LEN>, +>; diff --git a/crypto/camellia/src/cfb.rs b/crypto/camellia/src/cfb.rs new file mode 100644 index 000000000..92e7f6d32 --- /dev/null +++ b/crypto/camellia/src/cfb.rs @@ -0,0 +1,72 @@ +//! Type aliases for Camellia (RFC 3713) in CFB mode (NIST SP 800-38A Sec 6.3). The docs are on +//! [`Camellia_CFB_128`], which the crate root re-exports. + +use crate::BLOCK_LEN; +use crate::hazmat::{Camellia128Internal, Camellia192Internal, Camellia256Internal}; +use bouncycastle_cipher::modes::Cfb; + +// Imports needed for docs +#[allow(unused_imports)] +use bouncycastle_core::symmetric_key::{SymmetricDecryptionKey, SymmetricEncryptionKey}; +// end of imports needed for docs + +/// Camellia-128 in CFB128 mode. `Dir` is [`bouncycastle_cipher::Encrypting`] or +/// [`bouncycastle_cipher::Decrypting`]; the wrong direction is a compile error, not a runtime +/// check. +/// +/// See `bouncycastle_cipher::modes::cfb` for the construction. The aliases are stream ciphers: +/// the data is a `&mut [u8]` of any length, encrypted or decrypted in place. They come from a key, +/// [`Camellia128Key`](crate::Camellia128Key) and friends, through the +/// [`SymmetricEncryptionKey`] / [`SymmetricDecryptionKey`] pair; the IV is one block, drawn from +/// the caller's RNG by encryption and returned, and there is no API for supplying one. +/// +/// The segment size is the full block, so these are **CFB128**. SP 800-38A's `s = 8` variant is a +/// different, non-interoperable mode with its own aliases -- +/// [`Camellia_CFB8_128`](crate::Camellia_CFB8_128) and friends -- and `s = 1` is not implemented; +/// see the `bouncycastle_cipher::modes::Cfb` docs. +/// +/// ``` +/// use bouncycastle_camellia::Camellia128Key; +/// use bouncycastle_cipher::modes::CFB; +/// use bouncycastle_core::key_material::{KeyMaterial, KeyType}; +/// use bouncycastle_core::symmetric_key::{FromKeyMaterial, SymmetricDecryptionKey}; +/// use bouncycastle_core::symmetric_key::SymmetricEncryptionKey; +/// use bouncycastle_core::traits::{StreamCipherDecryptor, StreamCipherEncryptor}; +/// use bouncycastle_rng::HashDRBG_SHA512; +/// +/// let mut rng = HashDRBG_SHA512::new_from_os(); +/// let material = KeyMaterial::<16>::from_bytes_as_type(&[0x42; 16], KeyType::SymmetricCipherKey) +/// .expect("a 16-byte symmetric cipher key"); +/// let key = Camellia128Key::::from_key_material(&material) +/// .expect("a valid Camellia-128 key"); +/// +/// // 47 bytes: a stream cipher does not need a whole number of blocks. +/// let message = [0u8; 47]; +/// let mut data = message; +/// let (_, iv) = key.encrypt_inplace(&mut rng, &mut data).unwrap(); +/// assert_ne!(data, message); +/// key.decrypt_inplace(&iv, &mut data).unwrap(); +/// assert_eq!(data, message); +/// +/// // Streaming, at any byte boundary: +/// let (mut enc, iv) = key.create_encryptor(&mut rng).unwrap(); +/// let mut first = [0u8; 5]; +/// let mut rest = [1u8; 30]; +/// enc.do_encrypt_inplace(&mut first).unwrap(); +/// enc.do_encrypt_inplace(&mut rest).unwrap(); +/// let mut dec = key.create_decryptor(&iv); +/// dec.do_decrypt_inplace(&mut first).unwrap(); +/// dec.do_decrypt_inplace(&mut rest).unwrap(); +/// assert_eq!(first, [0u8; 5]); +/// assert_eq!(rest, [1u8; 30]); +/// ``` +#[allow(non_camel_case_types)] +pub type Camellia_CFB_128<'k, Dir> = Cfb<'k, Camellia128Internal, Dir, BLOCK_LEN>; + +/// Camellia-192 in CFB128 mode. See [`Camellia_CFB_128`]. +#[allow(non_camel_case_types)] +pub type Camellia_CFB_192<'k, Dir> = Cfb<'k, Camellia192Internal, Dir, BLOCK_LEN>; + +/// Camellia-256 in CFB128 mode. See [`Camellia_CFB_128`]. +#[allow(non_camel_case_types)] +pub type Camellia_CFB_256<'k, Dir> = Cfb<'k, Camellia256Internal, Dir, BLOCK_LEN>; diff --git a/crypto/camellia/src/cfb8.rs b/crypto/camellia/src/cfb8.rs new file mode 100644 index 000000000..eeed79cf2 --- /dev/null +++ b/crypto/camellia/src/cfb8.rs @@ -0,0 +1,66 @@ +//! Type aliases for Camellia (RFC 3713) in CFB8 mode (NIST SP 800-38A Sec 6.3, `s = 8`). The docs +//! are on [`Camellia_CFB8_128`], which the crate root re-exports. + +use crate::BLOCK_LEN; +use crate::hazmat::{Camellia128Internal, Camellia192Internal, Camellia256Internal}; +use bouncycastle_cipher::modes::Cfb8; + +// Imports needed for docs +#[allow(unused_imports)] +use bouncycastle_core::symmetric_key::{SymmetricDecryptionKey, SymmetricEncryptionKey}; +// end of imports needed for docs + +/// Camellia-128 in CFB8 mode. `Dir` is [`bouncycastle_cipher::Encrypting`] or +/// [`bouncycastle_cipher::Decrypting`]; the wrong direction is a compile error, not a runtime +/// check. +/// +/// See `bouncycastle_cipher::modes::cfb8` for the construction. The aliases are stream ciphers with +/// a one-byte segment, and come from a key, [`Camellia128Key`](crate::Camellia128Key) and +/// friends, through the [`SymmetricEncryptionKey`] / [`SymmetricDecryptionKey`] pair; the IV is one +/// block, drawn from the caller's RNG by encryption and returned. +/// +/// CFB8 is a **different, non-interoperable mode** from CFB128, not a variant of it: their +/// ciphertexts differ from the second byte, and it costs a full Camellia call per byte, sixteen +/// times the work of [`Camellia_CFB_128`](crate::Camellia_CFB_128). See the +/// `bouncycastle_cipher::modes::Cfb8` docs for when that is the right trade. +/// +/// ``` +/// use bouncycastle_camellia::Camellia128Key; +/// use bouncycastle_cipher::modes::{CFB, CFB8}; +/// use bouncycastle_core::key_material::{KeyMaterial, KeyType}; +/// use bouncycastle_core::symmetric_key::{FromKeyMaterial, SymmetricDecryptionKey}; +/// use bouncycastle_core::symmetric_key::SymmetricEncryptionKey; +/// use bouncycastle_rng::HashDRBG_SHA512; +/// +/// let mut rng = HashDRBG_SHA512::new_from_os(); +/// let material = KeyMaterial::<16>::from_bytes_as_type(&[0x42; 16], KeyType::SymmetricCipherKey) +/// .expect("a 16-byte symmetric cipher key"); +/// let cfb8_key = Camellia128Key::::from_key_material(&material) +/// .expect("a valid Camellia-128 key"); +/// +/// // 5 bytes: CFB8's segment is one byte, so any length at all is fine. +/// let message = *b"hello"; +/// let mut data = message; +/// let (_, iv) = cfb8_key.encrypt_inplace(&mut rng, &mut data).unwrap(); +/// assert_ne!(data, message); +/// cfb8_key.decrypt_inplace(&iv, &mut data).unwrap(); +/// assert_eq!(data, message); +/// +/// // CFB8 and CFB128 are not interchangeable: same key material, same IV, different ciphertext. +/// let cfb_key = Camellia128Key::::from_key_material(&material).unwrap(); +/// let mut as_cfb8 = message; +/// let (_, iv) = cfb8_key.encrypt_inplace(&mut rng, &mut as_cfb8).unwrap(); +/// let mut as_cfb128 = as_cfb8; +/// cfb_key.decrypt_inplace(&iv, &mut as_cfb128).unwrap(); +/// assert_ne!(as_cfb128, message); +/// ``` +#[allow(non_camel_case_types)] +pub type Camellia_CFB8_128<'k, Dir> = Cfb8<'k, Camellia128Internal, Dir, BLOCK_LEN>; + +/// Camellia-192 in CFB8 mode. See [`Camellia_CFB8_128`]. +#[allow(non_camel_case_types)] +pub type Camellia_CFB8_192<'k, Dir> = Cfb8<'k, Camellia192Internal, Dir, BLOCK_LEN>; + +/// Camellia-256 in CFB8 mode. See [`Camellia_CFB8_128`]. +#[allow(non_camel_case_types)] +pub type Camellia_CFB8_256<'k, Dir> = Cfb8<'k, Camellia256Internal, Dir, BLOCK_LEN>; diff --git a/crypto/camellia/src/cmac.rs b/crypto/camellia/src/cmac.rs new file mode 100644 index 000000000..6f60e88bd --- /dev/null +++ b/crypto/camellia/src/cmac.rs @@ -0,0 +1,46 @@ +//! Type aliases for Camellia in CMAC (NIST SP 800-38B). The docs are on [`Camellia_CMAC_128`], which the +//! crate root re-exports. + +use crate::hazmat::{Camellia128Internal, Camellia192Internal, Camellia256Internal}; +use bouncycastle_cipher::modes::Cmac; + +/// Camellia-128 in CMAC: the `Cmac` worker of `bouncycastle-cipher` over the Camellia permutation, which +/// implements `MAC`, from an `Camellia128Key` of `KeyType::MACKey` material through +/// `MacGenerationKey` and `MacVerificationKey`. The construction, the key requirements, +/// truncation and the security considerations are those of [`bouncycastle_cipher::modes::cmac`] +/// and, alias for alias, of `AES_CMAC_128` in `bouncycastle-aes`; only the permutation differs. +/// +/// # Usage Examples +/// +/// ``` +/// use bouncycastle_camellia::Camellia256Key; +/// use bouncycastle_cipher::modes::CMAC; +/// use bouncycastle_core::key_material::{KeyMaterial, KeyType}; +/// use bouncycastle_core::symmetric_key::{FromKeyMaterial, MacGenerationKey, MacVerificationKey}; +/// use bouncycastle_core::traits::MAC; +/// +/// let material = KeyMaterial::<32>::from_bytes_as_type(&[0x42; 32], KeyType::MACKey).unwrap(); +/// let key = Camellia256Key::::from_key_material(&material).expect("a valid Camellia-256 MAC key"); +/// +/// let mut generator = key.create_generator(); +/// generator.do_update(b"a message that arrives "); +/// generator.do_update(b"in pieces"); +/// let tag = generator.do_final(); +/// assert!(key.verify(b"a message that arrives in pieces", &tag)); +/// assert!(!key.verify(b"another message", &tag)); +/// ``` +/// +/// # Memory Usage +/// +/// A key is the expanded schedule plus the two 16-byte subkeys: 240, 304 and 304 bytes for +/// Camellia-128, -192 and -256. A worker borrows that and adds 48 bytes, as under AES. +#[allow(non_camel_case_types)] +pub type Camellia_CMAC_128<'k> = Cmac<'k, Camellia128Internal, 16>; + +/// Camellia-192 in CMAC. See [`Camellia_CMAC_128`]. +#[allow(non_camel_case_types)] +pub type Camellia_CMAC_192<'k> = Cmac<'k, Camellia192Internal, 16>; + +/// Camellia-256 in CMAC. See [`Camellia_CMAC_128`]. +#[allow(non_camel_case_types)] +pub type Camellia_CMAC_256<'k> = Cmac<'k, Camellia256Internal, 16>; diff --git a/crypto/camellia/src/ctr.rs b/crypto/camellia/src/ctr.rs new file mode 100644 index 000000000..b07969d3b --- /dev/null +++ b/crypto/camellia/src/ctr.rs @@ -0,0 +1,87 @@ +//! Type aliases for Camellia (RFC 3713) in CTR mode (NIST SP 800-38A Sec 6.5). The docs are on +//! [`Camellia_CTR_128`], which the crate root re-exports. + +use crate::BLOCK_LEN; +use crate::hazmat::{Camellia128Internal, Camellia192Internal, Camellia256Internal}; +use bouncycastle_cipher::modes::Ctr; + +// Imports needed for docs +#[allow(unused_imports)] +use bouncycastle_core::symmetric_key::{SymmetricDecryptionKey, SymmetricEncryptionKey}; +// end of imports needed for docs + +/// The nonce length these aliases use, leaving a 4-byte counter. +pub const CTR_NONCE_LEN: usize = 12; + +/// Camellia-128 in CTR mode with a 12-byte nonce. `Dir` is [`bouncycastle_cipher::Encrypting`] or +/// [`bouncycastle_cipher::Decrypting`]; the wrong direction is a compile error, not a runtime +/// check. +/// +/// See `bouncycastle_cipher::modes::ctr` for the construction. The aliases are stream ciphers: +/// the data is a `&mut [u8]` of any length, encrypted or decrypted in place. They come from a key, +/// [`Camellia128Key`](crate::Camellia128Key) and friends, through the +/// [`SymmetricEncryptionKey`] / [`SymmetricDecryptionKey`] pair; the nonce is drawn from the +/// caller's RNG by encryption and returned, and there is no API for supplying one. +/// +/// # The nonce length is 12, so the counter is 4 +/// +/// `Ctr` splits the counter block into a nonce and a counter by the length of its init data, and +/// these aliases, like `CTR`'s defaults, choose a **12-byte nonce**, leaving the 4-byte counter +/// that is the mode's maximum. That allows 2^32 blocks -- 64 GiB -- in one message, and past it +/// the mode errors rather than repeating keystream. A shorter message limit in exchange for more +/// nonce bits is available by naming `CTR<13>`, `CTR<14>` or `CTR<15>` as the key's mode. +/// +/// RFC 5528, "Camellia Counter Mode and Camellia Counter with CBC-MAC Mode Algorithms", divides the +/// same 16-byte counter block differently -- a 4-octet nonce, an 8-octet IV and a 4-octet block +/// counter that starts at **one** rather than zero, which is the IPsec convention rather than a +/// property of Camellia. Its nine test vectors therefore begin one block into the keystream these +/// keys generate, so `tests/stream_mode_tests.rs` uses them to pin a reference CTR built from the +/// SP 800-38A Sec 6.5 equations over the permutation, and holds the keys to that reference on the +/// counter blocks they do produce. +/// +/// ``` +/// use bouncycastle_camellia::Camellia128Key; +/// use bouncycastle_cipher::modes::CTR; +/// use bouncycastle_core::key_material::{KeyMaterial, KeyType}; +/// use bouncycastle_core::symmetric_key::{FromKeyMaterial, SymmetricDecryptionKey}; +/// use bouncycastle_core::symmetric_key::SymmetricEncryptionKey; +/// use bouncycastle_core::traits::{StreamCipherDecryptor, StreamCipherEncryptor}; +/// use bouncycastle_rng::HashDRBG_SHA512; +/// +/// let mut rng = HashDRBG_SHA512::new_from_os(); +/// let material = KeyMaterial::<16>::from_bytes_as_type(&[0x42; 16], KeyType::SymmetricCipherKey) +/// .expect("a 16-byte symmetric cipher key"); +/// let key = Camellia128Key::::from_key_material(&material) +/// .expect("a valid Camellia-128 key"); +/// +/// // 47 bytes: a stream cipher does not need a whole number of blocks. +/// let message = [0u8; 47]; +/// let mut data = message; +/// let (_, nonce) = key.encrypt_inplace(&mut rng, &mut data).unwrap(); +/// assert_eq!(nonce.len(), 12); +/// assert_ne!(data, message); +/// key.decrypt_inplace(&nonce, &mut data).unwrap(); +/// assert_eq!(data, message); +/// +/// // Streaming, at any byte boundary: +/// let (mut enc, nonce) = key.create_encryptor(&mut rng).unwrap(); +/// let mut first = [0u8; 5]; +/// let mut rest = [1u8; 30]; +/// enc.do_encrypt_inplace(&mut first).unwrap(); +/// enc.do_encrypt_inplace(&mut rest).unwrap(); +/// let mut dec = key.create_decryptor(&nonce); +/// dec.do_decrypt_inplace(&mut first).unwrap(); +/// dec.do_decrypt_inplace(&mut rest).unwrap(); +/// assert_eq!(first, [0u8; 5]); +/// assert_eq!(rest, [1u8; 30]); +/// ``` +#[allow(non_camel_case_types)] +pub type Camellia_CTR_128<'k, Dir> = Ctr<'k, Camellia128Internal, Dir, BLOCK_LEN, CTR_NONCE_LEN>; + +/// Camellia-192 in CTR mode with a 12-byte nonce. See [`Camellia_CTR_128`]. +#[allow(non_camel_case_types)] +pub type Camellia_CTR_192<'k, Dir> = Ctr<'k, Camellia192Internal, Dir, BLOCK_LEN, CTR_NONCE_LEN>; + +/// Camellia-256 in CTR mode with a 12-byte nonce. See [`Camellia_CTR_128`]. +#[allow(non_camel_case_types)] +pub type Camellia_CTR_256<'k, Dir> = Ctr<'k, Camellia256Internal, Dir, BLOCK_LEN, CTR_NONCE_LEN>; diff --git a/crypto/camellia/src/gcm.rs b/crypto/camellia/src/gcm.rs new file mode 100644 index 000000000..21a447fe8 --- /dev/null +++ b/crypto/camellia/src/gcm.rs @@ -0,0 +1,42 @@ +//! Type aliases for Camellia in GCM (NIST SP 800-38D). The docs are on [`Camellia_GCM_128`], which the +//! crate root re-exports. + +use crate::hazmat::{Camellia128Internal, Camellia192Internal, Camellia256Internal}; +use bouncycastle_cipher::modes::Gcm; + +/// Camellia-128 in GCM with a 128-bit tag: the `Gcm` worker of `bouncycastle-cipher` over the Camellia +/// permutation, from an `Camellia128Key` through the `AeadEncryptionKey` / `AeadDecryptionKey` +/// pair. The construction, the API and its security considerations are those of +/// [`bouncycastle_cipher::modes::gcm`] and, alias for alias, of `AES_GCM_128` in +/// `bouncycastle-aes`; only the permutation differs. RFC 6367 defines Camellia in GCM +/// for TLS. +/// +/// # Usage Examples +/// +/// ``` +/// use bouncycastle_camellia::Camellia256Key; +/// use bouncycastle_cipher::modes::GCM; +/// use bouncycastle_core::key_material::{KeyMaterial, KeyType}; +/// use bouncycastle_core::symmetric_key::{AeadDecryptionKey, AeadEncryptionKey, FromKeyMaterial}; +/// use bouncycastle_rng::HashDRBG_SHA512; +/// +/// let mut rng = HashDRBG_SHA512::new_from_os(); +/// let material = KeyMaterial::<32>::from_bytes_as_type(&[0x42; 32], KeyType::SymmetricCipherKey) +/// .expect("a 32-byte symmetric cipher key"); +/// let key = Camellia256Key::::from_key_material(&material).expect("a valid Camellia-256 key"); +/// +/// let aad = b"header, sent in the clear"; +/// let (nonce, ciphertext, tag) = key.encrypt_detached(&mut rng, aad, b"message").expect("encryption"); +/// assert_eq!(key.decrypt_detached(&nonce, aad, &ciphertext, &tag).expect("decryption"), b"message"); +/// assert!(key.decrypt_detached(&nonce, b"other header", &ciphertext, &tag).is_err()); +/// ``` +#[allow(non_camel_case_types)] +pub type Camellia_GCM_128<'k, Dir> = Gcm<'k, Camellia128Internal, Dir, 16>; + +/// Camellia-192 in GCM with a 128-bit tag. See [`Camellia_GCM_128`]. +#[allow(non_camel_case_types)] +pub type Camellia_GCM_192<'k, Dir> = Gcm<'k, Camellia192Internal, Dir, 16>; + +/// Camellia-256 in GCM with a 128-bit tag. See [`Camellia_GCM_128`]. +#[allow(non_camel_case_types)] +pub type Camellia_GCM_256<'k, Dir> = Gcm<'k, Camellia256Internal, Dir, 16>; diff --git a/crypto/camellia/src/gmac.rs b/crypto/camellia/src/gmac.rs new file mode 100644 index 000000000..24b908775 --- /dev/null +++ b/crypto/camellia/src/gmac.rs @@ -0,0 +1,94 @@ +//! Type aliases for Camellia in GMAC (NIST SP 800-38D Sec 5.2), and the generator/verifier pair that +//! makes `Camellia128Key` and friends GMAC keys. The docs are on [`Camellia_GMAC_128`], which the +//! crate root re-exports. + +use crate::hazmat::{ + Camellia128Internal, Camellia192Internal, Camellia256Internal, CamelliaInternal, +}; +use crate::{CamelliaKey, CamelliaParams}; +use bouncycastle_cipher::modes::{GCM_NONCE_LEN, GMAC, Gmac, ModeNames}; +use bouncycastle_cipher::{Decrypting, Encrypting}; +use bouncycastle_core::errors::SymmetricCipherError; +use bouncycastle_core::hazmat::{BlockPermutation, NonceMacMode}; +use bouncycastle_core::traits::RNG; + +/// Camellia-128 in GMAC with a 128-bit tag: the `Gmac` worker of `bouncycastle-cipher` over the Camellia +/// permutation, `Dir` [`Encrypting`] to generate a tag or [`Decrypting`] to verify one. A GMAC +/// tag is bound to a nonce, so the pair is inherent on the key, `Camellia128Key` of +/// `KeyType::MACKey` material: [`create_generator`](CamelliaKey::create_generator) draws the nonce, +/// [`create_generator_nonce`](CamelliaKey::create_generator_nonce) takes the caller's, and +/// [`create_verifier`](CamelliaKey::create_verifier) checks under it. The construction, the nonce +/// rule and the security considerations are those of [`bouncycastle_cipher::modes::gmac`] and, +/// alias for alias, of `AES_GMAC_128` in `bouncycastle-aes`; only the permutation differs. +/// +/// # Usage Examples +/// +/// ``` +/// use bouncycastle_camellia::Camellia256Key; +/// use bouncycastle_cipher::modes::GMAC; +/// use bouncycastle_core::key_material::{KeyMaterial, KeyType}; +/// use bouncycastle_core::symmetric_key::FromKeyMaterial; +/// use bouncycastle_rng::HashDRBG_SHA512; +/// +/// let mut rng = HashDRBG_SHA512::new_from_os(); +/// let material = KeyMaterial::<32>::from_bytes_as_type(&[0x42; 32], KeyType::MACKey).unwrap(); +/// let key = Camellia256Key::::from_key_material(&material).expect("a valid Camellia-256 MAC key"); +/// +/// let (mut generator, nonce) = key.create_generator(&mut rng).expect("nonce draw"); +/// generator.do_update(b"a message that arrives "); +/// generator.do_update(b"in pieces"); +/// let tag = generator.do_final(); +/// +/// assert!(key.create_verifier(&nonce).verify(b"a message that arrives in pieces", &tag)); +/// assert!(!key.create_verifier(&nonce).verify(b"another message", &tag)); +/// ``` +#[allow(non_camel_case_types)] +pub type Camellia_GMAC_128<'k, Dir> = Gmac<'k, Camellia128Internal, Dir, 16>; + +/// Camellia-192 in GMAC with a 128-bit tag. See [`Camellia_GMAC_128`]. +#[allow(non_camel_case_types)] +pub type Camellia_GMAC_192<'k, Dir> = Gmac<'k, Camellia192Internal, Dir, 16>; + +/// Camellia-256 in GMAC with a 128-bit tag. See [`Camellia_GMAC_128`]. +#[allow(non_camel_case_types)] +pub type Camellia_GMAC_256<'k, Dir> = Gmac<'k, Camellia256Internal, Dir, 16>; + +// The pair is inherent on the key rather than a role trait, since a GMAC tag is bound to a nonce; +// one impl over every Camellia key length, forwarding to the mode's `NonceMacMode` impl as the role +// impls forward to theirs. +impl CamelliaKey> +where + P: CamelliaParams, + CamelliaInternal

: BlockPermutation<16> + ModeNames + Clone, +{ + /// A generator under a nonce drawn from `rng`, which is returned with it. + /// + /// # Errors + /// [`SymmetricCipherError::RNGError`] if the draw fails. + #[allow(clippy::type_complexity)] // the worker and its nonce, as the AES key returns them + pub fn create_generator<'k>( + &'k self, + rng: &mut dyn RNG, + ) -> Result< + (Gmac<'k, CamelliaInternal

, Encrypting, TAG_LEN>, [u8; GCM_NONCE_LEN]), + SymmetricCipherError, + > { + GMAC::::generate_init(&self.state, rng) + } + + /// A generator under the caller's nonce, which must not repeat under this key. + pub fn create_generator_nonce<'k>( + &'k self, + nonce: &[u8; GCM_NONCE_LEN], + ) -> Gmac<'k, CamelliaInternal

, Encrypting, TAG_LEN> { + GMAC::::generate_init_nonce(&self.state, nonce) + } + + /// A verifier under the nonce the tag was made under. + pub fn create_verifier<'k>( + &'k self, + nonce: &[u8; GCM_NONCE_LEN], + ) -> Gmac<'k, CamelliaInternal

, Decrypting, TAG_LEN> { + GMAC::::verify_init(&self.state, nonce) + } +} diff --git a/crypto/camellia/src/hazmat/camellia.rs b/crypto/camellia/src/hazmat/camellia.rs new file mode 100644 index 000000000..89e316987 --- /dev/null +++ b/crypto/camellia/src/hazmat/camellia.rs @@ -0,0 +1,385 @@ +//! The public engine types, and the encryption and decryption entry points (RFC 3713 Sec 2.3). + +use crate::round::rounds; +use crate::schedule::{ + Camellia128Params, Camellia192Params, Camellia256Params, CamelliaParams, expand, k, ke, kw, +}; +use crate::{BLOCK_LEN, LANES}; +use bouncycastle_cipher::modes::ModeNames; +use bouncycastle_core::errors::{KeyMaterialError, SymmetricCipherError}; +use bouncycastle_core::hazmat::{BlockPermutation, ElectronicCodeBook}; +use bouncycastle_core::key_material::{KeyMaterial, KeyMaterialTrait, KeyType}; +use bouncycastle_core::security_strength::SecurityStrength; +use bouncycastle_core::traits::Algorithm; +use bouncycastle_utils::secret::Secret; + +/// One Camellia block. +pub type Block = [u8; BLOCK_LEN]; + +/// The Camellia keyed permutation, parameterised by key length, constant-time: the engine under +/// [`CamelliaKey`](crate::CamelliaKey). +/// +/// Use the aliases [`Camellia128Internal`], [`Camellia192Internal`] and [`Camellia256Internal`] +/// rather than naming this directly. `P` is sealed to the three parameter sets of RFC 3713, so no +/// fourth instantiation exists. +/// +/// The only state is the subkeys, held in a [`Secret`] so that they are zeroized on drop and +/// redacted from `Debug`. There is no direction flag and no initialisation state: decryption is +/// encryption with the subkeys read in the swapped order of Sec 2.3.3, so both directions work +/// from the same stored schedule, and a constructed value is always ready to use -- there is no +/// `init()` or `reset()`, unlike an engine that lays the subkeys out differently depending on the +/// direction it is initialised for. +#[derive(Clone)] +pub struct CamelliaInternal { + schedule: Secret, +} + +// Written out rather than derived so that `P`, a marker type, need not be `PartialEq`. `Secret`'s +// equality inspects every byte of the schedule, so the time taken does not say where two differ. +impl PartialEq for CamelliaInternal

{ + fn eq(&self, other: &Self) -> bool { + self.schedule == other.schedule + } +} + +impl Eq for CamelliaInternal

{} + +/// Camellia-128: 16-byte key, 18 rounds (RFC 3713 Sec 2.3.1). +#[allow(non_camel_case_types)] +pub type Camellia128Internal = CamelliaInternal; +/// Camellia-192: 24-byte key, 24 rounds (RFC 3713 Sec 2.3.2). +#[allow(non_camel_case_types)] +pub type Camellia192Internal = CamelliaInternal; +/// Camellia-256: 32-byte key, 24 rounds (RFC 3713 Sec 2.3.2). +#[allow(non_camel_case_types)] +pub type Camellia256Internal = CamelliaInternal; + +impl CamelliaInternal

{ + /// Checks a key is fit to use before it is expanded. + /// + /// The key must be tagged [`KeyType::SymmetricCipherKey`], must be exactly `P::KEY_LEN` bytes + /// of the buffer, and must carry a [`SecurityStrength`] at least equal to its own length -- + /// which is what a key of this length from a correctly-instantiated RNG or KDF will have. + /// The checks exist to catch a key that arrived from somewhere it should not have: a seed + /// reused as a cipher key, or a 32-byte buffer holding material only derived at the 128-bit + /// strength. + /// + /// Takes `&dyn KeyMaterialTrait` so the three constructors, whose `KeyMaterial` capacities + /// differ, can share one implementation. + fn validate(key: &dyn KeyMaterialTrait) -> Result<(), SymmetricCipherError> { + if key.key_type() != KeyType::SymmetricCipherKey { + return Err(KeyMaterialError::InvalidKeyType( + "Camellia requires a key of type KeyType::SymmetricCipherKey.", + ) + .into()); + } + if key.key_len() != P::KEY_LEN { + return Err(KeyMaterialError::InvalidLength.into()); + } + if key.security_strength() < SecurityStrength::from_bytes(P::KEY_LEN) { + return Err(KeyMaterialError::SecurityStrength( + "The provided key has a lower security strength than the Camellia key length \ + implies.", + ) + .into()); + } + Ok(()) + } + + /// Encrypts four independent blocks in place (Sec 2.3.1 / Sec 2.3.2): the subkeys in the + /// order the schedule lists them. + /// + /// This is the natural unit of work. The S-box circuit substitutes 32 bytes per pass and a + /// round substitutes eight bytes per block, so four blocks fill it exactly; fewer blocks cost + /// the same. Modes whose blocks are independent -- CTR, and the decryption direction of CBC + /// and CFB -- reach it as the `BlockPermutation` four-block batch; CBC encryption cannot, + /// since its blocks are serially dependent. + /// + /// Infallible: a constructed [`CamelliaInternal`] is always usable and every input length is + /// fixed. + pub fn encrypt_4blocks(&self, blocks: &mut [Block; LANES]) { + let s = self.schedule.as_ref(); + rounds(blocks, P::ROUNDS, |i| kw(s, i), |i| k(s, i), |i| ke::

(s, i)); + } + + /// Decrypts four independent blocks in place (Sec 2.3.3): "the same way as the encryption + /// procedure by reversing the order of the subkeys", namely `kw1 <-> kw3`, `kw2 <-> kw4`, + /// `k_i <-> k_{n+1-i}` for `n` rounds, and `ke_i <-> ke_{m+1-i}` for `m` FL keys. See + /// [`CamelliaInternal::encrypt_4blocks`]. + pub fn decrypt_4blocks(&self, blocks: &mut [Block; LANES]) { + let s = self.schedule.as_ref(); + rounds( + blocks, + P::ROUNDS, + |i| kw(s, [3, 4, 1, 2][i - 1]), + |i| k(s, P::ROUNDS + 1 - i), + |i| ke::

(s, P::FL_KEYS + 1 - i), + ); + } + + /// Encrypts one block in place. + /// + /// The circuit always processes four lanes, so a single-block call puts the block in every + /// lane and discards three results: it does four blocks' worth of work. Use + /// [`CamelliaInternal::encrypt_4blocks`] where independent blocks + /// are available. + /// + /// Filling the spare lanes with copies costs exactly what zeros would, and buys a free + /// self-check: all four lanes must agree, which `debug_assert` verifies. It is not a security + /// property; the spare lanes are never returned either way. + pub(crate) fn encrypt_block(&self, block: &mut Block) { + let mut lanes = [*block; LANES]; + self.encrypt_4blocks(&mut lanes); + debug_assert!(lanes.iter().all(|b| *b == lanes[0]), "all lanes must agree"); + *block = lanes[0]; + } + + /// Decrypts one block in place. See [`BlockPermutation::encrypt_block`] for the four-lane + /// caveat. + pub(crate) fn decrypt_block(&self, block: &mut Block) { + let mut lanes = [*block; LANES]; + self.decrypt_4blocks(&mut lanes); + debug_assert!(lanes.iter().all(|b| *b == lanes[0]), "all lanes must agree"); + *block = lanes[0]; + } + + /// Encrypts two blocks in place, in lanes 0 and 1; the other two lanes carry copies of the + /// first and are discarded. Two blocks for the price of four, but twice as good as two + /// [`BlockPermutation::encrypt_block`] calls, which is why the trait method uses it. + pub(crate) fn encrypt_2blocks(&self, blocks: &mut [Block; 2]) { + let mut lanes = [blocks[0]; LANES]; + lanes[1] = blocks[1]; + self.encrypt_4blocks(&mut lanes); + *blocks = [lanes[0], lanes[1]]; + } + + /// Decrypts two blocks in place. See [`BlockPermutation::encrypt_2blocks`]. + pub(crate) fn decrypt_2blocks(&self, blocks: &mut [Block; 2]) { + let mut lanes = [blocks[0]; LANES]; + lanes[1] = blocks[1]; + self.decrypt_4blocks(&mut lanes); + *blocks = [lanes[0], lanes[1]]; + } +} + +impl Camellia128Internal { + /// Expands a 16-byte key into the Camellia-128 subkeys (Sec 2.2). + /// + /// # Errors + /// * [`KeyMaterialError::InvalidKeyType`] if the key is not [`KeyType::SymmetricCipherKey`]. + /// * [`KeyMaterialError::InvalidLength`] if the key is not 16 bytes long. + /// * [`KeyMaterialError::SecurityStrength`] if the key carries a strength below 128 bits. + pub(crate) fn new(key: &KeyMaterial<16>) -> Result { + Self::validate(key)?; + Ok(Self { schedule: expand::(key.ref_to_bytes()) }) + } +} + +impl Camellia192Internal { + /// Expands a 24-byte key into the Camellia-192 subkeys (Sec 2.2). + /// + /// # Errors + /// * [`KeyMaterialError::InvalidKeyType`] if the key is not [`KeyType::SymmetricCipherKey`]. + /// * [`KeyMaterialError::InvalidLength`] if the key is not 24 bytes long. + /// * [`KeyMaterialError::SecurityStrength`] if the key carries a strength below 128 bits. + pub(crate) fn new(key: &KeyMaterial<24>) -> Result { + Self::validate(key)?; + Ok(Self { schedule: expand::(key.ref_to_bytes()) }) + } +} + +impl Camellia256Internal { + /// Expands a 32-byte key into the Camellia-256 subkeys (Sec 2.2). + /// + /// # Errors + /// * [`KeyMaterialError::InvalidKeyType`] if the key is not [`KeyType::SymmetricCipherKey`]. + /// * [`KeyMaterialError::InvalidLength`] if the key is not 32 bytes long. + /// * [`KeyMaterialError::SecurityStrength`] if the key carries a strength below 128 bits. + pub(crate) fn new(key: &KeyMaterial<32>) -> Result { + Self::validate(key)?; + Ok(Self { schedule: expand::(key.ref_to_bytes()) }) + } +} + +impl Algorithm for Camellia128Internal { + const ALG_NAME: &'static str = Camellia128Params::ALG_NAME; + const MAX_SECURITY_STRENGTH: SecurityStrength = SecurityStrength::_128bit; +} + +impl Algorithm for Camellia192Internal { + const ALG_NAME: &'static str = Camellia192Params::ALG_NAME; + const MAX_SECURITY_STRENGTH: SecurityStrength = SecurityStrength::_192bit; +} + +impl Algorithm for Camellia256Internal { + const ALG_NAME: &'static str = Camellia256Params::ALG_NAME; + const MAX_SECURITY_STRENGTH: SecurityStrength = SecurityStrength::_256bit; +} + +// The three `ElectronicCodeBook` / `BlockPermutation` impl pairs are one-line delegations to the +// inherent methods above, +// written out longhand rather than generated because `cargo mutants` cannot see into macro bodies. +// +// Each fills the lanes in its pair and four-block methods: two blocks in two of the four lanes +// cost one circuit pass per round where two single-block calls would cost two, and four blocks +// are one full pass where two pair calls would be two. + +impl ElectronicCodeBook<16, BLOCK_LEN> for Camellia128Internal { + fn new(key: &KeyMaterial<16>) -> Result { + Camellia128Internal::new(key) + } +} + +impl BlockPermutation for Camellia128Internal { + fn encrypt_block(&self, block: &mut Block) { + CamelliaInternal::encrypt_block(self, block) + } + fn decrypt_block(&self, block: &mut Block) { + CamelliaInternal::decrypt_block(self, block) + } + fn encrypt_2blocks(&self, blocks: &mut [Block; 2]) { + CamelliaInternal::encrypt_2blocks(self, blocks) + } + fn decrypt_2blocks(&self, blocks: &mut [Block; 2]) { + CamelliaInternal::decrypt_2blocks(self, blocks) + } + fn encrypt_4blocks(&self, blocks: &mut [Block; LANES]) { + CamelliaInternal::encrypt_4blocks(self, blocks) + } + fn decrypt_4blocks(&self, blocks: &mut [Block; LANES]) { + CamelliaInternal::decrypt_4blocks(self, blocks) + } +} + +impl ElectronicCodeBook<24, BLOCK_LEN> for Camellia192Internal { + fn new(key: &KeyMaterial<24>) -> Result { + Camellia192Internal::new(key) + } +} + +impl BlockPermutation for Camellia192Internal { + fn encrypt_block(&self, block: &mut Block) { + CamelliaInternal::encrypt_block(self, block) + } + fn decrypt_block(&self, block: &mut Block) { + CamelliaInternal::decrypt_block(self, block) + } + fn encrypt_2blocks(&self, blocks: &mut [Block; 2]) { + CamelliaInternal::encrypt_2blocks(self, blocks) + } + fn decrypt_2blocks(&self, blocks: &mut [Block; 2]) { + CamelliaInternal::decrypt_2blocks(self, blocks) + } + fn encrypt_4blocks(&self, blocks: &mut [Block; LANES]) { + CamelliaInternal::encrypt_4blocks(self, blocks) + } + fn decrypt_4blocks(&self, blocks: &mut [Block; LANES]) { + CamelliaInternal::decrypt_4blocks(self, blocks) + } +} + +impl ElectronicCodeBook<32, BLOCK_LEN> for Camellia256Internal { + fn new(key: &KeyMaterial<32>) -> Result { + Camellia256Internal::new(key) + } +} + +impl BlockPermutation for Camellia256Internal { + fn encrypt_block(&self, block: &mut Block) { + CamelliaInternal::encrypt_block(self, block) + } + fn decrypt_block(&self, block: &mut Block) { + CamelliaInternal::decrypt_block(self, block) + } + fn encrypt_2blocks(&self, blocks: &mut [Block; 2]) { + CamelliaInternal::encrypt_2blocks(self, blocks) + } + fn decrypt_2blocks(&self, blocks: &mut [Block; 2]) { + CamelliaInternal::decrypt_2blocks(self, blocks) + } + fn encrypt_4blocks(&self, blocks: &mut [Block; LANES]) { + CamelliaInternal::encrypt_4blocks(self, blocks) + } + fn decrypt_4blocks(&self, blocks: &mut [Block; LANES]) { + CamelliaInternal::decrypt_4blocks(self, blocks) + } +} + +// Every mode is named: RFC 5528 defines Camellia in CTR and CCM and RFC 6367 in GCM, and the +// keys carry the matching role pairs, with GMAC's pair inherent on the key. +impl ModeNames for Camellia128Internal { + const CBC_ALG_NAME: &'static str = "Camellia_CBC_128"; + const CCM_ALG_NAME: &'static str = "Camellia_CCM_128"; + const CFB_ALG_NAME: &'static str = "Camellia_CFB_128"; + const CFB8_ALG_NAME: &'static str = "Camellia_CFB8_128"; + const CMAC_ALG_NAME: &'static str = "Camellia_CMAC_128"; + const CTR_ALG_NAME: &'static str = "Camellia_CTR_128"; + const ECB_ALG_NAME: &'static str = "Camellia_ECB_128"; + const GCM_ALG_NAME: &'static str = "Camellia_GCM_128"; + const GMAC_ALG_NAME: &'static str = "Camellia_GMAC_128"; + const KW_ALG_NAME: &'static str = "Camellia_KW_128"; + const KWP_ALG_NAME: &'static str = "Camellia_KWP_128"; +} + +impl ModeNames for Camellia192Internal { + const CBC_ALG_NAME: &'static str = "Camellia_CBC_192"; + const CCM_ALG_NAME: &'static str = "Camellia_CCM_192"; + const CFB_ALG_NAME: &'static str = "Camellia_CFB_192"; + const CFB8_ALG_NAME: &'static str = "Camellia_CFB8_192"; + const CMAC_ALG_NAME: &'static str = "Camellia_CMAC_192"; + const CTR_ALG_NAME: &'static str = "Camellia_CTR_192"; + const ECB_ALG_NAME: &'static str = "Camellia_ECB_192"; + const GCM_ALG_NAME: &'static str = "Camellia_GCM_192"; + const GMAC_ALG_NAME: &'static str = "Camellia_GMAC_192"; + const KW_ALG_NAME: &'static str = "Camellia_KW_192"; + const KWP_ALG_NAME: &'static str = "Camellia_KWP_192"; +} + +impl ModeNames for Camellia256Internal { + const CBC_ALG_NAME: &'static str = "Camellia_CBC_256"; + const CCM_ALG_NAME: &'static str = "Camellia_CCM_256"; + const CFB_ALG_NAME: &'static str = "Camellia_CFB_256"; + const CFB8_ALG_NAME: &'static str = "Camellia_CFB8_256"; + const CMAC_ALG_NAME: &'static str = "Camellia_CMAC_256"; + const CTR_ALG_NAME: &'static str = "Camellia_CTR_256"; + const ECB_ALG_NAME: &'static str = "Camellia_ECB_256"; + const GCM_ALG_NAME: &'static str = "Camellia_GCM_256"; + const GMAC_ALG_NAME: &'static str = "Camellia_GMAC_256"; + const KW_ALG_NAME: &'static str = "Camellia_KW_256"; + const KWP_ALG_NAME: &'static str = "Camellia_KWP_256"; +} + +impl core::fmt::Debug for CamelliaInternal

{ + /// Prints the algorithm name only. The subkeys are secret and are never formatted. + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_str(P::ALG_NAME) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_decryption_subkey_swap_is_section_2_3_3() { + // kw1 <-> kw3, kw2 <-> kw4; k_i <-> k_{n+1-i}; ke_i <-> ke_{m+1-i}. The table below is + // the RFC's, and the closures in decrypt_4blocks must implement exactly it. + let swap_kw = |i: usize| [3, 4, 1, 2][i - 1]; + assert_eq!([swap_kw(1), swap_kw(2), swap_kw(3), swap_kw(4)], [3, 4, 1, 2]); + // 128-bit key: k1 <-> k18 ... k9 <-> k10; ke1 <-> ke4, ke2 <-> ke3. + let n = Camellia128Params::ROUNDS; + let swapped: [usize; 18] = core::array::from_fn(|i| n + 1 - (i + 1)); + let expected: [usize; 18] = core::array::from_fn(|i| 18 - i); + assert_eq!(swapped, expected); + let m = Camellia128Params::FL_KEYS; + let swapped: [usize; 4] = core::array::from_fn(|i| m + 1 - (i + 1)); + assert_eq!(swapped, [4, 3, 2, 1]); + // 192- or 256-bit key: k1 <-> k24 ... k12 <-> k13; ke1 <-> ke6, ke2 <-> ke5, ke3 <-> ke4. + let n = Camellia256Params::ROUNDS; + assert_eq!(n + 1 - 1, 24); + assert_eq!(n + 1 - 12, 13); + let m = Camellia256Params::FL_KEYS; + let swapped: [usize; 6] = core::array::from_fn(|i| m + 1 - (i + 1)); + assert_eq!(swapped, [6, 5, 4, 3, 2, 1]); + } +} diff --git a/crypto/camellia/src/hazmat/mod.rs b/crypto/camellia/src/hazmat/mod.rs new file mode 100644 index 000000000..cd73e89fa --- /dev/null +++ b/crypto/camellia/src/hazmat/mod.rs @@ -0,0 +1,12 @@ +//! The raw Camellia permutation, [`CamelliaInternal`] and its three key-length aliases; see +//! [`bouncycastle_core::hazmat`] for what the path means and the supported uses. +//! +//! [`Camellia128Internal`] and its siblings transform exactly one block and are the primitive +//! under the modes in this crate, not a cipher for data; use +//! [`Camellia_CBC_128`](crate::Camellia_CBC_128) and the other mode aliases at the crate root. + +pub(crate) mod camellia; + +pub use camellia::{ + Camellia128Internal, Camellia192Internal, Camellia256Internal, CamelliaInternal, +}; diff --git a/crypto/camellia/src/key.rs b/crypto/camellia/src/key.rs new file mode 100644 index 000000000..eb61f9a96 --- /dev/null +++ b/crypto/camellia/src/key.rs @@ -0,0 +1,522 @@ +//! Camellia key objects: a key bound to one Camellia variant and one mode, validated and expanded +//! once, from which the mode's encryptors and decryptors are made. The docs are on [`CamelliaKey`], +//! which the crate root re-exports. + +use crate::hazmat::{ + Camellia128Internal, Camellia192Internal, Camellia256Internal, CamelliaInternal, +}; +use crate::schedule::{Camellia128Params, Camellia192Params, Camellia256Params, CamelliaParams}; +use bouncycastle_core::errors::{KeyMaterialError, SymmetricCipherError}; +use bouncycastle_core::hazmat::{ + AeadDeclaredDecryptMode, AeadDeclaredEncryptMode, AeadDecryptMode, AeadEncryptMode, + BlockDecryptMode, BlockEncryptMode, EcbDecryptMode, EcbDecryptionKey, EcbEncryptMode, + EcbEncryptionKey, KeyUnwrapMode, KeyWrapMode, MacMode, Mode, SymmetricDecryptMode, + SymmetricEncryptMode, do_hazardous_operations, +}; +use bouncycastle_core::key_material::{KeyMaterial, KeyMaterialTrait, KeyType}; +use bouncycastle_core::symmetric_key::{ + AeadDeclaredDecryptionKey, AeadDeclaredEncryptionKey, AeadDecryptionKey, AeadEncryptionKey, + BlockDecryptionKey, BlockEncryptionKey, FromKeyMaterial, KeyUnwrappingKey, KeyWrappingKey, + MacGenerationKey, MacVerificationKey, SymmetricDecryptionKey, SymmetricEncryptionKey, +}; +use bouncycastle_core::traits::RNG; + +/// A Camellia key for the mode `M`, parameterised by key length. Use the aliases +/// [`Camellia128Key`], [`Camellia192Key`] and [`Camellia256Key`] rather than naming this directly. +/// +/// The only state is the mode's per-key state, which holds the expanded schedule in a `Secret` +/// and so is zeroized on drop; the key has no `Debug` and no way to read the material back. +/// +/// [`Camellia128Key`], [`Camellia192Key`] and [`Camellia256Key`] are one type each per +/// mode `M`, as `AES128Key` and friends are in `bouncycastle-aes`: the key holds the mode's +/// per-key state, the workers it hands out borrow it, and which role pair a key carries is decided +/// by its mode: the symmetric pair for the stream modes and the padded block modes (`CFB`, `CFB8`, +/// `CTR` at any nonce length, `CBC`, `CBC`, `ECB`, `ECB`), +/// the block pair for `CBC`, the `hazmat` ECB pair for `ECB`, the AEAD pairs for +/// `GCM`, `CCM` and `CCM_Packet`, the MAC pair for `CMAC`, the key-wrap pair for `KW` and `KWP`, +/// and GMAC's nonce-bound generator and verifier as inherent methods. The crate names the workers +/// of CBC, CFB, CFB8, CTR, GCM, CCM, CMAC, GMAC and KW as the `Camellia_*` aliases; the rest are +/// reached by naming the mode. +/// +/// # Usage Examples +/// +/// ``` +/// use bouncycastle_camellia::Camellia256Key; +/// use bouncycastle_cipher::modes::CBC; +/// use bouncycastle_cipher::padding::PKCS7; +/// use bouncycastle_core::key_material::{KeyMaterial, KeyType}; +/// use bouncycastle_core::symmetric_key::{FromKeyMaterial, SymmetricDecryptionKey}; +/// use bouncycastle_core::symmetric_key::SymmetricEncryptionKey; +/// use bouncycastle_rng::HashDRBG_SHA512; +/// +/// let mut rng = HashDRBG_SHA512::new_from_os(); // one RNG, held across messages +/// let material = KeyMaterial::<32>::from_bytes_as_type(&[0x42; 32], KeyType::SymmetricCipherKey) +/// .expect("a 32-byte symmetric cipher key"); +/// let key = Camellia256Key::>::from_key_material(&material) +/// .expect("a valid Camellia-256 key"); +/// +/// let (iv, ciphertext) = key.encrypt(&mut rng, b"a message of no particular length").unwrap(); +/// assert_eq!(key.decrypt(&iv, &ciphertext).unwrap(), b"a message of no particular length"); +/// ``` +/// +/// # Memory Usage +/// +/// A key is its mode's per-key state: the expanded schedule, 208, 272 or 272 bytes for +/// Camellia-128, -192 and -256, plus whatever the mode keeps per key (16 bytes of hash subkey +/// under `GCM` and `GMAC`, 32 bytes of subkeys under `CMAC`). The cost is paid per key, not per +/// message. +pub struct CamelliaKey>> { + pub(crate) state: M::KeyState, +} + +/// A Camellia-128 key for the mode `M`: 16 bytes of material, expanded to the 18-round subkeys. +#[allow(non_camel_case_types)] +pub type Camellia128Key = CamelliaKey; +/// A Camellia-192 key for the mode `M`: 24 bytes of material, expanded to the 24-round subkeys. +#[allow(non_camel_case_types)] +pub type Camellia192Key = CamelliaKey; +/// A Camellia-256 key for the mode `M`: 32 bytes of material, expanded to the 24-round subkeys. +#[allow(non_camel_case_types)] +pub type Camellia256Key = CamelliaKey; + +// Written out rather than derived so that `M`, a marker type, need not be `Clone`. +impl>> Clone for CamelliaKey { + fn clone(&self) -> Self { + Self { state: self.state.clone() } + } +} + +// Likewise for equality: two keys are equal when their mode states are, which every state over +// the engine decides in constant time, so the comparison follows the material without exposing it. +impl>> PartialEq for CamelliaKey +where + M::KeyState: PartialEq, +{ + fn eq(&self, other: &Self) -> bool { + self.state == other.state + } +} + +impl Eq for CamelliaKey +where + P: CamelliaParams, + M: Mode>, + M::KeyState: Eq, +{ +} + +/// The key-type check the mode asks for (`Mode::KEY_TYPE`), ahead of the permutation's own +/// validation. +fn check_key_type( + key: &dyn KeyMaterialTrait, + expected: KeyType, +) -> Result<(), SymmetricCipherError> { + if key.key_type() != expected { + return Err(KeyMaterialError::InvalidKeyType( + "The key is not of the KeyType this mode requires.", + ) + .into()); + } + Ok(()) +} + +/// The permutation accepts only a `SymmetricCipherKey`, so a MAC mode's key -- already checked to +/// be the `MACKey` the mode asks for -- is handed to it as a copy retagged at the same strength, +/// used for nothing else. The strength check in the permutation's constructor still applies. +fn as_cipher_key( + key: &KeyMaterial, +) -> Result, SymmetricCipherError> { + let mut cipher_key = + KeyMaterial::::from_bytes_as_type(key.ref_to_bytes(), KeyType::SymmetricCipherKey)?; + do_hazardous_operations(&mut cipher_key, |k| { + k.set_key_type(KeyType::SymmetricCipherKey)?; + k.set_security_strength(key.security_strength()) + })?; + Ok(cipher_key) +} + +// The constructors are implemented per key length rather than once over `P`, because stable Rust +// cannot name `KeyMaterial<{ P::KEY_LEN }>` in a generic signature; the fixed-capacity argument +// is what makes a wrong-length key a compile error rather than a runtime one. + +impl> FromKeyMaterial<16> for Camellia128Key { + const KEY_TYPE: KeyType = M::KEY_TYPE; + + /// Validates and expands a 16-byte key: the key type the mode asks for, then the + /// permutation's own checks. + /// + /// # Errors + /// * [`KeyMaterialError::InvalidKeyType`] if the key is not of [`Self::KEY_TYPE`]: the + /// `SymmetricCipherKey` a cipher mode asks for, or the `MACKey` a MAC mode does. + /// * [`KeyMaterialError::InvalidLength`] if the key is not 16 bytes long. + /// * [`KeyMaterialError::SecurityStrength`] if the key carries a strength below 128 bits. + fn from_key_material(key: &KeyMaterial<16>) -> Result { + check_key_type(key, M::KEY_TYPE)?; + let perm = match M::KEY_TYPE { + KeyType::SymmetricCipherKey => Camellia128Internal::new(key)?, + _ => Camellia128Internal::new(&as_cipher_key(key)?)?, + }; + Ok(Self { state: M::key_state(perm) }) + } +} + +impl> FromKeyMaterial<24> for Camellia192Key { + const KEY_TYPE: KeyType = M::KEY_TYPE; + + /// Validates and expands a 24-byte key; the errors are those of the 16-byte form, at 24 + /// bytes and 192 bits. + fn from_key_material(key: &KeyMaterial<24>) -> Result { + check_key_type(key, M::KEY_TYPE)?; + let perm = match M::KEY_TYPE { + KeyType::SymmetricCipherKey => Camellia192Internal::new(key)?, + _ => Camellia192Internal::new(&as_cipher_key(key)?)?, + }; + Ok(Self { state: M::key_state(perm) }) + } +} + +impl> FromKeyMaterial<32> for Camellia256Key { + const KEY_TYPE: KeyType = M::KEY_TYPE; + + /// Validates and expands a 32-byte key; the errors are those of the 16-byte form, at 32 + /// bytes and 256 bits. + fn from_key_material(key: &KeyMaterial<32>) -> Result { + check_key_type(key, M::KEY_TYPE)?; + let perm = match M::KEY_TYPE { + KeyType::SymmetricCipherKey => Camellia256Internal::new(key)?, + _ => Camellia256Internal::new(&as_cipher_key(key)?)?, + }; + Ok(Self { state: M::key_state(perm) }) + } +} + +// The role impls forward to whichever mode traits `M` implements over this permutation, so which +// roles a key type carries is decided by its mode, exactly as for `AESKey`. They are per crate +// rather than a blanket in `core` because the key state leaves the key only through here. + +impl + SymmetricEncryptionKey for CamelliaKey +where + P: CamelliaParams, + M: SymmetricEncryptMode, KEY_LEN, INIT_DATA_LEN, FINAL_LEN>, +{ + type Encryptor<'k> + = M::Encryptor<'k> + where + Self: 'k; + + fn create_encryptor<'k>( + &'k self, + rng: &mut dyn RNG, + ) -> Result<(Self::Encryptor<'k>, [u8; INIT_DATA_LEN]), SymmetricCipherError> { + M::encrypt_init(&self.state, rng) + } +} + +impl + SymmetricDecryptionKey for CamelliaKey +where + P: CamelliaParams, + M: SymmetricDecryptMode, KEY_LEN, INIT_DATA_LEN, FINAL_LEN>, +{ + type Decryptor<'k> + = M::Decryptor<'k> + where + Self: 'k; + + fn create_decryptor<'k>(&'k self, init_data: &[u8; INIT_DATA_LEN]) -> Self::Decryptor<'k> { + M::decrypt_init(&self.state, init_data) + } +} + +impl + BlockEncryptionKey for CamelliaKey +where + P: CamelliaParams, + M: BlockEncryptMode, KEY_LEN, INIT_DATA_LEN, BLOCK_LEN>, +{ + type Encryptor<'k> + = M::Encryptor<'k> + where + Self: 'k; + + fn create_encryptor<'k>( + &'k self, + rng: &mut dyn RNG, + ) -> Result<(Self::Encryptor<'k>, [u8; INIT_DATA_LEN]), SymmetricCipherError> { + M::encrypt_init(&self.state, rng) + } +} + +impl + BlockDecryptionKey for CamelliaKey +where + P: CamelliaParams, + M: BlockDecryptMode, KEY_LEN, INIT_DATA_LEN, BLOCK_LEN>, +{ + type Decryptor<'k> + = M::Decryptor<'k> + where + Self: 'k; + + fn create_decryptor<'k>(&'k self, init_data: &[u8; INIT_DATA_LEN]) -> Self::Decryptor<'k> { + M::decrypt_init(&self.state, init_data) + } +} + +impl< + P, + M, + const KEY_LEN: usize, + const NONCE_LEN: usize, + const TAG_LEN: usize, + const FINAL_LEN: usize, +> AeadEncryptionKey for CamelliaKey +where + P: CamelliaParams, + M: AeadEncryptMode, KEY_LEN, NONCE_LEN, TAG_LEN, FINAL_LEN>, +{ + type Encryptor<'k> + = M::Encryptor<'k> + where + Self: 'k; + + fn create_encryptor<'k>( + &'k self, + rng: &mut dyn RNG, + ) -> Result<(Self::Encryptor<'k>, [u8; NONCE_LEN]), SymmetricCipherError> { + M::encrypt_init(&self.state, rng) + } + + fn create_encryptor_nonce<'k>(&'k self, nonce: &[u8; NONCE_LEN]) -> Self::Encryptor<'k> { + M::encrypt_init_nonce(&self.state, nonce) + } + + // Forwarded rather than left to the trait's provided body so that a mode can override it: + // CCM's streaming worker is fixed-frame, and its in-place one-shot goes another way. + fn encrypt_detached_in_place( + &self, + rng: &mut dyn RNG, + aad: &[u8], + buf: &mut [u8], + ) -> Result<([u8; NONCE_LEN], [u8; TAG_LEN]), SymmetricCipherError> { + M::encrypt_detached_in_place(&self.state, rng, aad, buf) + } + + fn encrypt_detached_in_place_nonce( + &self, + nonce: &[u8; NONCE_LEN], + aad: &[u8], + buf: &mut [u8], + ) -> Result<[u8; TAG_LEN], SymmetricCipherError> { + M::encrypt_detached_in_place_nonce(&self.state, nonce, aad, buf) + } +} + +impl< + P, + M, + const KEY_LEN: usize, + const NONCE_LEN: usize, + const TAG_LEN: usize, + const FINAL_LEN: usize, +> AeadDecryptionKey for CamelliaKey +where + P: CamelliaParams, + M: AeadDecryptMode, KEY_LEN, NONCE_LEN, TAG_LEN, FINAL_LEN>, +{ + type Decryptor<'k> + = M::Decryptor<'k> + where + Self: 'k; + + fn create_decryptor<'k>(&'k self, nonce: &[u8; NONCE_LEN]) -> Self::Decryptor<'k> { + M::decrypt_init(&self.state, nonce) + } + + fn decrypt_detached_in_place( + &self, + nonce: &[u8; NONCE_LEN], + aad: &[u8], + buf: &mut [u8], + tag: &[u8; TAG_LEN], + ) -> Result<(), SymmetricCipherError> { + M::decrypt_detached_in_place(&self.state, nonce, aad, buf, tag) + } +} + +impl< + P, + M, + const KEY_LEN: usize, + const NONCE_LEN: usize, + const TAG_LEN: usize, + const FINAL_LEN: usize, +> AeadDeclaredEncryptionKey for CamelliaKey +where + P: CamelliaParams, + M: AeadDeclaredEncryptMode, KEY_LEN, NONCE_LEN, TAG_LEN, FINAL_LEN>, +{ + type Encryptor<'k> + = M::Encryptor<'k> + where + Self: 'k; + + fn create_encryptor<'k>( + &'k self, + rng: &mut dyn RNG, + aad_len: usize, + payload_len: usize, + ) -> Result<(Self::Encryptor<'k>, [u8; NONCE_LEN]), SymmetricCipherError> { + M::encrypt_init(&self.state, rng, aad_len, payload_len) + } + + fn create_encryptor_nonce<'k>( + &'k self, + nonce: &[u8; NONCE_LEN], + aad_len: usize, + payload_len: usize, + ) -> Result, SymmetricCipherError> { + M::encrypt_init_nonce(&self.state, nonce, aad_len, payload_len) + } + + // Forwarded so that the mode's own in-place path is the one that runs. + fn encrypt_detached_in_place( + &self, + rng: &mut dyn RNG, + aad: &[u8], + buf: &mut [u8], + ) -> Result<([u8; NONCE_LEN], [u8; TAG_LEN]), SymmetricCipherError> { + M::encrypt_detached_in_place(&self.state, rng, aad, buf) + } + + fn encrypt_detached_in_place_nonce( + &self, + nonce: &[u8; NONCE_LEN], + aad: &[u8], + buf: &mut [u8], + ) -> Result<[u8; TAG_LEN], SymmetricCipherError> { + M::encrypt_detached_in_place_nonce(&self.state, nonce, aad, buf) + } +} + +impl< + P, + M, + const KEY_LEN: usize, + const NONCE_LEN: usize, + const TAG_LEN: usize, + const FINAL_LEN: usize, +> AeadDeclaredDecryptionKey for CamelliaKey +where + P: CamelliaParams, + M: AeadDeclaredDecryptMode, KEY_LEN, NONCE_LEN, TAG_LEN, FINAL_LEN>, +{ + type Decryptor<'k> + = M::Decryptor<'k> + where + Self: 'k; + + fn create_decryptor<'k>( + &'k self, + nonce: &[u8; NONCE_LEN], + aad_len: usize, + payload_len: usize, + ) -> Result, SymmetricCipherError> { + M::decrypt_init(&self.state, nonce, aad_len, payload_len) + } + + fn decrypt_detached_in_place( + &self, + nonce: &[u8; NONCE_LEN], + aad: &[u8], + buf: &mut [u8], + tag: &[u8; TAG_LEN], + ) -> Result<(), SymmetricCipherError> { + M::decrypt_detached_in_place(&self.state, nonce, aad, buf, tag) + } +} + +impl EcbEncryptionKey + for CamelliaKey +where + P: CamelliaParams, + M: EcbEncryptMode, KEY_LEN, BLOCK_LEN>, +{ + type Encryptor<'k> + = M::Encryptor<'k> + where + Self: 'k; + + fn create_encryptor<'k>(&'k self) -> Self::Encryptor<'k> { + M::encrypt_init(&self.state) + } +} + +impl EcbDecryptionKey + for CamelliaKey +where + P: CamelliaParams, + M: EcbDecryptMode, KEY_LEN, BLOCK_LEN>, +{ + type Decryptor<'k> + = M::Decryptor<'k> + where + Self: 'k; + + fn create_decryptor<'k>(&'k self) -> Self::Decryptor<'k> { + M::decrypt_init(&self.state) + } +} + +impl>> MacGenerationKey for CamelliaKey { + type Generator<'k> + = M::Worker<'k> + where + Self: 'k; + + fn create_generator<'k>(&'k self) -> Self::Generator<'k> { + M::mac_init(&self.state) + } +} + +impl>> MacVerificationKey for CamelliaKey { + type Verifier<'k> + = M::Worker<'k> + where + Self: 'k; + + fn create_verifier<'k>(&'k self) -> Self::Verifier<'k> { + M::mac_init(&self.state) + } +} + +impl KeyWrappingKey for CamelliaKey +where + P: CamelliaParams, + M: KeyWrapMode, KEK_LEN>, +{ + type Wrapper<'k> + = M::Wrapper<'k> + where + Self: 'k; + + fn create_wrapper<'k>(&'k self) -> Self::Wrapper<'k> { + M::wrap_init(&self.state) + } +} + +impl KeyUnwrappingKey for CamelliaKey +where + P: CamelliaParams, + M: KeyUnwrapMode, KEK_LEN>, +{ + type Unwrapper<'k> + = M::Unwrapper<'k> + where + Self: 'k; + + fn create_unwrapper<'k>(&'k self) -> Self::Unwrapper<'k> { + M::unwrap_init(&self.state) + } +} diff --git a/crypto/camellia/src/kw.rs b/crypto/camellia/src/kw.rs new file mode 100644 index 000000000..c3215a389 --- /dev/null +++ b/crypto/camellia/src/kw.rs @@ -0,0 +1,56 @@ +//! Type aliases for Camellia Key Wrap, KW (NIST SP 800-38F Sec 6.2 over the Camellia +//! permutation; RFC 3657 Sec 3). The docs are on [`Camellia_KW_128`], which the crate root +//! re-exports. + +use crate::hazmat::{Camellia128Internal, Camellia192Internal, Camellia256Internal}; +use bouncycastle_cipher::modes::Kw; + +/// Camellia-128 Key Wrap: the `Kw` worker of `bouncycastle-cipher` over the Camellia +/// permutation, which implements `KeyWrapper` and `KeyUnwrapper`, from a `Camellia128Key` +/// of `KeyType::SymmetricCipherKey` material through `KeyWrappingKey` and `KeyUnwrappingKey`. +/// The construction, the length rules, the one-shots and the security considerations are those +/// of [`bouncycastle_cipher::modes::kw`] and, alias for alias, of `AES_KW_128` in +/// `bouncycastle-aes`; only the permutation differs. +/// +/// RFC 3657 Sec 3 defines Camellia key wrapping as the RFC 3394 algorithm over Camellia, and +/// Sec 2 names it: `id-camellia128-wrap`, `id-camellia192-wrap` and `id-camellia256-wrap` are +/// 1.2.392.200011.61.1.1.3.2 to .4. No padded form is specified for Camellia; a +/// `Camellia128Key` works all the same, but carries no identifier. +/// +/// # Usage Examples +/// +/// ``` +/// use bouncycastle_camellia::Camellia256Key; +/// use bouncycastle_cipher::modes::KW; +/// use bouncycastle_core::key_material::{KeyMaterial, KeyType}; +/// use bouncycastle_core::symmetric_key::{FromKeyMaterial, KeyUnwrappingKey, KeyWrappingKey}; +/// +/// let material = KeyMaterial::<32>::from_bytes_as_type(&[0x42; 32], KeyType::SymmetricCipherKey) +/// .expect("a 32-byte symmetric cipher key"); +/// let kek = Camellia256Key::::from_key_material(&material).expect("a valid Camellia-256 KEK"); +/// +/// // A 16-byte key wraps to 24 bytes; any other pair of lengths is a compile error. +/// let key_to_wrap = [0x5Au8; 16]; +/// let wrapped: [u8; 24] = kek.wrap_key(&key_to_wrap).expect("wrapping"); +/// assert_eq!(*kek.unwrap_key::<16, 24>(&wrapped).expect("unwrapping"), key_to_wrap); +/// +/// // Lengths known only at run time, through the allocating one-shots. +/// let wrapped = kek.wrap(&[0x5Au8; 40]).expect("wrapping"); +/// assert_eq!(kek.unwrap(&wrapped).expect("unwrapping"), [0x5Au8; 40]); +/// ``` +/// +/// # Memory Usage +/// +/// A key is the expanded schedule: 208, 272 and 272 bytes for Camellia-128, -192 and -256. A +/// worker is the borrow of it, one pointer, and the wrapping function's scratch is one block on +/// the stack; the data is wrapped and unwrapped in the caller's buffers. +#[allow(non_camel_case_types)] +pub type Camellia_KW_128<'k> = Kw<'k, Camellia128Internal>; + +/// Camellia-192 Key Wrap. See [`Camellia_KW_128`]. +#[allow(non_camel_case_types)] +pub type Camellia_KW_192<'k> = Kw<'k, Camellia192Internal>; + +/// Camellia-256 Key Wrap. See [`Camellia_KW_128`]. +#[allow(non_camel_case_types)] +pub type Camellia_KW_256<'k> = Kw<'k, Camellia256Internal>; diff --git a/crypto/camellia/src/lib.rs b/crypto/camellia/src/lib.rs new file mode 100644 index 000000000..3a7717359 --- /dev/null +++ b/crypto/camellia/src/lib.rs @@ -0,0 +1,353 @@ +//! A constant-time, table-free, low-memory Camellia block cipher engine (RFC 3713), ported from +//! Bouncy Castle Java's `CamelliaEngine` / `CamelliaLightEngine`. +//! +//! This crate provides Camellia -- a 128-bit block cipher with 128-, 192- and 256-bit keys, +//! designed by NTT and Mitsubishi Electric, selected by the EU NESSIE project and Japan's CRYPTREC, +//! and described in RFC 3713, which is the specification every comment in this crate cites -- +//! under the library's key objects: [`Camellia128Key`], [`Camellia192Key`] and +//! [`Camellia256Key`], a key bound to one mode `M`, validated and expanded once, handing out +//! that mode's encryptors and decryptors. The engines underneath, [`Camellia128Internal`] and +//! friends, evaluate the S-boxes as a Boolean circuit over bit-planes rather than looking them up +//! in tables, so they are constant-time and carry no tables at all; the planes are 32 bits wide so +//! that the working set stays small, which is what "lowmemory" means here. See [Design](#design). +//! +//! An engine is a *permutation*, not a cipher you can encrypt data with, which is why it lives +//! under [`hazmat`]. See [Security Considerations](#-security-considerations-). +//! +//! # Usage Examples +//! +//! ## Modes of operation +//! +//! A key is built once, under a mode from `bouncycastle_cipher::modes`, and used for as many +//! messages as needed: `CBC` for CBC (NIST SP 800-38A Sec 6.2) with PKCS#7 padding, `CFB` +//! for CFB128 (Sec 6.3), `CFB8` for the `s = 8` segment size, a different and non-interoperable +//! mode costing one Camellia call per byte, and `CTR` for CTR (Sec 6.5) with a 12-byte nonce and +//! a 4-byte counter; `GCM` and `CCM` for the authenticated modes (NIST SP 800-38D and +//! 800-38C; RFC 6367 and RFC 5528 define them over Camellia), `CMAC` and `GMAC` for the MACs, and +//! `KW` for key wrap (NIST SP 800-38F; RFC 3657 defines it over Camellia). The aliases +//! [`Camellia_CBC_128`], [`Camellia_CFB_128`], [`Camellia_CFB8_128`], [`Camellia_CTR_128`], +//! [`Camellia_GCM_128`], [`Camellia_CCM_128`], [`Camellia_CMAC_128`], [`Camellia_GMAC_128`], +//! [`Camellia_KW_128`] and their `_192` / `_256` siblings name the workers the keys hand out. +//! +//! CBC is a block cipher, so it is defined only on whole blocks and the key's mode carries a +//! padding scheme to bridge the difference; the CFB modes and CTR are stream ciphers and take any +//! length with no padding at all; GCM and CCM authenticate as well as encrypt, and are the modes +//! to prefer. See the `bouncycastle_cipher::modes` crate docs for the comparison. +//! +//! ``` +//! use bouncycastle_camellia::Camellia256Key; +//! use bouncycastle_cipher::modes::CBC; +//! use bouncycastle_cipher::padding::PKCS7; +//! use bouncycastle_core::key_material::{KeyMaterial, KeyType}; +//! use bouncycastle_core::symmetric_key::{FromKeyMaterial, SymmetricDecryptionKey}; +//! use bouncycastle_core::symmetric_key::SymmetricEncryptionKey; +//! use bouncycastle_rng::HashDRBG_SHA512; +//! +//! let mut rng = HashDRBG_SHA512::new_from_os(); // one RNG, held across messages +//! let material = KeyMaterial::<32>::from_bytes_as_type(&[0x42; 32], KeyType::SymmetricCipherKey) +//! .expect("a 32-byte symmetric cipher key"); +//! let key = Camellia256Key::>::from_key_material(&material) +//! .expect("a valid Camellia-256 key"); +//! +//! // Any length: PKCS#7 pads it out to whole blocks, so 50 bytes is as good as 48. +//! let plaintext = [0x5Au8; 50]; +//! +//! // The IV is drawn from `rng` and returned; there is no API for supplying one. +//! let (iv, ciphertext) = key.encrypt(&mut rng, &plaintext).expect("encryption"); +//! assert_eq!(ciphertext.len(), 64, "50 bytes padded out to four blocks"); +//! +//! let recovered = key.decrypt(&iv, &ciphertext).expect("decryption"); +//! assert_eq!(recovered, plaintext); +//! ``` +//! +//! The stream modes take any length and return the initialisation data the same way: +//! +//! ``` +//! use bouncycastle_camellia::Camellia256Key; +//! use bouncycastle_cipher::modes::CTR; +//! use bouncycastle_core::key_material::{KeyMaterial, KeyType}; +//! use bouncycastle_core::symmetric_key::{FromKeyMaterial, SymmetricDecryptionKey}; +//! use bouncycastle_core::symmetric_key::SymmetricEncryptionKey; +//! use bouncycastle_rng::HashDRBG_SHA512; +//! +//! let mut rng = HashDRBG_SHA512::new_from_os(); +//! let material = KeyMaterial::<32>::from_bytes_as_type(&[0x42; 32], KeyType::SymmetricCipherKey) +//! .expect("a 32-byte symmetric cipher key"); +//! let key = Camellia256Key::::from_key_material(&material) +//! .expect("a valid Camellia-256 key"); +//! +//! // 50 bytes, and the ciphertext is 50 bytes: no padding anywhere. +//! let plaintext = [0x5Au8; 50]; +//! let mut data = plaintext; +//! let (_, nonce) = key.encrypt_inplace(&mut rng, &mut data).expect("encryption"); +//! assert_ne!(data, plaintext); +//! +//! key.decrypt_inplace(&nonce, &mut data).expect("decryption"); +//! assert_eq!(data, plaintext); +//! ``` +//! +//! For the block-aligned API -- whole blocks in place, through the block role pair -- make the +//! key under `CBC`; the padded aliases wrap the same worker. +//! +//! ## The raw permutation +//! +//! The engine transforms one block, and `ElectronicCodeBook::new` on it is the one-shot: +//! +//! ``` +//! use bouncycastle_camellia::hazmat::Camellia128Internal; +//! use bouncycastle_core::hazmat::{BlockPermutation, ElectronicCodeBook}; +//! use bouncycastle_core::key_material::{KeyMaterial, KeyType}; +//! +//! // RFC 3713 Appendix A, "128-bit key". +//! let key = KeyMaterial::<16>::from_bytes_as_type( +//! &[0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, +//! 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10], +//! KeyType::SymmetricCipherKey, +//! ).expect("a 16-byte symmetric cipher key"); +//! +//! let camellia = Camellia128Internal::new(&key).expect("a valid Camellia-128 key"); +//! +//! let mut block = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, +//! 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10]; +//! camellia.encrypt_block(&mut block); +//! assert_eq!(block, [0x67, 0x67, 0x31, 0x38, 0x54, 0x96, 0x69, 0x73, +//! 0x08, 0x57, 0x06, 0x56, 0x48, 0xea, 0xbe, 0x43]); +//! +//! // The same value decrypts, from the same subkeys -- there is no separate decryptor. +//! camellia.decrypt_block(&mut block); +//! assert_eq!(block, [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, +//! 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10]); +//! ``` +//! +//! The 192- and 256-bit variants are [`Camellia192Internal`] and [`Camellia256Internal`], +//! constructed from a `KeyMaterial<24>` and a `KeyMaterial<32>`; a key of the wrong length does +//! not compile. +//! +//! ## Four blocks at a time +//! +//! The bit-sliced S-box layer substitutes 32 bytes per pass, and a round substitutes eight bytes +//! per block, so four independent blocks cost the same as one. Where a caller has four, +//! [`CamelliaInternal::encrypt_4blocks`] is four times the throughput of four `encrypt_block` +//! calls, and it is also the four-block batch `BlockPermutation::encrypt_4blocks` offers to modes: +//! +//! ``` +//! use bouncycastle_camellia::hazmat::Camellia256Internal; +//! use bouncycastle_camellia::LANES; +//! use bouncycastle_core::hazmat::{BlockPermutation, ElectronicCodeBook}; +//! use bouncycastle_core::key_material::{KeyMaterial, KeyType}; +//! +//! let key = KeyMaterial::<32>::from_bytes_as_type(&[0x42; 32], KeyType::SymmetricCipherKey) +//! .expect("a 32-byte symmetric cipher key"); +//! let camellia = Camellia256Internal::new(&key).expect("a valid Camellia-256 key"); +//! +//! let mut blocks: [[u8; 16]; LANES] = core::array::from_fn(|i| [i as u8; 16]); +//! let original = blocks; +//! camellia.encrypt_4blocks(&mut blocks); +//! camellia.decrypt_4blocks(&mut blocks); +//! assert_eq!(blocks, original); +//! ``` +//! +//! # Design +//! +//! Camellia is an 18-round (128-bit key) or 24-round (192- and 256-bit key) Feistel network over +//! two 64-bit halves, with a key-dependent linear `FL`/`FLINV` layer inserted every six rounds +//! (Sec 2.3) and 64-bit whitening keys XORed in before and after. The round function `F` +//! (Sec 2.4.1) XORs a subkey into the half, puts its eight bytes through four S-boxes -- `SBOX1` +//! and three one-bit rotations of it -- and mixes them with a byte-wise linear map `P`. The key +//! schedule (Sec 2.2) derives two or three 128-bit intermediate keys with six applications of `F` +//! under fixed constants, then takes every subkey as half of a rotation of one of them, so it is +//! cheap: Camellia's "key agility" is one of its design goals. Decryption is the same network with +//! the subkeys in reverse (Sec 2.3.3). +//! +//! ## Why not a lookup table +//! +//! Sec 2.4.1 presents `SBOX1` as a table, and a table-driven implementation stores one -- some +//! fold `P` into four 1 KiB tables, others use a single 256-byte table. A table indexed +//! by a byte of the state is indexed by secret data, so on any CPU with a data cache the memory +//! access pattern, and hence the timing, depends on the key and the data. That is the classic +//! cache-timing attack on table-driven block ciphers, and it is not fixable while the lookup +//! remains -- in the cipher or in the key schedule, whose `F` calls go through the S-boxes too. +//! +//! ## The S-box as a circuit +//! +//! This crate has no table outside its tests. `SBOX1` has the same algebraic shape as the AES +//! S-box -- an affine map, inversion in GF(2^8), and another affine map -- a decomposition found +//! here by exhaustive search against the Sec 2.4.1 table, not taken from recall: of the 256 +//! possible input constants exactly one admits such a decomposition, and it is unique up to the +//! inverse's own symmetries. The search was carried out in the AES representation of the field, +//! so the 62-gate non-linear section of the Boyar-Peralta AES circuit, copied verbatim from +//! `bouncycastle-aes`, does the inversion, with generated affine top and bottom layers +//! pinned by an exhaustive 256-input test. The whole S-box is 121 gates: 32 AND, 74 XOR, 9 XNOR, +//! 6 NOT. The `sbox` module docs give the full derivation. +//! +//! `SBOX2`, `SBOX3` and `SBOX4` are `SBOX1` with the output byte rotated left by one, rotated +//! right by one, and the input byte rotated left by one (Sec 2.4.1). On bit-planes a byte rotation +//! is a renumbering of the planes, so the one circuit serves all four: the rotations are applied +//! only at the byte positions that need them, selected by compile-time masks. +//! +//! A round substitutes eight bytes per block, and the circuit's eight `u32` planes hold 32 byte +//! positions, so the engine works on **four blocks at once**: each round forms the argument of `F` +//! for every block, splits the four 64-bit words into eight 32-bit halves, transposes them into +//! planes, runs the circuit once, transposes back, and finishes the round per block. The blocks +//! never mix. Everything else in +//! the cipher -- `P`, `FL`, `FLINV`, the whitening -- is XOR, AND and OR with key words, and +//! rotations, all already constant-time on words, so the rest of the engine is a direct, +//! spec-literal implementation: 64-bit halves as the RFC defines them, and `P` computed with a +//! five-rotation form that is checked against the RFC's byte formulas in a test. +//! +//! Beyond the S-box, this crate stores one schedule that serves both directions (a +//! direction-aware engine typically lays the subkeys out differently per direction at +//! initialisation); the block methods are infallible (the run-time buffer and initialisation +//! checks are compile-time facts here); and the constructors require a key tagged as a symmetric +//! cipher key of at least the strength its length implies, as every cipher in this workspace does. +//! +//! ## Why "lowmemory" +//! +//! Two things. First, no tables: a table-driven implementation carries anywhere from 256 bytes to +//! 4 KiB of them, indexed by secret data; here the S-box is code. Second, +//! the working set. Eight `u64` planes would take eight blocks per pass and double the throughput +//! on a 64-bit machine, but every per-call buffer -- the block state, the planes, their copy during +//! the byte rotations -- would double with them. Four lanes over `u32` planes keep the whole +//! per-call working state near 160 bytes, and cost nothing on a 32-bit target, where a `u64` +//! operation is two instructions anyway. +//! +//! # Memory Usage +//! +//! No heap allocation and no lookup tables. The persistent state is the subkeys of Sec 2.2 -- +//! four whitening keys, one round key per round, and two `FL`/`FLINV` keys per `FL` layer, 64 bits +//! each -- held once in the key; a worker adds the mode's own state and a reference to the key: +//! +//! | Type | Key | Rounds | Subkeys (persistent) | Tables | +//! |---|---|---|---|---| +//! | [`Camellia128Internal`] | 16 B | 18 | 26 x 8 = 208 B | 0 B | +//! | [`Camellia192Internal`] | 24 B | 24 | 34 x 8 = 272 B | 0 B | +//! | [`Camellia256Internal`] | 32 B | 24 | 34 x 8 = 272 B | 0 B | +//! +//! Per-call stack usage is the four-block working state -- two 64-bit halves per block, 64 +//! bytes -- plus the eight `u32` planes of the S-box argument (32 bytes), their copy during the +//! rotations (32 bytes), and the circuit's spills. Every entry point runs the same four-lane +//! circuit, so the one-, two- and four-block calls cost the same working state, and only key +//! expansion depends on the key length. Measured as the deepest frame chain below each entry +//! point's `measure` closure in `mem_usage_benches/src/bench_camellia_mem_usage.rs`: the +//! closure, then the out-of-line `encrypt_4blocks` (or the schedule's `expand`), `f` and +//! `ortho` frames under it, from the compiler's frame-layout remarks and the disassembly of the +//! release build (x86-64, rustc 1.97 nightly, return addresses included): +//! +//! | Entry point | Camellia-128 | Camellia-192 | Camellia-256 | +//! |---|---|---|---| +//! | `new` (key expansion) | 720 B | 1120 B | 1120 B | +//! | `encrypt_block` / `decrypt_block` | 496 B | 496 B | 496 B | +//! | `encrypt_2blocks` / `decrypt_2blocks` | 512 B | 512 B | 512 B | +//! | `encrypt_4blocks` | 528 B | 528 B | 528 B | +//! | `decrypt_4blocks` | 512 B | 512 B | 512 B | +//! +//! For comparison, a table-driven implementation carries anywhere from 256 bytes to 4 KiB of +//! tables on top of a 272-byte subkey array sized for the largest key. +//! +//! # 🚨 Security Considerations 🚨 +//! +//! ## A block permutation is not a cipher +//! +//! [`Camellia128Internal`] and its siblings transform exactly 16 bytes. Using one directly on +//! data means ECB, which is not confidential: identical plaintext blocks produce identical +//! ciphertext blocks, so structure in the plaintext survives encryption. **Do not do it.** Use a +//! mode of operation, and prefer an authenticated one so that ciphertext tampering is detected. +//! RFC 3713 Sec 3 itself assigns object identifiers only to Camellia in CBC mode. That is why the +//! permutation lives under [`hazmat`]; [`bouncycastle_core::hazmat`] lists the supported uses. +//! A `Camellia128Key>`, `>` or `>` hands out ECB through +//! the key API as well, and the same warning applies to it. The authenticated modes are +//! `Camellia128Key` and `>`. +//! +//! ## Constant-time properties +//! +//! By construction there is no secret-dependent memory access and no secret-dependent branch, in +//! the cipher *or* in the key schedule: the six `F` calls of Sec 2.2 go through the same circuit +//! as the rounds. The only branches are the round loop and the lane loops, which count over public +//! constants, and the odd/even and every-sixth-round tests on the public round counter. +//! +//! Caveats worth stating plainly: +//! +//! * The Rust compiler makes no guarantee it will preserve this. The code is written so that the +//! natural code generation is straight-line, and `#![forbid(unsafe_code)]` rules out the usual +//! ways of forcing the issue, but the property is not contractual. +//! * The four-block working state is not scrubbed after a call. Only the subkeys (and, during +//! expansion, `KL`, `KR`, `KA`, `KB` and the `D1`/`D2` temporaries) are wrapped in `Secret`, and +//! so only they are guaranteed to be zeroized on drop. +//! * Constant-time execution says nothing about power or electromagnetic side channels. +//! +//! ## Security strength +//! +//! RFC 3713 Sec 4 reports no differential or linear characteristic with probability above +//! `2^-128` for the full 18 rounds. Each variant's `MAX_SECURITY_STRENGTH` is its key length: +//! 128, 192 or 256 bits. +//! +//! # Provenance +//! +//! * **Source engine.** The `SIGMA` constants, `camelliaF2` linear layer, `camelliaFLs` and +//! subkey layout this crate reproduces, and the `SBOX1` table the circuit is verified against, +//! come from Bouncy Castle Java's `CamelliaEngine` and `CamelliaLightEngine`. A direct +//! transcription of `CamelliaLightEngine` lives in the tests (`tests/common/mod.rs`) and this +//! engine is checked against it on thousands of inputs. +//! * **Normative reference: RFC 3713**, "A Description of the Camellia Encryption Algorithm" +//! (Matsui, Nakajima, Moriai; April 2004). Every function cites its section. The `SBOX1` table +//! and the `Sigma` constants were extracted mechanically from the text of the RFC. +//! * **The non-linear section of the S-box circuit** is from the 113-gate straight-line program +//! `SLP_AES_113.txt` in Peralta's circuit collection, described in J. Boyar and R. Peralta, "A +//! new combinational logic minimization technique with applications to cryptology", +//! , as transcribed in `bouncycastle-aes`. +//! * **The bit-plane transpose** is translated from BearSSL's `aes_ct` by Thomas Pornin (MIT +//! licence), as in the AES and SM4 crates. +//! * Verified against the three vectors of RFC 3713 Appendix A; all 3840 vectors of NTT's +//! CRYPTREC test-vector file `t_camellia.txt` (ten keys per key length, 128 single-bit +//! plaintexts each), both directions; the nine vectors of `tests/bc_java_tests.rs` (RFC 3713 +//! and NESSIE); the CBC and CFB128 vectors of OpenSSL's `evpciph_camellia.txt` through the CBC +//! and CFB aliases; RFC 5528's nine Camellia-CTR vectors, through a reference built from the +//! SP 800-38A Sec 6.5 equations which the CTR keys are then held to (see +//! `tests/stream_mode_tests.rs` for why RFC 5528's counter blocks are not ones they produce); +//! and the transcription of `CamelliaLightEngine` on thousands of keys and blocks in every lane. +//! Project Wycheproof's `camellia_cbc_pkcs5_test.json` runs through the padded CBC keys and +//! its `camellia_ccm_test.json` through the `CCM` mode traits over the engines. + +#![no_std] +#![forbid(unsafe_code)] +#![forbid(missing_docs)] + +mod bitslice; +mod cbc; +mod ccm; +mod cfb; +mod cfb8; +mod cmac; +mod ctr; +mod gcm; +mod gmac; +pub mod hazmat; +mod key; +mod kw; +mod round; +mod sbox; +mod schedule; + +/// The Camellia block length in bytes: 16 (RFC 3713 Sec 1.1, "128-bit block size"). +pub const BLOCK_LEN: usize = 16; + +/// The number of blocks the bit-sliced S-box layer substitutes at once. See +/// [`CamelliaInternal::encrypt_4blocks`]. +pub const LANES: usize = 4; + +pub use cbc::{Camellia_CBC_128, Camellia_CBC_192, Camellia_CBC_256}; +pub use ccm::{CCM_NONCE_LEN, CCM_TAG_LEN, Camellia_CCM_128, Camellia_CCM_192, Camellia_CCM_256}; +pub use cfb::{Camellia_CFB_128, Camellia_CFB_192, Camellia_CFB_256}; +pub use cfb8::{Camellia_CFB8_128, Camellia_CFB8_192, Camellia_CFB8_256}; +pub use cmac::{Camellia_CMAC_128, Camellia_CMAC_192, Camellia_CMAC_256}; +pub use ctr::{CTR_NONCE_LEN, Camellia_CTR_128, Camellia_CTR_192, Camellia_CTR_256}; +pub use gcm::{Camellia_GCM_128, Camellia_GCM_192, Camellia_GCM_256}; +pub use gmac::{Camellia_GMAC_128, Camellia_GMAC_192, Camellia_GMAC_256}; +pub use key::{Camellia128Key, Camellia192Key, Camellia256Key, CamelliaKey}; +pub use kw::{Camellia_KW_128, Camellia_KW_192, Camellia_KW_256}; +pub use schedule::{Camellia128Params, Camellia192Params, Camellia256Params, CamelliaParams}; + +// Imports needed for docs +#[allow(unused_imports)] +use hazmat::{Camellia128Internal, Camellia192Internal, Camellia256Internal, CamelliaInternal}; +// end of imports needed for docs diff --git a/crypto/camellia/src/round.rs b/crypto/camellia/src/round.rs new file mode 100644 index 000000000..30238cee2 --- /dev/null +++ b/crypto/camellia/src/round.rs @@ -0,0 +1,265 @@ +//! The components of Camellia (RFC 3713 Sec 2.4) -- the F-function, the FL- and FLINV-functions +//! -- and the data randomizing part (Sec 2.3) that runs them, on four blocks at once. + +use crate::LANES; +use crate::hazmat::camellia::Block; +use crate::sbox::sboxes; + +/// `F(F_IN, KE)` (Sec 2.4.1) on four blocks at once: `f_in[b]` is `F_IN` for block `b`, and +/// `ke` is the same 64-bit subkey for all four. +/// +/// Line by line against Sec 2.4.1: `x = F_IN ^ KE`; `t1 .. t8` are the bytes of `x`, most +/// significant first, and go through `SBOX1, SBOX2, SBOX3, SBOX4, SBOX2, SBOX3, SBOX4, SBOX1` +/// respectively -- that is [`sboxes`], on all four blocks in one pass; `y1 .. y8` and `F_OUT` +/// are the linear map [`p`], per block. The blocks never mix. +pub(crate) fn f(f_in: &[u64; LANES], ke: u64) -> [u64; LANES] { + // x = F_IN ^ KE + let mut x = f_in.map(|d| d ^ ke); + // t1 = SBOX1[t1]; ... t8 = SBOX1[t8] + sboxes(&mut x); + // y1 .. y8, F_OUT + x.map(p) +} + +/// `F(F_IN, KE)` on one 64-bit word, for the key schedule (Sec 2.2), where `F` is applied to +/// `D1`/`D2` with the `Sigma` constants as keys. +/// +/// The circuit always processes four lanes; the one word is placed in every lane and lane 0 is +/// read back. All four lanes then hold the same result, which `test_f1_lanes_agree` checks. +pub(crate) fn f1(f_in: u64, ke: u64) -> u64 { + f(&[f_in; LANES], ke)[0] +} + +/// The linear part of the F-function, Sec 2.4.1's `y1 .. y8` from `t1 .. t8`: +/// +/// ```text +/// y1 = t1 ^ t3 ^ t4 ^ t6 ^ t7 ^ t8; y5 = t1 ^ t2 ^ t6 ^ t7 ^ t8; +/// y2 = t1 ^ t2 ^ t4 ^ t5 ^ t7 ^ t8; y6 = t2 ^ t3 ^ t5 ^ t7 ^ t8; +/// y3 = t1 ^ t2 ^ t3 ^ t5 ^ t6 ^ t8; y7 = t3 ^ t4 ^ t5 ^ t6 ^ t8; +/// y4 = t2 ^ t3 ^ t4 ^ t5 ^ t6 ^ t7; y8 = t1 ^ t4 ^ t5 ^ t6 ^ t7; +/// F_OUT = (y1 << 56) | (y2 << 48) | ... | y8 +/// ``` +/// +/// Computed on the two 32-bit halves `u = (t1, t2, t3, t4)` and `v = (t5, t6, t7, t8)` with five +/// rotations and four XORs instead of forty byte XORs. It is the same map: expanding the +/// rotations byte by byte gives exactly the eight sums above, and +/// `test_p_matches_the_rfc_formula` checks it on every single-bit input (which, `p` being linear, +/// determines it) and on random ones. +#[inline(always)] +fn p(t: u64) -> u64 { + let (mut u, mut v) = ((t >> 32) as u32, t as u32); + v = v.rotate_left(8); + u ^= v; + v = v.rotate_left(8) ^ u; + u = u.rotate_right(8) ^ v; + let hi = v.rotate_left(16) ^ u; + let lo = u.rotate_left(8); + ((hi as u64) << 32) | lo as u64 +} + +/// `FL(FL_IN, KE)` (Sec 2.4.2): +/// +/// ```text +/// x1 = FL_IN >> 32; x2 = FL_IN & MASK32; k1 = KE >> 32; k2 = KE & MASK32; +/// x2 = x2 ^ ((x1 & k1) <<< 1); +/// x1 = x1 ^ (x2 | k2); +/// FL_OUT = (x1 << 32) | x2; +/// ``` +/// +/// AND and OR with key words, and a rotation: no table and no branch, so constant-time as it +/// stands. +#[inline(always)] +pub(crate) fn fl(fl_in: u64, ke: u64) -> u64 { + let (mut x1, mut x2) = ((fl_in >> 32) as u32, fl_in as u32); + let (k1, k2) = ((ke >> 32) as u32, ke as u32); + x2 ^= (x1 & k1).rotate_left(1); + x1 ^= x2 | k2; + ((x1 as u64) << 32) | x2 as u64 +} + +/// `FLINV(FLINV_IN, KE)` (Sec 2.4.2), the inverse of [`fl`]: +/// +/// ```text +/// y1 = y1 ^ (y2 | k2); +/// y2 = y2 ^ ((y1 & k1) <<< 1); +/// ``` +#[inline(always)] +pub(crate) fn flinv(flinv_in: u64, ke: u64) -> u64 { + let (mut y1, mut y2) = ((flinv_in >> 32) as u32, flinv_in as u32); + let (k1, k2) = ((ke >> 32) as u32, ke as u32); + y1 ^= y2 | k2; + y2 ^= (y1 & k1).rotate_left(1); + ((y1 as u64) << 32) | y2 as u64 +} + +/// The data randomizing part (Sec 2.3.1 for 18 rounds, Sec 2.3.2 for 24) on four blocks at once, +/// with the subkeys supplied by three accessors: `kw(i)` for `kw1 .. kw4`, `k(i)` for +/// `k1 .. k_rounds`, and `ke(i)` for `ke1 .. ke_m` (`m = 4` or `6`), all 1-based as the RFC +/// numbers them. Encryption passes the schedule's own order; decryption passes the swapped order +/// of Sec 2.3.3 (see [`crate::hazmat::CamelliaInternal::decrypt_4blocks`]). +/// +/// Line by line against Sec 2.3.1 / 2.3.2: +/// +/// * `D1 = M >> 64; D2 = M & MASK64` -- the block as two big-endian 64-bit words; +/// * `D1 = D1 ^ kw1; D2 = D2 ^ kw2` -- prewhitening; +/// * round `i`: `D2 = D2 ^ F(D1, k_i)` for odd `i`, `D1 = D1 ^ F(D2, k_i)` for even `i`; +/// * after rounds 6, 12 (and 18 when there are 24), for the `m`-th FL layer: +/// `D1 = FL(D1, ke_{2m-1}); D2 = FLINV(D2, ke_{2m})` -- "FL- and FLINV-functions inserted every +/// 6 rounds", but not after the last round; +/// * `D2 = D2 ^ kw3; D1 = D1 ^ kw4` -- postwhitening; +/// * `C = (D2 << 64) | D1` -- the halves swap on output. +/// +/// The RFC writes the 18 or 24 rounds out longhand; this is the same sequence as a loop over a +/// public round counter. The four blocks are processed together only because [`f`] is: the +/// F-function's argument is formed per block, all four go through the S-box layer in one pass, +/// and everything else is per block. `tests/rfc3713_tests.rs` pins the result in every lane. +pub(crate) fn rounds( + blocks: &mut [Block; LANES], + num_rounds: usize, + kw: impl Fn(usize) -> u64, + k: impl Fn(usize) -> u64, + ke: impl Fn(usize) -> u64, +) { + // D1 = M >> 64; D2 = M & MASK64, per block. + let mut d1 = [0u64; LANES]; + let mut d2 = [0u64; LANES]; + for (b, block) in blocks.iter().enumerate() { + // Sixteen bytes are exactly two eight-byte halves; the remainder is provably empty. + let (halves, _) = block.as_chunks::<8>(); + d1[b] = u64::from_be_bytes(halves[0]); + d2[b] = u64::from_be_bytes(halves[1]); + } + + // Prewhitening. + let (kw1, kw2) = (kw(1), kw(2)); + for b in 0..LANES { + d1[b] ^= kw1; + d2[b] ^= kw2; + } + + for i in 1..=num_rounds { + // Round i. Odd rounds write D2 from F(D1, k_i), even rounds write D1 from F(D2, k_i). + if i % 2 == 1 { + let f_out = f(&d1, k(i)); + for b in 0..LANES { + d2[b] ^= f_out[b]; + } + } else { + let f_out = f(&d2, k(i)); + for b in 0..LANES { + d1[b] ^= f_out[b]; + } + } + // FL / FLINV after every sixth round except the last. + if i % 6 == 0 && i != num_rounds { + let m = i / 6; + let (ke1, ke2) = (ke(2 * m - 1), ke(2 * m)); + for b in 0..LANES { + d1[b] = fl(d1[b], ke1); + d2[b] = flinv(d2[b], ke2); + } + } + } + + // Postwhitening, and C = (D2 << 64) | D1. + let (kw3, kw4) = (kw(3), kw(4)); + for (b, block) in blocks.iter_mut().enumerate() { + let (halves, _) = block.as_chunks_mut::<8>(); + halves[0] = (d2[b] ^ kw3).to_be_bytes(); + halves[1] = (d1[b] ^ kw4).to_be_bytes(); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::sbox::tests::sboxes_table; + + /// Sec 2.4.1's `y1 .. y8`, written out literally, byte by byte. + fn p_literal(x: u64) -> u64 { + let [t1, t2, t3, t4, t5, t6, t7, t8] = x.to_be_bytes(); + let y1 = t1 ^ t3 ^ t4 ^ t6 ^ t7 ^ t8; + let y2 = t1 ^ t2 ^ t4 ^ t5 ^ t7 ^ t8; + let y3 = t1 ^ t2 ^ t3 ^ t5 ^ t6 ^ t8; + let y4 = t2 ^ t3 ^ t4 ^ t5 ^ t6 ^ t7; + let y5 = t1 ^ t2 ^ t6 ^ t7 ^ t8; + let y6 = t2 ^ t3 ^ t5 ^ t7 ^ t8; + let y7 = t3 ^ t4 ^ t5 ^ t6 ^ t8; + let y8 = t1 ^ t4 ^ t5 ^ t6 ^ t7; + u64::from_be_bytes([y1, y2, y3, y4, y5, y6, y7, y8]) + } + + /// Deterministic pseudo-random words (xorshift64), so the tests need no RNG crate. + fn pseudo_random(seed: &mut u64) -> u64 { + *seed ^= *seed << 13; + *seed ^= *seed >> 7; + *seed ^= *seed << 17; + *seed + } + + #[test] + fn test_p_matches_the_rfc_formula() { + // p is linear, so agreement on the 64 unit vectors proves agreement everywhere; the random + // words are a second, independent check of that reasoning. + for i in 0..64 { + assert_eq!(p(1 << i), p_literal(1 << i), "bit {i}"); + } + let mut seed = 0x9E37_79B9_7F4A_7C15; + for _ in 0..1000 { + let x = pseudo_random(&mut seed); + assert_eq!(p(x), p_literal(x), "{x:#018x}"); + } + assert_eq!(p(0), 0); + } + + #[test] + fn test_f_is_the_table_form_followed_by_p() { + // F(F_IN, KE) = P(S(F_IN ^ KE)), per lane, against the table-driven S-box layer. + let mut seed = 0x0123_4567_89AB_CDEF; + for _ in 0..200 { + let f_in: [u64; LANES] = core::array::from_fn(|_| pseudo_random(&mut seed)); + let ke = pseudo_random(&mut seed); + let got = f(&f_in, ke); + for b in 0..LANES { + assert_eq!(got[b], p_literal(sboxes_table(f_in[b] ^ ke)), "lane {b}"); + } + } + } + + #[test] + fn test_f1_lanes_agree() { + // The single-word F fills all four lanes with the same word; every lane must come back + // identical, or lane 0 would not be a valid answer. + for (x, ke) in [(0u64, 0u64), (u64::MAX, 0), (0x0123_4567_89AB_CDEF, 0xA09E_667F_3BCC_908B)] + { + let all = f(&[x; LANES], ke); + assert!(all.iter().all(|&w| w == all[0]), "lanes disagree for {x:#018x}"); + assert_eq!(f1(x, ke), all[0]); + assert_eq!(f1(x, ke), p_literal(sboxes_table(x ^ ke))); + } + } + + #[test] + fn test_flinv_inverts_fl() { + // Sec 2.4.2: "FLINV-function is the inverse function of the FL-function." + let mut seed = 0xDEAD_BEEF_CAFE_F00D; + for _ in 0..1000 { + let x = pseudo_random(&mut seed); + let ke = pseudo_random(&mut seed); + assert_eq!(flinv(fl(x, ke), ke), x); + assert_eq!(fl(flinv(x, ke), ke), x); + } + // And neither is the identity in general. + assert_ne!(fl(0, u64::MAX), 0); + } + + #[test] + fn test_fl_matches_a_hand_worked_value() { + // x1 = 0x0000_0001, x2 = 0, k1 = 0xFFFF_FFFF, k2 = 0: + // x2 = 0 ^ ((0x0000_0001 & 0xFFFF_FFFF) <<< 1) = 0x0000_0002 + // x1 = 0x0000_0001 ^ (0x0000_0002 | 0) = 0x0000_0003 + assert_eq!(fl(0x0000_0001_0000_0000, 0xFFFF_FFFF_0000_0000), 0x0000_0003_0000_0002); + // The rotation wraps: x1 = 0x8000_0000 gives x2 = 0x0000_0001. + assert_eq!(fl(0x8000_0000_0000_0000, 0xFFFF_FFFF_0000_0000), 0x8000_0001_0000_0001); + } +} diff --git a/crypto/camellia/src/sbox.rs b/crypto/camellia/src/sbox.rs new file mode 100644 index 000000000..e4b987229 --- /dev/null +++ b/crypto/camellia/src/sbox.rs @@ -0,0 +1,551 @@ +//! `SBOX1` .. `SBOX4` (RFC 3713 Sec 2.4.1) as a Boolean circuit over bit-planes. +//! +//! # Why a circuit and not a table +//! +//! Sec 2.4.1 defines `SBOX1` by a 256-entry table and the other three in terms of it, and BC +//! Java's `CamelliaEngine` and `CamelliaLightEngine` both store tables (four 1 KiB `u32` tables +//! with the P-function folded in, and one 256-byte table, respectively). A table indexed by a +//! byte of the state is indexed by *secret data*, and on any CPU with a data cache the access +//! pattern -- hence the timing -- depends on that secret. That is the standard cache-timing side +//! channel of every table-driven block cipher, and it cannot be closed while keeping the lookup. +//! +//! So this module has no table (outside its tests). It computes the same function as the Sec 2.4.1 +//! table with AND, XOR, XNOR and NOT gates applied to the bit-planes of [`crate::bitslice`]. Every +//! operation is a straight-line word operation on public *positions*, so there is no +//! secret-dependent memory access and no secret-dependent branch. This is the only place in the +//! crate where secret data meets non-linear logic; everything else is XOR, AND/OR with key words, +//! and rotates. +//! +//! Because the planes hold the eight bytes of one F-function input from each of four blocks, one +//! pass of the circuit is the whole S-box layer of a round for four blocks at once. +//! +//! # What the circuit computes, and where it came from +//! +//! `SBOX1` has the same algebraic shape as the AES S-box: an affine map, inversion in GF(2^8), and +//! another affine map. Writing `inv` for inversion in the AES field (`x^8 + x^4 + x^3 + x + 1`, +//! with `inv(0) = 0`), and `M`, `N` for 8x8 matrices over GF(2) given by their columns (column +//! `i` is the image of input bit `i`, bit 0 least significant): +//! +//! ```text +//! SBOX1(x) = N * inv(M * x xor 0x82) xor 0x6e +//! +//! M columns: 0x38, 0x84, 0xe7, 0xbb, 0x94, 0xff, 0x0d, 0x50 +//! N columns: 0xeb, 0x38, 0x5c, 0x19, 0xc5, 0xf8, 0xb5, 0x41 +//! ``` +//! +//! The input constant `0x82` is `M * 0xc5`, so equivalently `SBOX1(x) = N * inv(M * (x xor +//! 0xc5)) xor 0x6e`. This decomposition was **found by search, not recalled**: for each of the +//! 256 possible input constants the remaining linear equivalence to `inv` was searched +//! exhaustively (the search fixes the multiplicative and Frobenius self-equivalences of `inv`, +//! which is what makes it finite), against the table extracted from the text of RFC 3713. Exactly +//! one constant, `0xc5`, admits a decomposition, and it is unique up to those self-equivalences. +//! The 2040 equivalent forms give circuits of different sizes; the one above was chosen for the +//! fewest gates. +//! +//! Because both S-boxes are inversion between affine maps, the AES inversion circuit does +//! Camellia's work directly -- the field isomorphism is absorbed into `M` and `N`, since the +//! search was carried out in the AES representation. The circuit below is therefore +//! +//! * a **top affine layer**, generated: `M * x xor 0x82` composed with the Boyar-Peralta input +//! basis change, as one affine map from the eight input planes to the 22 signals the +//! non-linear section consumes; +//! * the **non-linear section** of the 113-gate Boyar-Peralta AES circuit, **copied verbatim** +//! from `bouncycastle-aes` (`src/sbox.rs`, itself a transcription of Peralta's +//! `SLP_AES_113.txt`): 32 AND and 30 XOR gates computing the inverse in a tower-field +//! representation; +//! * a **bottom affine layer**, generated: the tower field back to the AES polynomial basis, then +//! `N * . xor 0x6e`, as one affine map from the 18 non-linear outputs to the eight output planes. +//! +//! The two affine layers were fitted by linear algebra over GF(2) (the bottom one by solving for +//! the linear map from the non-linear section's outputs to `inv`, on all 256 inputs) and reduced +//! with a greedy common-subexpression pass. The result is 121 gates: 32 AND, 74 XOR, 9 XNOR, +//! 6 NOT (31 in the top layer, 62 in the non-linear section, 28 in the bottom layer). The +//! generator verified the assembled circuit -- the emitted text, re-evaluated -- against the table +//! before any of it was written here, and `test_sbox_matches_rfc_3713_sbox1` re-verifies all 256 +//! inputs in Rust. The gate list is not meaningful line by line and should not be "tidied". +//! +//! # The other three S-boxes +//! +//! Sec 2.4.1 defines `SBOX2[x] = SBOX1[x] <<< 1`, `SBOX3[x] = SBOX1[x] <<< 7` and +//! `SBOX4[x] = SBOX1[x <<< 1]`: rotations of the output byte, or of the input byte, by one bit. +//! On bit-planes a byte rotation is a *renumbering of the planes*, so [`sboxes`] runs the one +//! circuit for all 32 byte positions and applies the rotations only at the positions that need +//! them, with public position masks derived from the layout of [`crate::bitslice`]: plane `k` at +//! those positions is +//! taken from plane `k - 1` (rotate left) or `k + 1` (rotate right). No second circuit, and no +//! secret-dependent selection -- the masks are compile-time constants. +//! +//! # Bit numbering +//! +//! Plane `k` holds bit `k` of every byte (bit 0 least significant), for inputs and outputs alike. +//! The Boyar-Peralta section keeps its own signal names (`y*`, `t*`, `z*`) so it can be diffed +//! against the AES and SM4 crates; its inputs are bound from the generated top layer, so its +//! `U0`-is-MSB convention never appears here. + +use crate::LANES; +use crate::bitslice::{Planes, ortho}; + +// The position masks. [`sboxes`] loads plane word `b` with the high 32 bits of block `b`'s +// F-function input (`t1 t2 t3 t4`, most significant byte first) and word `4 + b` with the low 32 +// bits (`t5 t6 t7 t8`), so after `ortho` the bits `8L .. 8L+3` of every plane are byte `L` of the +// four high halves and `8L+4 .. 8L+7` byte `L` of the four low halves. Byte `L = 3` of the high +// half is `t1` and byte `L = 0` is `t4`; of the low half, `t5` and `t8`. So a byte position's +// S-box is a public 32-bit mask, and the four masks partition the word. +// +// The `|` in each constant joins disjoint nibbles, so `|` and `^` compute the same constant; +// `cargo mutants` reports those `| -> ^` mutants as surviving, and they are equivalences. + +/// The positions that go through `SBOX2`: `t2` (high half, byte 2) and `t5` (low half, byte 3). +const SBOX2_LANES: u32 = (0x0F << 16) | (0xF0 << 24); +/// The positions that go through `SBOX3`: `t3` (high half, byte 1) and `t6` (low half, byte 2). +const SBOX3_LANES: u32 = (0x0F << 8) | (0xF0 << 16); +/// The positions that go through `SBOX4`: `t4` (high half, byte 0) and `t7` (low half, byte 1). +const SBOX4_LANES: u32 = 0x0F | (0xF0 << 8); + +/// `SBOX1` applied to every byte position of the eight words in `q` (Sec 2.4.1), on bit-planes: +/// `q[k]` holds bit `k` of each byte on entry and on exit. +/// +/// See the module docs for what the three sections are and where they come from. +pub(crate) fn sbox(q: &mut Planes) { + // Inputs: plane k holds bit k of every byte. + let x0 = q[0]; + let x1 = q[1]; + let x2 = q[2]; + let x3 = q[3]; + let x4 = q[4]; + let x5 = q[5]; + let x6 = q[6]; + let x7 = q[7]; + + // Top affine layer (31 gates, generated): the input affine map `M * x xor 0x82` and the + // Boyar-Peralta input basis change, folded into one affine map over x0..x7. NOTs and XNORs + // carry the constant. + let a1 = x3 ^ x6; + let a2 = x0 ^ x7; + let a3 = x2 ^ a1; + let a4 = x1 ^ x4; + let a5 = a1 ^ a2; + let a6 = x2 ^ a2; + let a7 = x4 ^ a3; + let a8 = x2 ^ x3; + let a9 = x0 ^ x1; + let a10 = x1 ^ x7; + let a11 = a4 ^ a5; + let a12 = x5 ^ a3; + let a13 = x5 ^ x6; + let a14 = a13 ^ a6; + let a15 = x5 ^ a8; + let a16 = a15 ^ a10; + let a17 = !(x5 ^ a11); + let a18 = !(x1 ^ a6); + let a19 = a1 ^ a9; + let a20 = !(a4 ^ a6); + let a21 = a2 ^ a7; + let a22 = x1 ^ a2; + let a23 = a22 ^ a3; + let a24 = x6 ^ a10; + let a25 = !(a4 ^ a8); + let a26 = !(x7 ^ a7); + let u7 = a12; + let y1 = a14; + let y2 = !a11; + let y3 = a2; + let y4 = a7; + let y5 = !a5; + let y6 = a16; + let y7 = a17; + let y8 = !a1; + let y9 = a18; + let y10 = a19; + let y11 = a20; + let y12 = a21; + let y13 = a4; + let y14 = a23; + let y15 = a24; + let y16 = a25; + let y17 = a26; + let y18 = x5; + let y19 = !a9; + let y20 = x4; + let y21 = !a8; + + // Non-linear section (62 gates): GF(2^8) inversion, copied verbatim from the Boyar-Peralta + // AES circuit in `bouncycastle-aes` (`src/sbox.rs`). It consumes the signals bound + // above and produces the tower-field coordinates of the inverse. + let t2 = y12 & y15; + let t3 = y3 & y6; + let t4 = t3 ^ t2; + let t5 = y4 & u7; + let t6 = t5 ^ t2; + let t7 = y13 & y16; + let t8 = y5 & y1; + let t9 = t8 ^ t7; + let t10 = y2 & y7; + let t11 = t10 ^ t7; + let t12 = y9 & y11; + let t13 = y14 & y17; + let t14 = t13 ^ t12; + let t15 = y8 & y10; + let t16 = t15 ^ t12; + let t17 = t4 ^ y20; + let t18 = t6 ^ t16; + let t19 = t9 ^ t14; + let t20 = t11 ^ t16; + let t21 = t17 ^ t14; + let t22 = t18 ^ y19; + let t23 = t19 ^ y21; + let t24 = t20 ^ y18; + let t25 = t21 ^ t22; + let t26 = t21 & t23; + let t27 = t24 ^ t26; + let t28 = t25 & t27; + let t29 = t28 ^ t22; + let t30 = t23 ^ t24; + let t31 = t22 ^ t26; + let t32 = t31 & t30; + let t33 = t32 ^ t24; + let t34 = t23 ^ t33; + let t35 = t27 ^ t33; + let t36 = t24 & t35; + // `cargo mutants` reports the `^ -> |` mutant on the next line as surviving. That is a true + // equivalence, not a gap: `t36` and `t34` are never both 1 for any of the 256 possible input + // bytes, so XOR and OR agree here. It is the same gate the AES and SM4 crates document, since + // this section is copied from there; `test_sbox_matches_rfc_3713_sbox1` kills every other + // `^ -> |` mutant in the circuit. + let t37 = t36 ^ t34; + let t38 = t27 ^ t36; + let t39 = t29 & t38; + let t40 = t25 ^ t39; + let t41 = t40 ^ t37; + let t42 = t29 ^ t33; + let t43 = t29 ^ t40; + let t44 = t33 ^ t37; + let t45 = t42 ^ t41; + let z0 = t44 & y15; + let z1 = t37 & y6; + let z2 = t33 & u7; + let z3 = t43 & y16; + let z4 = t40 & y1; + let z5 = t29 & y7; + let z6 = t42 & y11; + let z7 = t45 & y17; + let z8 = t41 & y10; + let z9 = t44 & y12; + let z10 = t37 & y3; + let z11 = t33 & y4; + let z12 = t43 & y13; + let z13 = t40 & y5; + let z14 = t29 & y2; + let z15 = t42 & y9; + let z16 = t45 & y14; + let z17 = t41 & y8; + + // Bottom affine layer (28 gates, generated): tower field back to the AES polynomial basis + // and the output affine map `N * . xor 0x6e`, folded into one affine map over the inverse's + // coordinates; XNORs and NOTs carry the constant. Plane j receives bit j of SBOX1(x). + let b1 = z9 ^ z15; + let b2 = z2 ^ z8; + let b3 = z3 ^ z6; + let b4 = z10 ^ b1; + let b5 = z13 ^ z14; + let b6 = z1 ^ b2; + let b7 = z4 ^ b3; + let b8 = z11 ^ b1; + let b9 = z17 ^ b4; + let b10 = b5 ^ b9; + let b11 = z7 ^ z12; + let b12 = b11 ^ z14; + let b13 = b12 ^ z15; + let b14 = b13 ^ z17; + let b15 = b14 ^ b6; + let b16 = !(z17 ^ b8); + let b17 = z5 ^ z8; + let b18 = b17 ^ b3; + let b19 = !(b18 ^ b10); + let b20 = z16 ^ b5; + let b21 = !(b20 ^ b8); + let b22 = z16 ^ b4; + let b23 = b22 ^ b6; + let b24 = b23 ^ b7; + let b25 = !(z7 ^ b7); + let b26 = z0 ^ z6; + let b27 = b26 ^ b2; + q[0] = b15; + q[1] = b16; + q[2] = b19; + q[3] = b21; + q[4] = b24; + q[5] = b25; + q[6] = !b10; + q[7] = b27; +} + +/// Rotates the byte at every position selected by `lanes` one bit to the left, on bit-planes: +/// bit `k` of the output byte is bit `k - 1` of the input byte, so plane `k` takes plane +/// `k - 1` (mod 8) at those positions and is unchanged elsewhere. +/// +/// `lanes` is a public constant, so this is a fixed data movement, not a secret-dependent one. +/// The two operands of the `|` occupy disjoint bits (`lanes` and its complement), so `|` and `^` +/// compute the same function here; `cargo mutants` reports that as a surviving mutant, and +/// `test_sboxes_apply_the_four_tables_to_the_right_bytes` is what pins the code. +fn rotate_bytes_left_at(q: &mut Planes, lanes: u32) { + let old = *q; + for k in 0..8 { + q[k] = (old[k] & !lanes) | (old[(k + 7) % 8] & lanes); + } +} + +/// Rotates the byte at every position selected by `lanes` one bit to the right: plane `k` takes +/// plane `k + 1` (mod 8) at those positions. See [`rotate_bytes_left_at`]. +fn rotate_bytes_right_at(q: &mut Planes, lanes: u32) { + let old = *q; + for k in 0..8 { + q[k] = (old[k] & !lanes) | (old[(k + 1) % 8] & lanes); + } +} + +/// The S-box layer of the F-function (Sec 2.4.1): `t1 = SBOX1[t1]; t2 = SBOX2[t2]; t3 = SBOX3[t3]; +/// t4 = SBOX4[t4]; t5 = SBOX2[t5]; t6 = SBOX3[t6]; t7 = SBOX4[t7]; t8 = SBOX1[t8]`, on the +/// 64-bit `x` of one F-function from each of four blocks at once. +/// +/// `x[b]` is `x` for block `b`, big-endian as Sec 2.4.1 reads it: `t1 = x >> 56` is the most +/// significant byte. Each word is split into its two 32-bit halves -- the high halves in plane +/// words `0 .. 4`, the low halves in `4 .. 8` -- and the eight words are transposed into +/// bit-planes; the bytes bound for `SBOX4` are rotated left one bit (`SBOX4[x] = SBOX1[x <<< 1]`); +/// one pass of [`sbox`] substitutes all 32 bytes; the bytes that came from `SBOX2` positions are +/// rotated left (`SBOX2[x] = SBOX1[x] <<< 1`) and those from `SBOX3` positions right +/// (`SBOX3[x] = SBOX1[x] <<< 7`, which on a byte is a rotate right by one); the planes are +/// transposed back and the halves rejoined. [`ortho`] being its own inverse is what returns each +/// substituted byte to its original position. +pub(crate) fn sboxes(x: &mut [u64; LANES]) { + let mut q: Planes = [0; 8]; + for b in 0..LANES { + q[b] = (x[b] >> 32) as u32; + q[LANES + b] = x[b] as u32; + } + ortho(&mut q); + rotate_bytes_left_at(&mut q, SBOX4_LANES); + sbox(&mut q); + rotate_bytes_left_at(&mut q, SBOX2_LANES); + rotate_bytes_right_at(&mut q, SBOX3_LANES); + ortho(&mut q); + for b in 0..LANES { + // The two halves occupy disjoint bit ranges, so `|` and `^` agree here (a surviving + // `cargo mutants` equivalence, as in `round::p`). + x[b] = ((q[b] as u64) << 32) | q[LANES + b] as u64; + } +} + +#[cfg(test)] +pub(crate) mod tests { + use super::*; + + /// Sec 2.4.1, the `SBOX1` table, row-major: `SBOX1[16 * row + column]`. Extracted mechanically + /// from the text of RFC 3713 (the table is decimal there, and is kept decimal here so it can + /// be diffed against the RFC); byte-for-byte the `SBOX1` array in BC Java's + /// `CamelliaLightEngine`. Test data only -- the engine never reads it. + #[rustfmt::skip] + pub(crate) const SBOX1: [u8; 256] = [ + 112, 130, 44, 236, 179, 39, 192, 229, 228, 133, 87, 53, 234, 12, 174, 65, + 35, 239, 107, 147, 69, 25, 165, 33, 237, 14, 79, 78, 29, 101, 146, 189, + 134, 184, 175, 143, 124, 235, 31, 206, 62, 48, 220, 95, 94, 197, 11, 26, + 166, 225, 57, 202, 213, 71, 93, 61, 217, 1, 90, 214, 81, 86, 108, 77, + 139, 13, 154, 102, 251, 204, 176, 45, 116, 18, 43, 32, 240, 177, 132, 153, + 223, 76, 203, 194, 52, 126, 118, 5, 109, 183, 169, 49, 209, 23, 4, 215, + 20, 88, 58, 97, 222, 27, 17, 28, 50, 15, 156, 22, 83, 24, 242, 34, + 254, 68, 207, 178, 195, 181, 122, 145, 36, 8, 232, 168, 96, 252, 105, 80, + 170, 208, 160, 125, 161, 137, 98, 151, 84, 91, 30, 149, 224, 255, 100, 210, + 16, 196, 0, 72, 163, 247, 117, 219, 138, 3, 230, 218, 9, 63, 221, 148, + 135, 92, 131, 2, 205, 74, 144, 51, 115, 103, 246, 243, 157, 127, 191, 226, + 82, 155, 216, 38, 200, 55, 198, 59, 129, 150, 111, 75, 19, 190, 99, 46, + 233, 121, 167, 140, 159, 110, 188, 142, 41, 245, 249, 182, 47, 253, 180, 89, + 120, 152, 6, 106, 231, 70, 113, 186, 212, 37, 171, 66, 136, 162, 141, 250, + 114, 7, 185, 85, 248, 238, 172, 10, 54, 73, 42, 104, 60, 56, 241, 164, + 64, 40, 211, 123, 187, 201, 67, 193, 21, 227, 173, 244, 119, 199, 128, 158, + ]; + + /// `SBOX2[x] = SBOX1[x] <<< 1` (Sec 2.4.1). + fn sbox2(x: u8) -> u8 { + SBOX1[x as usize].rotate_left(1) + } + /// `SBOX3[x] = SBOX1[x] <<< 7` (Sec 2.4.1). + fn sbox3(x: u8) -> u8 { + SBOX1[x as usize].rotate_left(7) + } + /// `SBOX4[x] = SBOX1[x <<< 1]` (Sec 2.4.1). + fn sbox4(x: u8) -> u8 { + SBOX1[x.rotate_left(1) as usize] + } + + /// The table-driven S-box layer, on one word: `t1 .. t8` through `SBOX1, 2, 3, 4, 2, 3, 4, 1`. + pub(crate) fn sboxes_table(x: u64) -> u64 { + let [t1, t2, t3, t4, t5, t6, t7, t8] = x.to_be_bytes(); + u64::from_be_bytes([ + SBOX1[t1 as usize], + sbox2(t2), + sbox3(t3), + sbox4(t4), + sbox2(t5), + sbox3(t6), + sbox4(t7), + SBOX1[t8 as usize], + ]) + } + + #[test] + fn test_table_matches_the_worked_example() { + // Sec 2.4.1: "For example, SBOX1[0x3d] equals 86." Pins the row-major flattening. + assert_eq!(SBOX1[0x3d], 86); + assert_eq!(SBOX1[0x00], 112); + assert_eq!(SBOX1[0x0f], 65); + assert_eq!(SBOX1[0xf0], 64); + assert_eq!(SBOX1[0xff], 158); + // A permutation of 0..=255. + let mut seen = [false; 256]; + for &v in SBOX1.iter() { + seen[v as usize] = true; + } + assert!(seen.iter().all(|&s| s)); + } + + #[test] + fn test_sbox_matches_rfc_3713_sbox1() { + // Exhaustive: all 256 inputs. 32 byte positions per pass, so eight passes cover them all, + // with the byte value `32 * pass + position` at each position. This is what makes the + // generated gate list trustworthy, so it must stay exhaustive. + for pass in 0..8u32 { + let mut q: Planes = core::array::from_fn(|w| { + let base = 32 * pass + 4 * w as u32; + u32::from_le_bytes(core::array::from_fn(|j| (base + j as u32) as u8)) + }); + let inputs = q; + ortho(&mut q); + sbox(&mut q); + ortho(&mut q); + for (w, (got, input)) in q.iter().zip(inputs.iter()).enumerate() { + for (byte, expected) in got + .to_le_bytes() + .iter() + .zip(input.to_le_bytes().iter().map(|&b| SBOX1[b as usize])) + { + assert_eq!(*byte, expected, "pass {pass}, word {w}, input {input:#010x}"); + } + } + } + } + + #[test] + fn test_sboxes_apply_the_four_tables_to_the_right_bytes() { + // Exhaustive per value: every byte position holds the same value v, in all four lanes, so + // each position's output must be its own table's entry for v. This is what pins the three + // position masks and the direction of each rotation. + for v in 0..=255u8 { + let word = u64::from_be_bytes([v; 8]); + let mut words = [word; LANES]; + sboxes(&mut words); + let expected = sboxes_table(word); + for (lane, got) in words.iter().enumerate() { + assert_eq!(*got, expected, "value {v:#04x}, lane {lane}"); + } + assert_eq!( + expected.to_be_bytes(), + [ + SBOX1[v as usize], + sbox2(v), + sbox3(v), + sbox4(v), + sbox2(v), + sbox3(v), + sbox4(v), + SBOX1[v as usize] + ] + ); + } + } + + #[test] + fn test_sboxes_lanes_are_independent() { + // Changing one word must not change any other word's output, and each word must get the + // table-driven answer for its own bytes. + let base: [u64; LANES] = + core::array::from_fn(|i| 0x0123_4567_89AB_CDEFu64.wrapping_mul(2 * i as u64 + 1)); + let mut expected = base; + sboxes(&mut expected); + for (lane, e) in expected.iter().enumerate() { + assert_eq!(*e, sboxes_table(base[lane]), "lane {lane}"); + } + for lane in 0..LANES { + let mut words = base; + words[lane] ^= 0xA5A5_5A5A_0F0F_F0F0; + sboxes(&mut words); + for other in (0..LANES).filter(|&o| o != lane) { + assert_eq!(words[other], expected[other], "lane {lane} disturbed lane {other}"); + } + assert_eq!(words[lane], sboxes_table(base[lane] ^ 0xA5A5_5A5A_0F0F_F0F0)); + } + } + + #[test] + fn test_rotations_move_exactly_the_selected_lanes() { + // A single set bit at plane k, position p: rotate-left moves it to plane k+1 if p is in + // the mask and leaves it alone otherwise; rotate-right, to plane k-1. + for k in 0..8 { + for p in 0..32 { + let mut q: Planes = [0; 8]; + q[k] = 1 << p; + let mut l = q; + rotate_bytes_left_at(&mut l, SBOX2_LANES); + let mut r = q; + rotate_bytes_right_at(&mut r, SBOX2_LANES); + let mut el: Planes = [0; 8]; + let mut er: Planes = [0; 8]; + if SBOX2_LANES >> p & 1 == 1 { + el[(k + 1) % 8] = 1 << p; + er[(k + 7) % 8] = 1 << p; + } else { + el[k] = 1 << p; + er[k] = 1 << p; + } + assert_eq!(l, el, "left, plane {k}, position {p}"); + assert_eq!(r, er, "right, plane {k}, position {p}"); + } + } + } + + #[test] + fn test_position_masks_are_the_documented_bytes() { + // Byte L of a half is bits 8L..8L+7 of a plane, of which the low nibble is the four high + // halves (t1 = byte 3 .. t4 = byte 0) and the high nibble the four low halves + // (t5 = byte 3 .. t8 = byte 0). + let high = |l: u32| 0x0Fu32 << (8 * l); + let low = |l: u32| 0xF0u32 << (8 * l); + assert_eq!(SBOX2_LANES, high(2) | low(3), "t2 and t5"); + assert_eq!(SBOX3_LANES, high(1) | low(2), "t3 and t6"); + assert_eq!(SBOX4_LANES, high(0) | low(1), "t4 and t7"); + assert_eq!(SBOX2_LANES & SBOX3_LANES, 0); + assert_eq!(SBOX2_LANES & SBOX4_LANES, 0); + assert_eq!(SBOX3_LANES & SBOX4_LANES, 0); + assert_eq!(!(SBOX2_LANES | SBOX3_LANES | SBOX4_LANES), high(3) | low(0), "t1 and t8"); + } + + #[test] + fn test_sboxes_places_the_halves_where_the_masks_expect() { + // A single byte set in block b's input must be substituted by the S-box the RFC assigns to + // that byte and land back in the same place, with the other three blocks untouched. + for b in 0..LANES { + for (i, sbox_i) in + [(0usize, 1u8), (1, 2), (2, 3), (3, 4), (4, 2), (5, 3), (6, 4), (7, 1)] + { + let mut x = [0u64; LANES]; + let mut bytes = [0u8; 8]; + bytes[i] = 0x3d; + x[b] = u64::from_be_bytes(bytes); + let mut got = x; + sboxes(&mut got); + let mut expected = [sboxes_table(0); LANES]; + expected[b] = sboxes_table(x[b]); + assert_eq!(got, expected, "block {b}, t{} through SBOX{sbox_i}", i + 1); + } + } + } +} diff --git a/crypto/camellia/src/schedule.rs b/crypto/camellia/src/schedule.rs new file mode 100644 index 000000000..35b04c92d --- /dev/null +++ b/crypto/camellia/src/schedule.rs @@ -0,0 +1,411 @@ +//! The key scheduling part (RFC 3713 Sec 2.2), and the parameter sets that distinguish the three +//! key lengths. +//! +//! The schedule is the whole set of 64-bit subkeys the data randomizing part reads: the four +//! whitening keys `kw1 .. kw4`, the 18 or 24 round keys `k1 .. k18` / `k1 .. k24`, and the four or +//! six FL/FLINV keys `ke1 .. ke4` / `ke1 .. ke6` -- 26 words (208 bytes) for a 128-bit key, 34 +//! words (272 bytes) for 192- and 256-bit keys. It is computed once by [`expand`] and stored in a +//! [`Secret`]. Decryption uses the same words in the swapped order of Sec 2.3.3, so there is no +//! second schedule: this crate stores the encryption order and lets +//! [`crate::hazmat::CamelliaInternal::decrypt_4blocks`] index it the other way, rather than +//! writing the subkeys into decryption positions when initialised for decryption. +//! +//! # Layout +//! +//! One flat `[u64; N]`, in the RFC's numbering: `kw_i` at `[i - 1]`, `k_i` at `[3 + i]`, `ke_i` +//! at `[3 + ROUNDS + i]`. The accessors [`kw`], [`k`] and [`ke`] take the RFC's 1-based index so +//! that the round loop and the Sec 2.3.3 swap can be read against the text. +//! +//! # Constant-time +//! +//! The schedule routes secret key material through the F-function -- six times, with the `Sigma` +//! constants as the keys -- so the expansion needs the same treatment as the cipher: [`f1`] is the +//! bit-sliced circuit of [`crate::sbox`], not a table. The rest of the schedule is rotations of +//! 128-bit values by public amounts. + +use crate::round::f1; +use bouncycastle_utils::secret::{NoPadding, Secret, ZeroizablePrimitive}; + +/// Sealed: the three parameter sets are the only implementors. The key-schedule steps that +/// differ by key length live here, off the public trait. +mod sealed { + pub trait CamelliaParamsInternalTrait { + /// `KL` and `KR` from the key (Sec 2.2, "128-bit key K:" / "192-bit key K:" / "256-bit + /// key K:"). `k` is the key as big-endian 64-bit words, `KEY_LEN / 8` of them -- the + /// engine checks the length before calling, so the indexing here is in bounds by + /// construction. + fn kl_kr(k: &[u64]) -> (u128, u128); + + /// Fills the schedule from `KL`, `KR`, `KA`, `KB` (Sec 2.2, the subkey tables). + fn subkeys(kl: u128, kr: u128, ka: u128, kb: u128, schedule: &mut [u64]); + } +} +pub(crate) use sealed::CamelliaParamsInternalTrait; + +/// The parameters that distinguish Camellia-128 from Camellia-192 and Camellia-256 +/// (RFC 3713 Sec 2.2 and Sec 2.3). +/// +/// Sealed: implemented by `Camellia128Params`, `Camellia192Params` and `Camellia256Params` +/// only, so there is no fourth instantiation. +pub trait CamelliaParams: CamelliaParamsInternalTrait { + /// Key length in bytes: 16, 24 or 32. + const KEY_LEN: usize; + /// Rounds of the Feistel structure: 18 for 128-bit keys (Sec 2.3.1), 24 otherwise (Sec 2.3.2). + const ROUNDS: usize; + /// FL/FLINV subkeys: `ke1 .. ke4` for 18 rounds, `ke1 .. ke6` for 24 -- one pair per FL layer, + /// a layer every six rounds except after the last. + const FL_KEYS: usize; + /// The algorithm name, as reported by `Algorithm::ALG_NAME`. + const ALG_NAME: &'static str; + /// `[u64; 4 + ROUNDS + FL_KEYS]` -- the subkeys. See the module docs for the layout. + type Schedule: ZeroizablePrimitive + NoPadding + AsRef<[u64]> + AsMut<[u64]>; +} + +/// Camellia-128 parameters: 16-byte key, 18 rounds, `ke1 .. ke4`. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Camellia128Params; +/// Camellia-192 parameters: 24-byte key, 24 rounds, `ke1 .. ke6`. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Camellia192Params; +/// Camellia-256 parameters: 32-byte key, 24 rounds, `ke1 .. ke6`. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Camellia256Params; + +impl CamelliaParamsInternalTrait for Camellia128Params { + /// `KL = K; KR = 0;` + fn kl_kr(k: &[u64]) -> (u128, u128) { + (join(k[0], k[1]), 0) + } + + fn subkeys(kl: u128, kr: u128, ka: u128, kb: u128, schedule: &mut [u64]) { + subkeys_128(kl, kr, ka, kb, schedule) + } +} + +impl CamelliaParamsInternalTrait for Camellia192Params { + /// `KL = K >> 64; KR = ((K & MASK64) << 64) | (~(K & MASK64));` -- the leftmost 128 bits are + /// `KL`, and `KR` is the rightmost 64 bits followed by their complement. + fn kl_kr(k: &[u64]) -> (u128, u128) { + (join(k[0], k[1]), join(k[2], !k[2])) + } + + fn subkeys(kl: u128, kr: u128, ka: u128, kb: u128, schedule: &mut [u64]) { + subkeys_192_256(kl, kr, ka, kb, schedule) + } +} + +impl CamelliaParamsInternalTrait for Camellia256Params { + /// `KL = K >> 128; KR = K & MASK128;` + fn kl_kr(k: &[u64]) -> (u128, u128) { + (join(k[0], k[1]), join(k[2], k[3])) + } + + fn subkeys(kl: u128, kr: u128, ka: u128, kb: u128, schedule: &mut [u64]) { + subkeys_192_256(kl, kr, ka, kb, schedule) + } +} + +/// `(hi << 64) | lo`: joins two 64-bit words into a 128-bit value. +/// +/// The two operands occupy disjoint bit ranges, so `|` and `^` compute the same function here; +/// `cargo mutants` reports that `| -> ^` mutant as surviving, and it is an equivalence, not a gap. +#[inline(always)] +fn join(hi: u64, lo: u64) -> u128 { + ((hi as u128) << 64) | lo as u128 +} + +impl CamelliaParams for Camellia128Params { + const KEY_LEN: usize = 16; + const ROUNDS: usize = 18; + const FL_KEYS: usize = 4; + const ALG_NAME: &'static str = "Camellia-128"; + type Schedule = [u64; 26]; // 4 + 18 + 4 +} + +impl CamelliaParams for Camellia192Params { + const KEY_LEN: usize = 24; + const ROUNDS: usize = 24; + const FL_KEYS: usize = 6; + const ALG_NAME: &'static str = "Camellia-192"; + type Schedule = [u64; 34]; // 4 + 24 + 6 +} + +impl CamelliaParams for Camellia256Params { + const KEY_LEN: usize = 32; + const ROUNDS: usize = 24; + const FL_KEYS: usize = 6; + const ALG_NAME: &'static str = "Camellia-256"; + type Schedule = [u64; 34]; // 4 + 24 + 6 +} + +/// `Sigma1 .. Sigma6` (Sec 2.2), "used as 'keys' in the F-function" when deriving `KA` and `KB`. +/// Transcribed from the text of RFC 3713. +pub(crate) const SIGMA: [u64; 6] = [ + 0xA09E_667F_3BCC_908B, 0xB67A_E858_4CAA_73B2, 0xC6EF_372F_E94F_82BE, 0x54FF_53A5_F1D3_6F1C, + 0x10E5_27FA_DE68_2D1D, 0xB056_88C2_B3E6_C1FD, +]; + +/// `kw_i`, `i` in `1..=4`. +#[inline(always)] +pub(crate) fn kw(schedule: &[u64], i: usize) -> u64 { + schedule[i - 1] +} + +/// `k_i`, `i` in `1..=ROUNDS`. +#[inline(always)] +pub(crate) fn k(schedule: &[u64], i: usize) -> u64 { + schedule[3 + i] +} + +/// `ke_i`, `i` in `1..=FL_KEYS`. +#[inline(always)] +pub(crate) fn ke(schedule: &[u64], i: usize) -> u64 { + schedule[3 + P::ROUNDS + i] +} + +/// `(X <<< rot) >> 64`: the left half of a rotated 128-bit value. +#[inline(always)] +fn left(x: u128, rot: u32) -> u64 { + (x.rotate_left(rot) >> 64) as u64 +} + +/// `(X <<< rot) & MASK64`: the right half of a rotated 128-bit value. +#[inline(always)] +fn right(x: u128, rot: u32) -> u64 { + x.rotate_left(rot) as u64 +} + +/// Sec 2.2, "For 128-bit keys, 64-bit subkeys kw1, ..., kw4, k1, ..., k18, ke1, ..., ke4 are +/// generated as follows." One line per line of the RFC; `KR` and `KB` are unused, as the text +/// says ("KB is used only if the length of the secret key is 192 or 256 bits"). +fn subkeys_128(kl: u128, _kr: u128, ka: u128, _kb: u128, s: &mut [u64]) { + let mut set_kw = |i: usize, v: u64| s[i - 1] = v; + set_kw(1, left(kl, 0)); // kw1 = (KL <<< 0) >> 64; + set_kw(2, right(kl, 0)); // kw2 = (KL <<< 0) & MASK64; + let mut set_k = |i: usize, v: u64| s[3 + i] = v; + set_k(1, left(ka, 0)); // k1 = (KA <<< 0) >> 64; + set_k(2, right(ka, 0)); // k2 = (KA <<< 0) & MASK64; + set_k(3, left(kl, 15)); // k3 = (KL <<< 15) >> 64; + set_k(4, right(kl, 15)); // k4 = (KL <<< 15) & MASK64; + set_k(5, left(ka, 15)); // k5 = (KA <<< 15) >> 64; + set_k(6, right(ka, 15)); // k6 = (KA <<< 15) & MASK64; + let mut set_ke = |i: usize, v: u64| s[3 + 18 + i] = v; + set_ke(1, left(ka, 30)); // ke1 = (KA <<< 30) >> 64; + set_ke(2, right(ka, 30)); // ke2 = (KA <<< 30) & MASK64; + let mut set_k = |i: usize, v: u64| s[3 + i] = v; + set_k(7, left(kl, 45)); // k7 = (KL <<< 45) >> 64; + set_k(8, right(kl, 45)); // k8 = (KL <<< 45) & MASK64; + set_k(9, left(ka, 45)); // k9 = (KA <<< 45) >> 64; + set_k(10, right(kl, 60)); // k10 = (KL <<< 60) & MASK64; + set_k(11, left(ka, 60)); // k11 = (KA <<< 60) >> 64; + set_k(12, right(ka, 60)); // k12 = (KA <<< 60) & MASK64; + let mut set_ke = |i: usize, v: u64| s[3 + 18 + i] = v; + set_ke(3, left(kl, 77)); // ke3 = (KL <<< 77) >> 64; + set_ke(4, right(kl, 77)); // ke4 = (KL <<< 77) & MASK64; + let mut set_k = |i: usize, v: u64| s[3 + i] = v; + set_k(13, left(kl, 94)); // k13 = (KL <<< 94) >> 64; + set_k(14, right(kl, 94)); // k14 = (KL <<< 94) & MASK64; + set_k(15, left(ka, 94)); // k15 = (KA <<< 94) >> 64; + set_k(16, right(ka, 94)); // k16 = (KA <<< 94) & MASK64; + set_k(17, left(kl, 111)); // k17 = (KL <<< 111) >> 64; + set_k(18, right(kl, 111)); // k18 = (KL <<< 111) & MASK64; + let mut set_kw = |i: usize, v: u64| s[i - 1] = v; + set_kw(3, left(ka, 111)); // kw3 = (KA <<< 111) >> 64; + set_kw(4, right(ka, 111)); // kw4 = (KA <<< 111) & MASK64; +} + +/// Sec 2.2, "For 192- and 256-bit keys, 64-bit subkeys kw1, ..., kw4, k1, ..., k24, ke1, ..., +/// ke6 are generated as follows." One line per line of the RFC. +fn subkeys_192_256(kl: u128, kr: u128, ka: u128, kb: u128, s: &mut [u64]) { + let mut set_kw = |i: usize, v: u64| s[i - 1] = v; + set_kw(1, left(kl, 0)); // kw1 = (KL <<< 0) >> 64; + set_kw(2, right(kl, 0)); // kw2 = (KL <<< 0) & MASK64; + let mut set_k = |i: usize, v: u64| s[3 + i] = v; + set_k(1, left(kb, 0)); // k1 = (KB <<< 0) >> 64; + set_k(2, right(kb, 0)); // k2 = (KB <<< 0) & MASK64; + set_k(3, left(kr, 15)); // k3 = (KR <<< 15) >> 64; + set_k(4, right(kr, 15)); // k4 = (KR <<< 15) & MASK64; + set_k(5, left(ka, 15)); // k5 = (KA <<< 15) >> 64; + set_k(6, right(ka, 15)); // k6 = (KA <<< 15) & MASK64; + let mut set_ke = |i: usize, v: u64| s[3 + 24 + i] = v; + set_ke(1, left(kr, 30)); // ke1 = (KR <<< 30) >> 64; + set_ke(2, right(kr, 30)); // ke2 = (KR <<< 30) & MASK64; + let mut set_k = |i: usize, v: u64| s[3 + i] = v; + set_k(7, left(kb, 30)); // k7 = (KB <<< 30) >> 64; + set_k(8, right(kb, 30)); // k8 = (KB <<< 30) & MASK64; + set_k(9, left(kl, 45)); // k9 = (KL <<< 45) >> 64; + set_k(10, right(kl, 45)); // k10 = (KL <<< 45) & MASK64; + set_k(11, left(ka, 45)); // k11 = (KA <<< 45) >> 64; + set_k(12, right(ka, 45)); // k12 = (KA <<< 45) & MASK64; + let mut set_ke = |i: usize, v: u64| s[3 + 24 + i] = v; + set_ke(3, left(kl, 60)); // ke3 = (KL <<< 60) >> 64; + set_ke(4, right(kl, 60)); // ke4 = (KL <<< 60) & MASK64; + let mut set_k = |i: usize, v: u64| s[3 + i] = v; + set_k(13, left(kr, 60)); // k13 = (KR <<< 60) >> 64; + set_k(14, right(kr, 60)); // k14 = (KR <<< 60) & MASK64; + set_k(15, left(kb, 60)); // k15 = (KB <<< 60) >> 64; + set_k(16, right(kb, 60)); // k16 = (KB <<< 60) & MASK64; + set_k(17, left(kl, 77)); // k17 = (KL <<< 77) >> 64; + set_k(18, right(kl, 77)); // k18 = (KL <<< 77) & MASK64; + let mut set_ke = |i: usize, v: u64| s[3 + 24 + i] = v; + set_ke(5, left(ka, 77)); // ke5 = (KA <<< 77) >> 64; + set_ke(6, right(ka, 77)); // ke6 = (KA <<< 77) & MASK64; + let mut set_k = |i: usize, v: u64| s[3 + i] = v; + set_k(19, left(kr, 94)); // k19 = (KR <<< 94) >> 64; + set_k(20, right(kr, 94)); // k20 = (KR <<< 94) & MASK64; + set_k(21, left(ka, 94)); // k21 = (KA <<< 94) >> 64; + set_k(22, right(ka, 94)); // k22 = (KA <<< 94) & MASK64; + set_k(23, left(kl, 111)); // k23 = (KL <<< 111) >> 64; + set_k(24, right(kl, 111)); // k24 = (KL <<< 111) & MASK64; + let mut set_kw = |i: usize, v: u64| s[i - 1] = v; + set_kw(3, left(kb, 111)); // kw3 = (KB <<< 111) >> 64; + set_kw(4, right(kb, 111)); // kw4 = (KB <<< 111) & MASK64; +} + +/// Expands a key into the subkeys (Sec 2.2). `key` is exactly `P::KEY_LEN` bytes -- the engine +/// checks that before calling. +/// +/// Line by line against Sec 2.2, "The 128-bit variables KA and KB are generated from KL and KR as +/// follows": +/// +/// ```text +/// D1 = (KL ^ KR) >> 64; D2 = (KL ^ KR) & MASK64; +/// D2 = D2 ^ F(D1, Sigma1); D1 = D1 ^ F(D2, Sigma2); +/// D1 = D1 ^ (KL >> 64); D2 = D2 ^ (KL & MASK64); +/// D2 = D2 ^ F(D1, Sigma3); D1 = D1 ^ F(D2, Sigma4); +/// KA = (D1 << 64) | D2; +/// D1 = (KA ^ KR) >> 64; D2 = (KA ^ KR) & MASK64; +/// D2 = D2 ^ F(D1, Sigma5); D1 = D1 ^ F(D2, Sigma6); +/// KB = (D1 << 64) | D2; +/// ``` +/// +/// `KB` is computed for every key length, although Sec 2.2 notes it "is used only if the length of +/// the secret key is 192 or 256 bits": two F-function calls, once per key, buy a single code path +/// with no length-dependent branch. Then the subkey table for the key length fills the schedule. +pub(crate) fn expand(key: &[u8]) -> Secret { + // The key as big-endian 64-bit words. KEY_LEN is a multiple of eight, so the remainder is + // provably empty and ignored. + let (words, _) = key.as_chunks::<8>(); + let mut k = Secret::<[u64; 4]>::new(); + for (w, bytes) in k.iter_mut().zip(words) { + *w = u64::from_be_bytes(*bytes); + } + + // KL, KR, and then KA, KB, held in a Secret so they are scrubbed on return. + let mut kx = Secret::<[u128; 4]>::new(); + (kx[0], kx[1]) = P::kl_kr(&k[..P::KEY_LEN / 8]); + let (kl, kr) = (kx[0], kx[1]); + + // D1, D2: 64-bit temporaries, likewise. + let mut d = Secret::<[u64; 2]>::new(); + d[0] = ((kl ^ kr) >> 64) as u64; // D1 = (KL ^ KR) >> 64; + d[1] = (kl ^ kr) as u64; // D2 = (KL ^ KR) & MASK64; + d[1] ^= f1(d[0], SIGMA[0]); // D2 = D2 ^ F(D1, Sigma1); + d[0] ^= f1(d[1], SIGMA[1]); // D1 = D1 ^ F(D2, Sigma2); + d[0] ^= (kl >> 64) as u64; // D1 = D1 ^ (KL >> 64); + d[1] ^= kl as u64; // D2 = D2 ^ (KL & MASK64); + d[1] ^= f1(d[0], SIGMA[2]); // D2 = D2 ^ F(D1, Sigma3); + d[0] ^= f1(d[1], SIGMA[3]); // D1 = D1 ^ F(D2, Sigma4); + kx[2] = join(d[0], d[1]); // KA = (D1 << 64) | D2; + let ka = kx[2]; + d[0] = ((ka ^ kr) >> 64) as u64; // D1 = (KA ^ KR) >> 64; + d[1] = (ka ^ kr) as u64; // D2 = (KA ^ KR) & MASK64; + d[1] ^= f1(d[0], SIGMA[4]); // D2 = D2 ^ F(D1, Sigma5); + d[0] ^= f1(d[1], SIGMA[5]); // D1 = D1 ^ F(D2, Sigma6); + kx[3] = join(d[0], d[1]); // KB = (D1 << 64) | D2; + + let mut schedule = Secret::::new(); + P::subkeys(kx[0], kx[1], kx[2], kx[3], schedule.as_mut()); + schedule +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_schedule_lengths_match_the_layout() { + // 4 kw + ROUNDS k + FL_KEYS ke, and one FL layer (two keys) per six rounds bar the last. + assert_eq!(size_of::<::Schedule>(), 8 * (4 + 18 + 4)); + assert_eq!(size_of::<::Schedule>(), 8 * (4 + 24 + 6)); + assert_eq!(size_of::<::Schedule>(), 8 * (4 + 24 + 6)); + assert_eq!(Camellia128Params::FL_KEYS, 2 * (Camellia128Params::ROUNDS / 6 - 1)); + assert_eq!(Camellia192Params::FL_KEYS, 2 * (Camellia192Params::ROUNDS / 6 - 1)); + assert_eq!(Camellia256Params::FL_KEYS, 2 * (Camellia256Params::ROUNDS / 6 - 1)); + } + + #[test] + fn test_accessors_index_the_documented_layout() { + let s: [u64; 34] = core::array::from_fn(|i| 1000 + i as u64); + assert_eq!(kw(&s, 1), 1000); + assert_eq!(kw(&s, 4), 1003); + assert_eq!(k(&s, 1), 1004); + assert_eq!(k(&s, 24), 1027); + assert_eq!(ke::(&s, 1), 1028); + assert_eq!(ke::(&s, 6), 1033); + let s: [u64; 26] = core::array::from_fn(|i| 1000 + i as u64); + assert_eq!(k(&s, 18), 1021); + assert_eq!(ke::(&s, 1), 1022); + assert_eq!(ke::(&s, 4), 1025); + } + + #[test] + fn test_kl_kr_for_each_key_length() { + let key: [u64; 4] = [ + 0x0001_0203_0405_0607, 0x0809_0A0B_0C0D_0E0F, 0x1011_1213_1415_1617, + 0x1819_1A1B_1C1D_1E1F, + ]; + let k0 = 0x0001_0203_0405_0607_0809_0A0B_0C0D_0E0Fu128; + let k1 = 0x1011_1213_1415_1617_1819_1A1B_1C1D_1E1Fu128; + // 128-bit key K: KL = K; KR = 0; + assert_eq!(Camellia128Params::kl_kr(&key[..2]), (k0, 0)); + // 192-bit key K: KL = K >> 64; KR = ((K & MASK64) << 64) | (~(K & MASK64)); + let (kl, kr) = Camellia192Params::kl_kr(&key[..3]); + assert_eq!(kl, k0); + assert_eq!(kr, (0x1011_1213_1415_1617u128 << 64) | (!0x1011_1213_1415_1617u64) as u128); + // 256-bit key K: KL = K >> 128; KR = K & MASK128; + assert_eq!(Camellia256Params::kl_kr(&key), (k0, k1)); + } + + #[test] + fn test_whitening_keys_are_the_key_itself() { + // kw1 = (KL <<< 0) >> 64 and kw2 = (KL <<< 0) & MASK64: the first 16 bytes of every key, + // unchanged, for all three lengths. A direct consequence of the tables that needs no + // vectors. + let key: [u8; 32] = core::array::from_fn(|i| (i as u8).wrapping_mul(37).wrapping_add(11)); + let (words, _) = key.as_chunks::<8>(); + let (w0, w1) = (u64::from_be_bytes(words[0]), u64::from_be_bytes(words[1])); + let s = expand::(&key[..16]); + assert_eq!(kw(s.as_ref(), 1), w0); + assert_eq!(kw(s.as_ref(), 2), w1); + let s = expand::(&key[..24]); + assert_eq!(kw(s.as_ref(), 1), w0); + let s = expand::(&key); + assert_eq!(kw(s.as_ref(), 2), w1); + } + + #[test] + fn test_rotations_split_as_the_rfc_reads() { + // (X <<< rot) >> 64 and (X <<< rot) & MASK64, by hand on a value with one bit at each end. + let x = 0x8000_0000_0000_0000_0000_0000_0000_0001u128; + assert_eq!(left(x, 0), 0x8000_0000_0000_0000); + assert_eq!(right(x, 0), 1); + // <<< 15: bit 127 wraps to bit 14 and bit 0 moves to bit 15, both in the right half. + assert_eq!(left(x, 15), 0); + assert_eq!(right(x, 15), (1 << 14) | (1 << 15)); + // <<< 77: bit 127 wraps to bit 76 and bit 0 moves to bit 77, both in the left half, whose + // bit 0 is bit 64 of the whole. + assert_eq!(left(x, 77), (1 << 12) | (1 << 13)); + assert_eq!(right(x, 77), 0); + } + + #[test] + fn test_sigma_constants_match_section_2_2() { + assert_eq!(SIGMA[0], 0xA09E667F3BCC908B); + assert_eq!(SIGMA[1], 0xB67AE8584CAA73B2); + assert_eq!(SIGMA[2], 0xC6EF372FE94F82BE); + assert_eq!(SIGMA[3], 0x54FF53A5F1D36F1C); + assert_eq!(SIGMA[4], 0x10E527FADE682D1D); + assert_eq!(SIGMA[5], 0xB05688C2B3E6C1FD); + } +} diff --git a/crypto/camellia/tests/alg_name_tests.rs b/crypto/camellia/tests/alg_name_tests.rs new file mode 100644 index 000000000..679d2013d --- /dev/null +++ b/crypto/camellia/tests/alg_name_tests.rs @@ -0,0 +1,228 @@ +//! What each public Camellia alias is: the algorithm it reports and the type it resolves to. +//! +//! Each alias reports its own algorithm through `Algorithm`, not the engine it is built on: +//! `Camellia_CBC_128` is `"Camellia_CBC_128"`, while `Camellia128Internal` stays +//! `"Camellia-128"`. The strength is the key's. The direction and the padding are type parameters +//! of one algorithm, not different algorithms, so every combination of them must report the same +//! name. + +use bouncycastle_camellia::hazmat::{ + Camellia128Internal, Camellia192Internal, Camellia256Internal, +}; +use bouncycastle_camellia::{ + BLOCK_LEN, CTR_NONCE_LEN, Camellia_CBC_128, Camellia_CBC_192, Camellia_CBC_256, + Camellia_CFB_128, Camellia_CFB_192, Camellia_CFB_256, Camellia_CFB8_128, Camellia_CFB8_192, + Camellia_CFB8_256, Camellia_CTR_128, Camellia_CTR_192, Camellia_CTR_256, Camellia_KW_128, + Camellia_KW_192, Camellia_KW_256, Camellia128Key, LANES, +}; +use bouncycastle_cipher::modes::{CBC, CFB, CFB8, CTR, Cbc, Cfb, Cfb8, Ctr}; +use bouncycastle_cipher::padding::{ + NoPadding, PKCS7, PaddedBlockCipherDecryptor, PaddedBlockCipherEncryptor, +}; +use bouncycastle_cipher::{Decrypting, Encrypting}; +use bouncycastle_core::key_material::{KeyMaterial, KeyType}; +use bouncycastle_core::security_strength::SecurityStrength; +use bouncycastle_core::symmetric_key::{ + FromKeyMaterial, SymmetricDecryptionKey, SymmetricEncryptionKey, +}; +use bouncycastle_core::traits::Algorithm; +use bouncycastle_rng::HashDRBG_SHA512; +use core::mem::size_of; + +/// Both directions of one algorithm report `name` and `strength`. +fn check(name: &str, strength: SecurityStrength) { + assert_eq!(Enc::ALG_NAME, name); + assert_eq!(Dec::ALG_NAME, name); + assert_eq!(Enc::MAX_SECURITY_STRENGTH, strength, "{name}"); + assert_eq!(Dec::MAX_SECURITY_STRENGTH, strength, "{name}"); +} + +#[test] +fn cbc() { + use SecurityStrength::*; + check::, Camellia_CBC_128<'_, Decrypting, PKCS7>>( + "Camellia_CBC_128", _128bit, + ); + type NoPadEnc<'k> = Camellia_CBC_128<'k, Encrypting, NoPadding>; + type NoPadDec<'k> = Camellia_CBC_128<'k, Decrypting, NoPadding>; + check::, NoPadDec<'_>>("Camellia_CBC_128", _128bit); + check::, Camellia_CBC_192<'_, Decrypting, PKCS7>>( + "Camellia_CBC_192", _192bit, + ); + check::, Camellia_CBC_256<'_, Decrypting, PKCS7>>( + "Camellia_CBC_256", _256bit, + ); +} + +#[test] +fn cfb_cfb8_ctr() { + use SecurityStrength::*; + check::, Camellia_CFB_128<'_, Decrypting>>( + "Camellia_CFB_128", _128bit, + ); + check::, Camellia_CFB_192<'_, Decrypting>>( + "Camellia_CFB_192", _192bit, + ); + check::, Camellia_CFB_256<'_, Decrypting>>( + "Camellia_CFB_256", _256bit, + ); + check::, Camellia_CFB8_128<'_, Decrypting>>( + "Camellia_CFB8_128", _128bit, + ); + check::, Camellia_CFB8_192<'_, Decrypting>>( + "Camellia_CFB8_192", _192bit, + ); + check::, Camellia_CFB8_256<'_, Decrypting>>( + "Camellia_CFB8_256", _256bit, + ); + check::, Camellia_CTR_128<'_, Decrypting>>( + "Camellia_CTR_128", _128bit, + ); + check::, Camellia_CTR_192<'_, Decrypting>>( + "Camellia_CTR_192", _192bit, + ); + check::, Camellia_CTR_256<'_, Decrypting>>( + "Camellia_CTR_256", _256bit, + ); +} + +/// One worker serves both halves of a key wrap, so each alias is checked against itself. +#[test] +fn kw() { + use SecurityStrength::*; + check::, Camellia_KW_128<'_>>("Camellia_KW_128", _128bit); + check::, Camellia_KW_192<'_>>("Camellia_KW_192", _192bit); + check::, Camellia_KW_256<'_>>("Camellia_KW_256", _256bit); +} + +#[test] +fn the_engines_keep_their_own_names() { + assert_eq!(Camellia128Internal::ALG_NAME, "Camellia-128"); + assert_eq!(Camellia192Internal::ALG_NAME, "Camellia-192"); + assert_eq!(Camellia256Internal::ALG_NAME, "Camellia-256"); + assert_eq!(Camellia128Internal::MAX_SECURITY_STRENGTH, SecurityStrength::_128bit); + assert_eq!(Camellia192Internal::MAX_SECURITY_STRENGTH, SecurityStrength::_192bit); + assert_eq!(Camellia256Internal::MAX_SECURITY_STRENGTH, SecurityStrength::_256bit); +} + +/// The aliases must resolve to exactly the types they claim to, at both directions, and be what +/// the keys hand out. A type alias that quietly resolved to something else would still compile +/// everywhere it is used, so this pins the projection by asserting the layouts coincide with the +/// fully spelled-out types. +#[test] +fn the_aliases_name_the_expected_types() { + assert_eq!( + size_of::>(), + size_of::< + PaddedBlockCipherEncryptor< + Cbc<'_, Camellia128Internal, Encrypting, BLOCK_LEN>, + PKCS7, + BLOCK_LEN, + BLOCK_LEN, + >, + >() + ); + assert_eq!( + size_of::>(), + size_of::< + PaddedBlockCipherDecryptor< + Cbc<'_, Camellia192Internal, Decrypting, BLOCK_LEN>, + PKCS7, + BLOCK_LEN, + BLOCK_LEN, + >, + >() + ); + assert_eq!( + size_of::>(), + size_of::< + PaddedBlockCipherEncryptor< + Cbc<'_, Camellia256Internal, Encrypting, BLOCK_LEN>, + NoPadding, + BLOCK_LEN, + BLOCK_LEN, + >, + >() + ); + // The two directions are genuinely different types, so the encryptor and the decryptor do not + // have to agree in size -- and here they do not, which is itself evidence the projection + // selected two different adapters rather than one. + assert_ne!( + size_of::>(), + size_of::>() + ); + + assert_eq!( + size_of::>(), + size_of::>() + ); + assert_eq!( + size_of::>(), + size_of::>() + ); + assert_eq!( + size_of::>(), + size_of::>() + ); + assert_eq!( + size_of::>(), + size_of::>() + ); + assert_eq!( + size_of::>(), + size_of::>() + ); + assert_eq!( + size_of::>(), + size_of::>() + ); + assert_eq!( + size_of::>(), + size_of::>() + ); + assert_eq!( + size_of::>(), + size_of::>() + ); + assert_eq!( + size_of::>(), + size_of::>() + ); + + // ...and the key hands out exactly those types. + let bytes: [u8; 16] = core::array::from_fn(|i| (i as u8).wrapping_mul(7).wrapping_add(1)); + let material = + KeyMaterial::<16>::from_bytes_as_type(&bytes, KeyType::SymmetricCipherKey).unwrap(); + let mut rng = HashDRBG_SHA512::new_from_os(); + let key = Camellia128Key::>::from_key_material(&material).unwrap(); + let (enc, iv) = key.create_encryptor(&mut rng).unwrap(); + let _: Camellia_CBC_128<'_, Encrypting, PKCS7> = enc; + let _: Camellia_CBC_128<'_, Decrypting, PKCS7> = key.create_decryptor(&iv); + let key = Camellia128Key::::from_key_material(&material).unwrap(); + let _: Camellia_CFB_128<'_, Encrypting> = key.create_encryptor(&mut rng).unwrap().0; + let key = Camellia128Key::::from_key_material(&material).unwrap(); + let _: Camellia_CFB8_128<'_, Encrypting> = key.create_encryptor(&mut rng).unwrap().0; + let key = Camellia128Key::::from_key_material(&material).unwrap(); + let (enc, nonce) = key.create_encryptor(&mut rng).unwrap(); + let _: Camellia_CTR_128<'_, Encrypting> = enc; + let _: Camellia_CTR_128<'_, Decrypting> = key.create_decryptor(&nonce); +} + +/// The const parameters are Camellia's, CTR's nonce leaves the four-byte counter the mode caps +/// at, and four lanes of eight-byte F-function inputs fill the 32 byte positions of the `u32` +/// planes. +#[test] +fn the_const_parameters_are_camellias() { + assert_eq!(BLOCK_LEN, 16); + assert_eq!(CTR_NONCE_LEN, 12, "a 12-byte nonce leaves the 4-byte counter CTR caps at"); + assert_eq!(LANES * 8, 32, "four lanes of one F-function input each fill the circuit"); +} + +/// The engines are exactly their subkeys, the sizes the crate docs quote: 26 or 34 subkeys of 64 +/// bits and nothing else, no direction flag, no round counter, no initialised marker. +#[test] +fn the_engines_are_exactly_their_subkeys() { + assert_eq!(size_of::(), 208); + assert_eq!(size_of::(), 272); + assert_eq!(size_of::(), 272); +} diff --git a/crypto/camellia/tests/bc_java_tests.rs b/crypto/camellia/tests/bc_java_tests.rs new file mode 100644 index 000000000..b60122be7 --- /dev/null +++ b/crypto/camellia/tests/bc_java_tests.rs @@ -0,0 +1,125 @@ +//! The test vectors of Bouncy Castle Java's Camellia tests, run against this port. +//! +//! `core/src/test/java/org/bouncycastle/crypto/test/CamelliaTest.java` (and the identical +//! `CamelliaLightTest.java`) is a `CipherTest` over nine `BlockCipherVectorTest`s -- key, +//! plaintext, ciphertext, checked in both directions -- whose header credits them to the NESSIE +//! test vectors () and RFC 3713. Vectors 2, +//! 3 and 6 are the three of RFC 3713 Appendix A (also in `rfc3713_tests.rs`); the others are +//! NESSIE's, and coincide with entries in NTT's file (`ntt_cryptrec_tests.rs`). They are kept as a +//! separate file so that agreement with the source implementation's own test suite is asserted in +//! its own terms. + +mod common; + +use bouncycastle_camellia::BLOCK_LEN; +use bouncycastle_camellia::hazmat::{ + Camellia128Internal, Camellia192Internal, Camellia256Internal, +}; +use bouncycastle_core::hazmat::ElectronicCodeBook; +use bouncycastle_core::key_material::{KeyMaterial, KeyMaterialTrait, KeyType}; +use common::bytes; + +/// `CamelliaTest.tests`: `(index, key, input, output)`. +const TESTS: [(usize, &str, &str, &str); 9] = [ + ( + 0, + "00000000000000000000000000000000", + "80000000000000000000000000000000", + "07923A39EB0A817D1C4D87BDB82D1F1C", + ), + ( + 1, + "80000000000000000000000000000000", + "00000000000000000000000000000000", + "6C227F749319A3AA7DA235A9BBA05A2C", + ), + ( + 2, + "0123456789abcdeffedcba9876543210", + "0123456789abcdeffedcba9876543210", + "67673138549669730857065648eabe43", + ), + // 192 bit + ( + 3, + "0123456789abcdeffedcba98765432100011223344556677", + "0123456789abcdeffedcba9876543210", + "b4993401b3e996f84ee5cee7d79b09b9", + ), + ( + 4, + "000000000000000000000000000000000000000000000000", + "00040000000000000000000000000000", + "9BCA6C88B928C1B0F57F99866583A9BC", + ), + ( + 5, + "949494949494949494949494949494949494949494949494", + "636EB22D84B006381235641BCF0308D2", + "94949494949494949494949494949494", + ), + // 256 bit + ( + 6, + "0123456789abcdeffedcba987654321000112233445566778899aabbccddeeff", + "0123456789abcdeffedcba9876543210", + "9acc237dff16d76c20ef7c919e3a7509", + ), + ( + 7, + "4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A", + "057764FE3A500EDBD988C5C3B56CBA9A", + "4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A", + ), + ( + 8, + "0303030303030303030303030303030303030303030303030303030303030303", + "7968B08ABA92193F2295121EF8D75C8A", + "03030303030303030303030303030303", + ), +]; + +/// `BlockCipherVectorTest`: `engine.init(true, param)`, `processBlock`, compare; then +/// `engine.init(false, param)`, `processBlock`, compare ("failed reversal"). +fn block_cipher_vector_test>( + id: usize, + key: &str, + input: &[u8; BLOCK_LEN], + output: &[u8; BLOCK_LEN], +) { + // The Java `KeyParameter` takes any bytes; an all-zero key would be tagged `Zeroized` by + // `from_bytes_as_type`, so the tag and strength are set explicitly, as the CLI does. + let key_bytes: [u8; KEY_LEN] = bytes(key); + let mut km = + KeyMaterial::::from_bytes_as_type(&key_bytes, KeyType::SymmetricCipherKey) + .expect("a key"); + bouncycastle_core::hazmat::do_hazardous_operations(&mut km, |k| { + k.set_key_type(KeyType::SymmetricCipherKey)?; + k.set_security_strength(bouncycastle_core::security_strength::SecurityStrength::from_bytes( + KEY_LEN, + )) + }) + .expect("retagging the key"); + let engine = P::new(&km).expect("a valid key"); + + let mut buf = *input; + engine.encrypt_block(&mut buf); + assert_eq!(&buf, output, "Camellia test {id} failed encryption"); + + engine.decrypt_block(&mut buf); + assert_eq!(&buf, input, "Camellia test {id} failed reversal"); +} + +#[test] +fn camellia_test_vectors() { + for (id, key, input, output) in TESTS { + let input: [u8; BLOCK_LEN] = bytes(input); + let output: [u8; BLOCK_LEN] = bytes(output); + match key.len() / 2 { + 16 => block_cipher_vector_test::<16, Camellia128Internal>(id, key, &input, &output), + 24 => block_cipher_vector_test::<24, Camellia192Internal>(id, key, &input, &output), + 32 => block_cipher_vector_test::<32, Camellia256Internal>(id, key, &input, &output), + n => panic!("unexpected key length {n}"), + } + } +} diff --git a/crypto/camellia/tests/cbc_wycheproof.rs b/crypto/camellia/tests/cbc_wycheproof.rs new file mode 100644 index 000000000..fb78a4bda --- /dev/null +++ b/crypto/camellia/tests/cbc_wycheproof.rs @@ -0,0 +1,222 @@ +//! Known-answer tests against Project Wycheproof's `testvectors_v1/camellia_cbc_pkcs5_test.json`, +//! through `Camellia128Key>` and friends. +//! +//! The same suite as `crypto/aes/tests/cbc_wycheproof.rs`, which says why the set is worth +//! having beside the block-aligned OpenSSL vectors: two thirds of it is `result: "invalid"` -- +//! ciphertexts whose final block does not unpad (`BadPadding`, 141 cases) and empty ciphertexts +//! (`NoPadding`, 3 cases) -- and each invalid case must fail with the error its flags predict, +//! leaving the output buffer zeroized, not merely fail. The valid cases are driven through the +//! key's `encrypt_out` with a `FixedSeedRNG` emitting the vector's IV, which is checked before +//! any ciphertext is compared. Requires the Wycheproof repository at `../wycheproof`; absent, +//! the test warns and passes. + +use bouncycastle_camellia::{Camellia128Key, Camellia192Key, Camellia256Key}; +use bouncycastle_cipher::modes::CBC; +use bouncycastle_cipher::padding::PKCS7; +use bouncycastle_core::errors::{PaddingError, SymmetricCipherError}; +use bouncycastle_core::hazmat::do_hazardous_operations; +use bouncycastle_core::key_material::{KeyMaterial, KeyMaterialTrait, KeyType}; +use bouncycastle_core::security_strength::SecurityStrength; +use bouncycastle_core::symmetric_key::{ + FromKeyMaterial, SymmetricDecryptionKey, SymmetricEncryptionKey, +}; +use bouncycastle_core::traits::{SymmetricCipherDecryptor, SymmetricCipherEncryptor}; +use bouncycastle_core_test_framework::test_data_loaders::{Value, hex_field, wycheproof_json}; +use bouncycastle_rng::FixedSeedRNG; + +const BLOCK_LEN: usize = 16; + +/// Wraps the vector's raw key bytes, promoting them if `KeyMaterial`'s entropy heuristic declined +/// to call them a cipher key. Same helper as the other vector suites in this crate. +fn cipher_key(bytes: &[u8]) -> KeyMaterial { + assert_eq!(bytes.len(), N, "key length should match the parameter set"); + let mut key = KeyMaterial::::from_bytes_as_type(bytes, KeyType::SymmetricCipherKey) + .expect("wycheproof key bytes fit the buffer"); + + if key.key_type() != KeyType::SymmetricCipherKey { + do_hazardous_operations(&mut key, |k| { + k.set_key_type(KeyType::SymmetricCipherKey)?; + k.set_security_strength(SecurityStrength::from_bytes(N)) + }) + .expect("promoting a wycheproof test key"); + } + key +} + +/// What an invalid case must fail with, from its `flags`. +/// +/// `BadPadding` is a well-formed ciphertext whose final block does not unpad, so the adapter +/// surfaces [`PKCS7::unpad`]'s single undifferentiated [`PaddingError::InvalidPadding`]. +/// `NoPadding` is an empty ciphertext: there is no final block to unpad at all, which the adapter +/// reports as [`SymmetricCipherError::DecryptionFailed`] before any padding is looked at. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum Expected { + Valid, + BadPadding, + NoFinalBlock, +} + +/// Runs one case through the `Camellia*Key>` key at one key length. +/// +/// For a valid case, `msg` must encrypt to exactly `expected_ct` under the vector's IV, and +/// `expected_ct` must decrypt back to `msg`. For an invalid case only the decrypt direction is +/// checked -- re-encrypting `msg` with correct padding has no reason to reproduce a deliberately +/// mis-padded `ct` -- and it must fail with the variant the case's flags predict, leaving the +/// output buffer zeroized: CBC writes plaintext before it reaches the padding, and the key's +/// `decrypt_out` must wipe it when the final block does not unpad. +fn run_case( + tc_id: u64, + key_bytes: &[u8], + iv: [u8; BLOCK_LEN], + msg: &[u8], + expected_ct: &[u8], + expected: Expected, +) where + K: FromKeyMaterial + + SymmetricEncryptionKey + + SymmetricDecryptionKey, +{ + let key = K::from_key_material(&cipher_key::(key_bytes)) + .unwrap_or_else(|e| panic!("tcId {tc_id}: the key should be accepted: {e:?}")); + + if expected == Expected::Valid { + let ct_len = + as SymmetricCipherEncryptor>::encrypt_out_len( + msg.len(), + ); + let mut ct = vec![0u8; ct_len]; + let (written, got_iv) = key + .encrypt_out(&mut FixedSeedRNG::new(iv), msg, &mut ct) + .unwrap_or_else(|e| panic!("tcId {tc_id}: valid case failed to encrypt: {e:?}")); + assert_eq!(got_iv, iv, "tcId {tc_id}: the seeded RNG must reproduce the vector's IV"); + ct.truncate(written); + assert_eq!(ct, expected_ct, "tcId {tc_id}: ciphertext mismatch"); + } + + // Pre-filled with a non-zero byte, so a buffer the decryptor never wrote is not mistaken for + // one it zeroized. + let pt_len = + as SymmetricCipherDecryptor>::decrypt_out_len( + expected_ct.len(), + ); + let mut plaintext = vec![0xEEu8; pt_len]; + let outcome = key.decrypt_out(&iv, expected_ct, &mut plaintext); + if outcome.is_err() { + assert!( + plaintext.iter().all(|&b| b == 0), + "tcId {tc_id}: a failed decrypt must leave the output buffer zeroized" + ); + } + match (expected, outcome) { + (Expected::Valid, Ok(n)) => { + plaintext.truncate(n); + assert_eq!(plaintext, msg, "tcId {tc_id}: decrypted plaintext mismatch"); + } + (Expected::BadPadding, Err(SymmetricCipherError::PaddingError(e))) => { + assert_eq!( + e, + PaddingError::InvalidPadding, + "tcId {tc_id}: bad padding must be refused" + ); + } + (Expected::NoFinalBlock, Err(SymmetricCipherError::DecryptionFailed)) => {} + (expected, outcome) => { + panic!("tcId {tc_id}: expected {expected:?}, got {outcome:?}") + } + } +} + +/// Dispatches on the key length to the matching `Camellia*Key>`. +fn dispatch( + tc_id: u64, + key_bytes: &[u8], + iv: [u8; BLOCK_LEN], + msg: &[u8], + expected_ct: &[u8], + expected: Expected, +) { + match key_bytes.len() { + 16 => run_case::>, 16>( + tc_id, key_bytes, iv, msg, expected_ct, expected, + ), + 24 => run_case::>, 24>( + tc_id, key_bytes, iv, msg, expected_ct, expected, + ), + 32 => run_case::>, 32>( + tc_id, key_bytes, iv, msg, expected_ct, expected, + ), + other => panic!("tcId {tc_id}: Camellia keys are 16, 24 or 32 bytes, got {other}"), + } +} + +#[test] +fn wycheproof_camellia_cbc_pkcs7_known_answer_tests() { + let Some(doc) = wycheproof_json("camellia_cbc_pkcs5_test.json") else { + return; + }; + + assert_eq!( + doc.get("algorithm").and_then(Value::as_str), + Some("CAMELLIA-CBC-PKCS5"), + "this is the CAMELLIA-CBC-PKCS5 vector file" + ); + + let groups = doc.get("testGroups").and_then(Value::as_array).expect("testGroups"); + + let mut valid_count = 0usize; + let mut bad_padding_count = 0usize; + let mut no_final_block_count = 0usize; + + for group in groups { + let iv_size_bits = group.get("ivSize").and_then(Value::as_u64).expect("ivSize"); + let key_size_bits = group.get("keySize").and_then(Value::as_u64).expect("keySize"); + assert_eq!(iv_size_bits as usize, 8 * BLOCK_LEN, "CBC's IV is one block"); + assert_eq!(key_size_bits % 8, 0, "keySize must be a whole number of octets"); + + let tests = group.get("tests").and_then(Value::as_array).expect("tests"); + + for test in tests { + let tc_id = test.get("tcId").and_then(Value::as_u64).expect("tcId"); + let key_bytes = hex_field(test, "key", tc_id); + let iv: [u8; BLOCK_LEN] = hex_field(test, "iv", tc_id) + .try_into() + .unwrap_or_else(|_| panic!("tcId {tc_id}: the IV must be one block")); + let msg = hex_field(test, "msg", tc_id); + let ct = hex_field(test, "ct", tc_id); + let result = test.get("result").and_then(Value::as_str).expect("result"); + let flags: Vec<&str> = test + .get("flags") + .and_then(Value::as_array) + .expect("flags") + .iter() + .map(|f| f.as_str().expect("flag")) + .collect(); + + // The flags say *how* an invalid case is invalid, and so which error it must produce. + let expected = match result { + "valid" => Expected::Valid, + "invalid" if flags.contains(&"BadPadding") => Expected::BadPadding, + "invalid" if flags.contains(&"NoPadding") => Expected::NoFinalBlock, + other => panic!("tcId {tc_id}: unexpected result/flags {other} {flags:?}"), + }; + + dispatch(tc_id, &key_bytes, iv, &msg, &ct, expected); + + match expected { + Expected::Valid => valid_count += 1, + Expected::BadPadding => bad_padding_count += 1, + Expected::NoFinalBlock => no_final_block_count += 1, + } + } + } + + println!( + "Wycheproof CAMELLIA-CBC-PKCS5: {valid_count} valid, {bad_padding_count} bad-padding and \ + {no_final_block_count} empty-ciphertext cases run" + ); + + // Guards against a silently-vacuous run. + assert!(valid_count > 0, "expected valid cases"); + assert!(bad_padding_count > 0, "expected bad-padding cases, which are the point of this set"); + assert!(no_final_block_count > 0, "expected the empty-ciphertext cases"); +} diff --git a/crypto/camellia/tests/ccm_wycheproof.rs b/crypto/camellia/tests/ccm_wycheproof.rs new file mode 100644 index 000000000..286b67213 --- /dev/null +++ b/crypto/camellia/tests/ccm_wycheproof.rs @@ -0,0 +1,277 @@ +//! Known-answer tests against Project Wycheproof's `testvectors_v1/camellia_ccm_test.json`. +//! +//! Requires the Wycheproof repository (https://github.com/C2SP/wycheproof) to be cloned alongside +//! this repository, i.e. at `../wycheproof` relative to the root of this git project. If it is +//! absent the test prints a warning and passes, matching the convention used by the other vector +//! suites in this crate. +//! +//! # What this set covers +//! +//! There is no NIST vector file for Camellia-CCM, so this is the crate's only CCM known answer, +//! and it is deliberately adversarial in the ways a conformance set is not: malformed and truncated tags, every +//! nonce length from 8 to 2144 *bits* (most of which A.1 does not permit at all), a tag size of +//! 16 bits that SP 800-38C Appendix B.2 calls insecure, and pseudorandom sizes meant to catch an +//! implementation that only handles the common cases. See +//! `camellia_ccm_test.json`'s own `"notes"` object for exactly what each +//! `flags` entry is checking. +//! +//! # Ciphertext and tag are separate fields +//! +//! Wycheproof's AEAD schema carries `ct` and `tag` as distinct fields (the `aead_test_schema_v1` +//! schema), so these cases go through the key's detached in-place one-shots +//! (`Camellia*Key>`), not the inline pair. +//! +//! # Most of the parameter space cannot be dispatched to at all, by design +//! +//! The mode's `NONCE_LEN` and `TAG_LEN` are const generics restricted to A.1's sets -- +//! `NONCE_LEN` in `7..=13` bytes, `TAG_LEN` in `{4, 6, 8, 10, 12, 14, 16}` bytes -- so there is no +//! instantiation to dispatch a group whose `ivSize`/`tagSize` falls outside them to at all; unlike +//! a runtime check, this is not something a case can "fail", because it is a compile-time property +//! of the type, not a value the library ever sees. Those groups (most of the file: the point of +//! `InvalidNonceSize`/`InvalidTagSize` and most of the `Pseudorandom` groups is to probe exactly +//! this boundary) are counted as not supported rather than silently dropped, and the counts are +//! asserted at the end so a change in the vector file's shape is visible. + +use bouncycastle_camellia::{Camellia128Key, Camellia192Key, Camellia256Key}; +use bouncycastle_cipher::modes::CCM; +use bouncycastle_core::errors::SymmetricCipherError; +use bouncycastle_core::hazmat::do_hazardous_operations; +use bouncycastle_core::key_material::{KeyMaterial, KeyMaterialTrait, KeyType}; +use bouncycastle_core::security_strength::SecurityStrength; +use bouncycastle_core::symmetric_key::{ + AeadDeclaredDecryptionKey, AeadDeclaredEncryptionKey, FromKeyMaterial, +}; +use bouncycastle_core_test_framework::test_data_loaders::{Value, hex_field, wycheproof_json}; + +/// Wraps the vector's raw key bytes, promoting them if `KeyMaterial`'s entropy heuristic declined +/// to call them a cipher key. Same helper as the CMAC suite in this crate. +fn cipher_key(bytes: &[u8]) -> KeyMaterial { + assert_eq!(bytes.len(), N, "key length should match the parameter set"); + let mut key = KeyMaterial::::from_bytes_as_type(bytes, KeyType::SymmetricCipherKey) + .expect("wycheproof key bytes fit the buffer"); + + if key.key_type() != KeyType::SymmetricCipherKey { + do_hazardous_operations(&mut key, |k| { + k.set_key_type(KeyType::SymmetricCipherKey)?; + k.set_security_strength(SecurityStrength::from_bytes(N)) + }) + .expect("promoting a wycheproof test key"); + } + key +} + +/// Runs one case at a fully-instantiated `(KEY_LEN, NONCE_LEN, TAG_LEN)` key type `K`, through +/// the key's detached in-place one-shots. +/// +/// For a `result: "valid"` case, `msg` must encrypt to exactly `expected_ct`/`expected_tag`, and +/// `expected_ct`/`expected_tag` must decrypt back to `msg`. For `result: "invalid"`, only the +/// decrypt direction is checked -- re-encrypting `msg` has no reason to reproduce a deliberately +/// corrupted `ct`/`tag` -- and it must fail the tag check rather than return a payload, leaving +/// the buffer zeroized as the mode's in-place decrypt documents. +#[allow(clippy::too_many_arguments)] +fn run_case( + tc_id: u64, + key_bytes: &[u8], + nonce_bytes: &[u8], + aad: &[u8], + msg: &[u8], + expected_ct: &[u8], + expected_tag: &[u8], + valid: bool, +) where + K: FromKeyMaterial + + AeadDeclaredEncryptionKey + + AeadDeclaredDecryptionKey, +{ + let key = K::from_key_material(&cipher_key::(key_bytes)).expect("a wycheproof key"); + let nonce: [u8; NONCE_LEN] = + nonce_bytes.try_into().unwrap_or_else(|_| panic!("tcId {tc_id}: bad nonce length")); + let tag: [u8; TAG_LEN] = + expected_tag.try_into().unwrap_or_else(|_| panic!("tcId {tc_id}: bad tag length")); + + if valid { + let mut ct = msg.to_vec(); + let got_tag = key + .encrypt_detached_in_place_nonce(&nonce, aad, &mut ct) + .unwrap_or_else(|e| panic!("tcId {tc_id}: valid case failed to encrypt: {e:?}")); + assert_eq!(ct, expected_ct, "tcId {tc_id}: ciphertext mismatch"); + assert_eq!(got_tag, tag, "tcId {tc_id}: tag mismatch"); + } + + let mut plaintext = expected_ct.to_vec(); + match key.decrypt_detached_in_place(&nonce, aad, &mut plaintext, &tag) { + Ok(()) => { + assert!(valid, "tcId {tc_id}: an invalid vector decrypted and verified anyway"); + assert_eq!(plaintext, msg, "tcId {tc_id}: decrypted plaintext mismatch"); + } + Err(SymmetricCipherError::AEADTagCheckFailed) => { + assert!(!valid, "tcId {tc_id}: a valid vector failed its tag check"); + assert!( + plaintext.iter().all(|&b| b == 0), + "tcId {tc_id}: a failed tag check must leave the output buffer zeroized" + ); + } + Err(e) => panic!("tcId {tc_id}: unexpected CCM error: {e:?}"), + } +} + +/// Dispatches to one of the 3 (key) x 7 (nonce) x 7 (tag) valid instantiations, or reports that +/// the case's parameter sizes have no instantiation to dispatch to at all. +#[allow(clippy::too_many_arguments)] +fn dispatch( + tc_id: u64, + key_len_bytes: u64, + nonce_len_bytes: u64, + tag_len_bytes: u64, + key_bytes: &[u8], + nonce_bytes: &[u8], + aad: &[u8], + msg: &[u8], + expected_ct: &[u8], + expected_tag: &[u8], + valid: bool, +) -> bool { + macro_rules! with_key_len { + ($n:literal, $t:literal) => { + match key_len_bytes { + 16 => { + run_case::<16, $n, $t, Camellia128Key>>( + tc_id, key_bytes, nonce_bytes, aad, msg, expected_ct, expected_tag, valid, + ); + true + } + 24 => { + run_case::<24, $n, $t, Camellia192Key>>( + tc_id, key_bytes, nonce_bytes, aad, msg, expected_ct, expected_tag, valid, + ); + true + } + 32 => { + run_case::<32, $n, $t, Camellia256Key>>( + tc_id, key_bytes, nonce_bytes, aad, msg, expected_ct, expected_tag, valid, + ); + true + } + _ => false, + } + }; + } + macro_rules! with_tag_len { + ($n:literal) => { + match tag_len_bytes { + 4 => with_key_len!($n, 4), + 6 => with_key_len!($n, 6), + 8 => with_key_len!($n, 8), + 10 => with_key_len!($n, 10), + 12 => with_key_len!($n, 12), + 14 => with_key_len!($n, 14), + 16 => with_key_len!($n, 16), + _ => false, + } + }; + } + match nonce_len_bytes { + 7 => with_tag_len!(7), + 8 => with_tag_len!(8), + 9 => with_tag_len!(9), + 10 => with_tag_len!(10), + 11 => with_tag_len!(11), + 12 => with_tag_len!(12), + 13 => with_tag_len!(13), + _ => false, + } +} + +#[test] +fn wycheproof_camellia_ccm_known_answer_tests() { + let Some(doc) = wycheproof_json("camellia_ccm_test.json") else { return }; + + let groups = doc.get("testGroups").and_then(Value::as_array).expect("testGroups"); + + let mut run = 0usize; + let mut valid_count = 0usize; + let mut invalid_count = 0usize; + let mut unsupported_groups = 0usize; + let mut unsupported_cases = 0usize; + + for group in groups { + let iv_size_bits = group.get("ivSize").and_then(Value::as_u64).expect("ivSize"); + let key_size_bits = group.get("keySize").and_then(Value::as_u64).expect("keySize"); + let tag_size_bits = group.get("tagSize").and_then(Value::as_u64).expect("tagSize"); + assert_eq!(iv_size_bits % 8, 0, "ivSize must be a whole number of octets"); + assert_eq!(key_size_bits % 8, 0, "keySize must be a whole number of octets"); + assert_eq!(tag_size_bits % 8, 0, "tagSize must be a whole number of octets"); + + // A group is only fully within A.1's dispatchable sets if its *declared* nonce/tag sizes + // are; a `Pseudorandom` group whose individual tests vary can still contribute some + // dispatched and some unsupported cases, so this is a per-group tally for the printout, not + // something the per-case counts below depend on. + if !(7..=13).contains(&(iv_size_bits / 8)) + || ![4u64, 6, 8, 10, 12, 14, 16].contains(&(tag_size_bits / 8)) + { + unsupported_groups += 1; + } + + let tests = group.get("tests").and_then(Value::as_array).expect("tests"); + + // Each case is dispatched on its own actual field lengths, not the group's declared + // sizes: a `Pseudorandom` group's whole point is varying them per test, and `dispatch` + // itself is the authority on what it can run (only A.1's own sets). + for test in tests { + let tc_id = test.get("tcId").and_then(Value::as_u64).expect("tcId"); + let key_bytes = hex_field(test, "key", tc_id); + let nonce_bytes = hex_field(test, "iv", tc_id); + let aad = hex_field(test, "aad", tc_id); + let msg = hex_field(test, "msg", tc_id); + let ct = hex_field(test, "ct", tc_id); + let tag = hex_field(test, "tag", tc_id); + let result = test.get("result").and_then(Value::as_str).expect("result"); + let valid = match result { + "valid" => true, + "invalid" => false, + other => panic!("tcId {tc_id}: unexpected result {other}"), + }; + + let ran = dispatch( + tc_id, + key_bytes.len() as u64, + nonce_bytes.len() as u64, + tag.len() as u64, + &key_bytes, + &nonce_bytes, + &aad, + &msg, + &ct, + &tag, + valid, + ); + + if ran { + run += 1; + if valid { + valid_count += 1; + } else { + invalid_count += 1; + } + } else { + unsupported_cases += 1; + } + } + } + + println!( + "Wycheproof Camellia-CCM: {run} cases run ({valid_count} valid, {invalid_count} invalid), \ + {unsupported_cases} cases in {unsupported_groups} groups not supported \ + (no A.1 instantiation)" + ); + + // Guards against a silently-vacuous run: at least the common 96-bit-nonce/128-bit-tag groups + // must have been dispatched to and must have included both valid and invalid cases. + assert!(run > 0, "expected at least some cases to be within A.1's dispatchable sets"); + assert!(valid_count > 0, "expected at least some valid cases to be run"); + assert!(invalid_count > 0, "expected at least some invalid (tag-failure) cases to be run"); + assert!( + unsupported_groups > 0, + "expected most of this adversarial set to be outside A.1's sets" + ); +} diff --git a/crypto/camellia/tests/cmac_wycheproof.rs b/crypto/camellia/tests/cmac_wycheproof.rs new file mode 100644 index 000000000..1b583fc07 --- /dev/null +++ b/crypto/camellia/tests/cmac_wycheproof.rs @@ -0,0 +1,82 @@ +//! Known-answer tests against Wycheproof's `camellia_cmac_test.json`. +//! +//! Requires the Wycheproof repository (https://github.com/C2SP/wycheproof) to be cloned alongside +//! this repository, i.e. at `../wycheproof` relative to the root of this git project. If it is +//! missing, the test prints a warning and passes without checking anything. +//! +//! Every tag is checked through the worker an `Camellia*Key` hands out and through the key's own +//! one-shots, so the two routes are held to the same answers. + +use bouncycastle_camellia::{Camellia128Key, Camellia192Key, Camellia256Key}; +use bouncycastle_cipher::modes::{CMAC, CMAC_MIN_TAG_LEN}; +use bouncycastle_core::symmetric_key::{FromKeyMaterial, MacGenerationKey, MacVerificationKey}; +use bouncycastle_core::traits::MAC; +use bouncycastle_core_test_framework::test_data_loaders::{hex_field, wycheproof_json}; + +#[path = "common/cmac_helpers.rs"] +mod cmac_helpers; +use cmac_helpers::mac_key; + +/// One case at one key length, through both routes. +fn run_case(tc_id: u64, key: &[u8], msg: &[u8], tag: &[u8], valid: bool) +where + K: FromKeyMaterial + MacGenerationKey + MacVerificationKey, + for<'k> ::Generator<'k>: MAC, +{ + let material = mac_key::(key); + let key = K::from_key_material(&material).unwrap_or_else(|e| panic!("tcId {tc_id}: {e:?}")); + let full = key.create_generator().mac(msg); + assert_eq!(full == tag, valid, "tcId {tc_id}"); + assert_eq!(key.create_generator().verify(msg, tag), valid, "tcId {tc_id}"); + + assert_eq!(key.verify(msg, tag), valid, "tcId {tc_id}: via the key's one-shot"); + if valid { + assert_eq!(key.mac(msg), tag, "tcId {tc_id}: via the key's one-shot"); + let mut out = [0u8; CMAC_MIN_TAG_LEN]; + key.mac_out(msg, &mut out).unwrap(); + assert_eq!(out[..], tag[..CMAC_MIN_TAG_LEN], "tcId {tc_id}: truncated tag"); + } +} + +#[test] +fn wycheproof_camellia_cmac() { + let Some(set) = wycheproof_json("camellia_cmac_test.json") else { return }; + + let (mut valid, mut invalid, mut bad_key) = (0usize, 0usize, 0usize); + for group in set["testGroups"].as_array().unwrap() { + assert_eq!(group["tagSize"].as_u64(), Some(128)); + for test in group["tests"].as_array().unwrap() { + let tc_id = test["tcId"].as_u64().unwrap(); + let key = hex_field(test, "key", tc_id); + let msg = hex_field(test, "msg", tc_id); + let tag = hex_field(test, "tag", tc_id); + let expect_valid = match test["result"].as_str().unwrap() { + "valid" => true, + "invalid" => false, + other => panic!("tcId {tc_id}: unexpected result {other}"), + }; + + match key.len() { + 16 => run_case::<16, Camellia128Key>(tc_id, &key, &msg, &tag, expect_valid), + 24 => run_case::<24, Camellia192Key>(tc_id, &key, &msg, &tag, expect_valid), + 32 => run_case::<32, Camellia256Key>(tc_id, &key, &msg, &tag, expect_valid), + _ => { + // "InvalidKeySize": no `Camellia*Key` takes it, since the key length is in + // the `KeyMaterial<16 | 24 | 32>` type; nothing to run at runtime. + assert!(!expect_valid, "tcId {tc_id}"); + bad_key += 1; + continue; + } + } + if expect_valid { valid += 1 } else { invalid += 1 } + } + } + println!( + "Wycheproof Camellia-CMAC: {valid} valid, {invalid} invalid tags, {bad_key} invalid key sizes" + ); + assert_eq!( + valid + invalid + bad_key, + 311, + "expected all 311 Wycheproof Camellia-CMAC cases to run" + ); +} diff --git a/crypto/camellia/tests/common/cmac_helpers.rs b/crypto/camellia/tests/common/cmac_helpers.rs new file mode 100644 index 000000000..78ce49d40 --- /dev/null +++ b/crypto/camellia/tests/common/cmac_helpers.rs @@ -0,0 +1,23 @@ +//! Shared plumbing for the CMAC vector suites: building `KeyType::MACKey` material from raw key +//! bytes, including the all-zero keys the sets include, which `KeyMaterial` tags `Zeroized` and +//! will not promote outside a `do_hazardous_operations` closure. + +#![allow(dead_code)] + +use bouncycastle_core::hazmat::do_hazardous_operations; +use bouncycastle_core::key_material::{KeyMaterial, KeyMaterialTrait, KeyType}; +use bouncycastle_core::security_strength::SecurityStrength; + +pub fn mac_key(bytes: &[u8]) -> KeyMaterial { + assert_eq!(bytes.len(), N, "key length should match the parameter set"); + let mut key = KeyMaterial::::from_bytes_as_type(bytes, KeyType::MACKey) + .expect("key bytes fit the buffer"); + if key.key_type() != KeyType::MACKey { + do_hazardous_operations(&mut key, |k| { + k.set_key_type(KeyType::MACKey)?; + k.set_security_strength(SecurityStrength::from_bytes(N)) + }) + .expect("promoting an all-zero test key"); + } + key +} diff --git a/crypto/camellia/tests/common/mod.rs b/crypto/camellia/tests/common/mod.rs new file mode 100644 index 000000000..6b5da4552 --- /dev/null +++ b/crypto/camellia/tests/common/mod.rs @@ -0,0 +1,441 @@ +//! A table-driven reference Camellia, for cross-checking the constant-time engine. +//! +//! This is BC Java's `CamelliaLightEngine` transcribed as directly as Rust allows: the 256-byte +//! `SBOX1` table of RFC 3713 Sec 2.4.1 with `sbox2`/`sbox3`/`sbox4` derived from it as the Java +//! does, `SIGMA` as 32-bit halves, the 32-bit-word `camelliaF2` (two rounds per call) and +//! `camelliaFLs`, the `roldq` / `decroldq` / `roldqo32` / `decroldqo32` subkey layout, and the +//! direction-dependent `setKey`. It exists only in the tests, where its cache-timing behaviour does +//! not matter, and it is deliberately independent of the crate's own code: it shares no modules +//! with it and is organised around 32-bit quarters where the engine uses 64-bit halves, so +//! agreement between the two is meaningful. +//! +//! It is itself checked against RFC 3713 Appendix A in `reference_sanity`, so a bug here cannot +//! silently validate a bug in the engine. + +#![allow(dead_code)] + +/// Sec 2.4.1's `SBOX1`; identical to BC Java's `SBOX1`. +#[rustfmt::skip] +pub const SBOX1: [u8; 256] = [ + 112, 130, 44, 236, 179, 39, 192, 229, 228, 133, 87, 53, 234, 12, 174, 65, + 35, 239, 107, 147, 69, 25, 165, 33, 237, 14, 79, 78, 29, 101, 146, 189, + 134, 184, 175, 143, 124, 235, 31, 206, 62, 48, 220, 95, 94, 197, 11, 26, + 166, 225, 57, 202, 213, 71, 93, 61, 217, 1, 90, 214, 81, 86, 108, 77, + 139, 13, 154, 102, 251, 204, 176, 45, 116, 18, 43, 32, 240, 177, 132, 153, + 223, 76, 203, 194, 52, 126, 118, 5, 109, 183, 169, 49, 209, 23, 4, 215, + 20, 88, 58, 97, 222, 27, 17, 28, 50, 15, 156, 22, 83, 24, 242, 34, + 254, 68, 207, 178, 195, 181, 122, 145, 36, 8, 232, 168, 96, 252, 105, 80, + 170, 208, 160, 125, 161, 137, 98, 151, 84, 91, 30, 149, 224, 255, 100, 210, + 16, 196, 0, 72, 163, 247, 117, 219, 138, 3, 230, 218, 9, 63, 221, 148, + 135, 92, 131, 2, 205, 74, 144, 51, 115, 103, 246, 243, 157, 127, 191, 226, + 82, 155, 216, 38, 200, 55, 198, 59, 129, 150, 111, 75, 19, 190, 99, 46, + 233, 121, 167, 140, 159, 110, 188, 142, 41, 245, 249, 182, 47, 253, 180, 89, + 120, 152, 6, 106, 231, 70, 113, 186, 212, 37, 171, 66, 136, 162, 141, 250, + 114, 7, 185, 85, 248, 238, 172, 10, 54, 73, 42, 104, 60, 56, 241, 164, + 64, 40, 211, 123, 187, 201, 67, 193, 21, 227, 173, 244, 119, 199, 128, 158, +]; + +/// `SIGMA`, as 32-bit halves, as in the Java. +const SIGMA: [u32; 12] = [ + 0xa09e667f, 0x3bcc908b, 0xb67ae858, 0x4caa73b2, 0xc6ef372f, 0xe94f82be, 0x54ff53a5, 0xf1d36f1c, + 0x10e527fa, 0xde682d1d, 0xb05688c2, 0xb3e6c1fd, +]; + +fn right_rotate(x: u32, s: u32) -> u32 { + x.rotate_right(s) +} +fn left_rotate(x: u32, s: u32) -> u32 { + x.rotate_left(s) +} + +/// `roldq(rot, ki, ioff, ko, ooff)`: rotates the 128-bit `ki[ioff..ioff+4]` left by `rot` (< 32), +/// storing the result at `ko[ooff..ooff+4]` and back into `ki`. +fn roldq(rot: u32, ki: &mut [u32], ioff: usize, ko: &mut [u32], ooff: usize) { + ko[ooff] = (ki[ioff] << rot) | (ki[1 + ioff] >> (32 - rot)); + ko[1 + ooff] = (ki[1 + ioff] << rot) | (ki[2 + ioff] >> (32 - rot)); + ko[2 + ooff] = (ki[2 + ioff] << rot) | (ki[3 + ioff] >> (32 - rot)); + ko[3 + ooff] = (ki[3 + ioff] << rot) | (ki[ioff] >> (32 - rot)); + ki[ioff] = ko[ooff]; + ki[1 + ioff] = ko[1 + ooff]; + ki[2 + ioff] = ko[2 + ooff]; + ki[3 + ioff] = ko[3 + ooff]; +} + +/// `decroldq`: as `roldq`, but the two 64-bit halves land swapped in `ko` (decryption order). +fn decroldq(rot: u32, ki: &mut [u32], ioff: usize, ko: &mut [u32], ooff: usize) { + ko[2 + ooff] = (ki[ioff] << rot) | (ki[1 + ioff] >> (32 - rot)); + ko[3 + ooff] = (ki[1 + ioff] << rot) | (ki[2 + ioff] >> (32 - rot)); + ko[ooff] = (ki[2 + ioff] << rot) | (ki[3 + ioff] >> (32 - rot)); + ko[1 + ooff] = (ki[3 + ioff] << rot) | (ki[ioff] >> (32 - rot)); + ki[ioff] = ko[2 + ooff]; + ki[1 + ioff] = ko[3 + ooff]; + ki[2 + ioff] = ko[ooff]; + ki[3 + ioff] = ko[1 + ooff]; +} + +/// `roldqo32`: rotation by `rot` in 33..63 -- a word shift plus a bit rotation. +fn roldqo32(rot: u32, ki: &mut [u32], ioff: usize, ko: &mut [u32], ooff: usize) { + ko[ooff] = (ki[1 + ioff] << (rot - 32)) | (ki[2 + ioff] >> (64 - rot)); + ko[1 + ooff] = (ki[2 + ioff] << (rot - 32)) | (ki[3 + ioff] >> (64 - rot)); + ko[2 + ooff] = (ki[3 + ioff] << (rot - 32)) | (ki[ioff] >> (64 - rot)); + ko[3 + ooff] = (ki[ioff] << (rot - 32)) | (ki[1 + ioff] >> (64 - rot)); + ki[ioff] = ko[ooff]; + ki[1 + ioff] = ko[1 + ooff]; + ki[2 + ioff] = ko[2 + ooff]; + ki[3 + ioff] = ko[3 + ooff]; +} + +/// `decroldqo32`: as `roldqo32`, halves swapped. +fn decroldqo32(rot: u32, ki: &mut [u32], ioff: usize, ko: &mut [u32], ooff: usize) { + ko[2 + ooff] = (ki[1 + ioff] << (rot - 32)) | (ki[2 + ioff] >> (64 - rot)); + ko[3 + ooff] = (ki[2 + ioff] << (rot - 32)) | (ki[3 + ioff] >> (64 - rot)); + ko[ooff] = (ki[3 + ioff] << (rot - 32)) | (ki[ioff] >> (64 - rot)); + ko[1 + ooff] = (ki[ioff] << (rot - 32)) | (ki[1 + ioff] >> (64 - rot)); + ki[ioff] = ko[2 + ooff]; + ki[1 + ioff] = ko[3 + ooff]; + ki[2 + ioff] = ko[ooff]; + ki[3 + ioff] = ko[1 + ooff]; +} + +fn bytes2int(src: &[u8], offset: usize) -> u32 { + let mut word = 0u32; + for i in 0..4 { + word = (word << 8) + src[i + offset] as u32; + } + word +} + +fn int2bytes(mut word: u32, dst: &mut [u8], offset: usize) { + for i in 0..4 { + dst[(3 - i) + offset] = word as u8; + word >>= 8; + } +} + +fn sbox1(x: u32) -> u32 { + SBOX1[x as usize] as u32 +} +/// `sbox2(x)`: `Bytes.rotateLeft(SBOX1[x], 1) & MASK8`. +fn sbox2(x: u32) -> u32 { + SBOX1[x as usize].rotate_left(1) as u32 +} +/// `sbox3(x)`: `Bytes.rotateLeft(SBOX1[x], 7) & MASK8`. +fn sbox3(x: u32) -> u32 { + SBOX1[x as usize].rotate_left(7) as u32 +} +/// `sbox4(x)`: `SBOX1[rotateLeft((byte)x, 1) & MASK8]`. +fn sbox4(x: u32) -> u32 { + SBOX1[(x as u8).rotate_left(1) as usize] as u32 +} + +/// `camelliaF2(s, skey, keyoff)`: two Feistel rounds on the 32-bit-quarter state. +fn camellia_f2(s: &mut [u32; 4], skey: &[u32], keyoff: usize) { + let mut t1 = s[0] ^ skey[keyoff]; + let mut u = sbox4(t1 & 0xff); + u |= sbox3((t1 >> 8) & 0xff) << 8; + u |= sbox2((t1 >> 16) & 0xff) << 16; + u |= sbox1((t1 >> 24) & 0xff) << 24; + + let mut t2 = s[1] ^ skey[1 + keyoff]; + let mut v = sbox1(t2 & 0xff); + v |= sbox4((t2 >> 8) & 0xff) << 8; + v |= sbox3((t2 >> 16) & 0xff) << 16; + v |= sbox2((t2 >> 24) & 0xff) << 24; + + v = left_rotate(v, 8); + u ^= v; + v = left_rotate(v, 8) ^ u; + u = right_rotate(u, 8) ^ v; + s[2] ^= left_rotate(v, 16) ^ u; + s[3] ^= left_rotate(u, 8); + + t1 = s[2] ^ skey[2 + keyoff]; + u = sbox4(t1 & 0xff); + u |= sbox3((t1 >> 8) & 0xff) << 8; + u |= sbox2((t1 >> 16) & 0xff) << 16; + u |= sbox1((t1 >> 24) & 0xff) << 24; + + t2 = s[3] ^ skey[3 + keyoff]; + v = sbox1(t2 & 0xff); + v |= sbox4((t2 >> 8) & 0xff) << 8; + v |= sbox3((t2 >> 16) & 0xff) << 16; + v |= sbox2((t2 >> 24) & 0xff) << 24; + + v = left_rotate(v, 8); + u ^= v; + v = left_rotate(v, 8) ^ u; + u = right_rotate(u, 8) ^ v; + s[0] ^= left_rotate(v, 16) ^ u; + s[1] ^= left_rotate(u, 8); +} + +/// `camelliaFLs(s, fkey, keyoff)`: FL on the left half, FLINV on the right. +fn camellia_fls(s: &mut [u32; 4], fkey: &[u32], keyoff: usize) { + s[1] ^= left_rotate(s[0] & fkey[keyoff], 1); + s[0] ^= fkey[1 + keyoff] | s[1]; + + s[2] ^= fkey[3 + keyoff] | s[3]; + s[3] ^= left_rotate(fkey[2 + keyoff] & s[2], 1); +} + +/// The Java engine's fields after `setKey`. +pub struct Reference { + key_size: usize, + subkey: [u32; 24 * 4], + kw: [u32; 4 * 2], + ke: [u32; 6 * 2], +} + +impl Reference { + /// `setKey(forEncryption, key)`. + pub fn new(for_encryption: bool, key: &[u8]) -> Self { + let mut k = [0u32; 8]; + let mut ka = [0u32; 4]; + let mut kb = [0u32; 4]; + let mut t = [0u32; 4]; + let mut subkey = [0u32; 24 * 4]; + let mut kw = [0u32; 8]; + let mut ke = [0u32; 12]; + let key_size = key.len(); + + match key.len() { + 16 => { + k[0] = bytes2int(key, 0); + k[1] = bytes2int(key, 4); + k[2] = bytes2int(key, 8); + k[3] = bytes2int(key, 12); + k[4] = 0; + k[5] = 0; + k[6] = 0; + k[7] = 0; + } + 24 => { + k[0] = bytes2int(key, 0); + k[1] = bytes2int(key, 4); + k[2] = bytes2int(key, 8); + k[3] = bytes2int(key, 12); + k[4] = bytes2int(key, 16); + k[5] = bytes2int(key, 20); + k[6] = !k[4]; + k[7] = !k[5]; + } + 32 => { + for (i, ki) in k.iter_mut().enumerate() { + *ki = bytes2int(key, 4 * i); + } + } + _ => panic!("key sizes are only 16/24/32 bytes."), + } + + for i in 0..4 { + ka[i] = k[i] ^ k[i + 4]; + } + /* compute KA */ + camellia_f2(&mut ka, &SIGMA, 0); + for i in 0..4 { + ka[i] ^= k[i]; + } + camellia_f2(&mut ka, &SIGMA, 4); + + if key_size == 16 { + if for_encryption { + /* KL dependant keys */ + kw[0] = k[0]; + kw[1] = k[1]; + kw[2] = k[2]; + kw[3] = k[3]; + roldq(15, &mut k, 0, &mut subkey, 4); + roldq(30, &mut k, 0, &mut subkey, 12); + roldq(15, &mut k, 0, &mut t, 0); + subkey[18] = t[2]; + subkey[19] = t[3]; + roldq(17, &mut k, 0, &mut ke, 4); + roldq(17, &mut k, 0, &mut subkey, 24); + roldq(17, &mut k, 0, &mut subkey, 32); + /* KA dependant keys */ + subkey[0] = ka[0]; + subkey[1] = ka[1]; + subkey[2] = ka[2]; + subkey[3] = ka[3]; + roldq(15, &mut ka, 0, &mut subkey, 8); + roldq(15, &mut ka, 0, &mut ke, 0); + roldq(15, &mut ka, 0, &mut t, 0); + subkey[16] = t[0]; + subkey[17] = t[1]; + roldq(15, &mut ka, 0, &mut subkey, 20); + roldqo32(34, &mut ka, 0, &mut subkey, 28); + roldq(17, &mut ka, 0, &mut kw, 4); + } else { + // decryption + /* KL dependant keys */ + kw[4] = k[0]; + kw[5] = k[1]; + kw[6] = k[2]; + kw[7] = k[3]; + decroldq(15, &mut k, 0, &mut subkey, 28); + decroldq(30, &mut k, 0, &mut subkey, 20); + decroldq(15, &mut k, 0, &mut t, 0); + subkey[16] = t[0]; + subkey[17] = t[1]; + decroldq(17, &mut k, 0, &mut ke, 0); + decroldq(17, &mut k, 0, &mut subkey, 8); + decroldq(17, &mut k, 0, &mut subkey, 0); + /* KA dependant keys */ + subkey[34] = ka[0]; + subkey[35] = ka[1]; + subkey[32] = ka[2]; + subkey[33] = ka[3]; + decroldq(15, &mut ka, 0, &mut subkey, 24); + decroldq(15, &mut ka, 0, &mut ke, 4); + decroldq(15, &mut ka, 0, &mut t, 0); + subkey[18] = t[2]; + subkey[19] = t[3]; + decroldq(15, &mut ka, 0, &mut subkey, 12); + decroldqo32(34, &mut ka, 0, &mut subkey, 4); + roldq(17, &mut ka, 0, &mut kw, 0); + } + } else { + // 192bit or 256bit + /* compute KB */ + for i in 0..4 { + kb[i] = ka[i] ^ k[i + 4]; + } + camellia_f2(&mut kb, &SIGMA, 8); + + if for_encryption { + /* KL dependant keys */ + kw[0] = k[0]; + kw[1] = k[1]; + kw[2] = k[2]; + kw[3] = k[3]; + roldqo32(45, &mut k, 0, &mut subkey, 16); + roldq(15, &mut k, 0, &mut ke, 4); + roldq(17, &mut k, 0, &mut subkey, 32); + roldqo32(34, &mut k, 0, &mut subkey, 44); + /* KR dependant keys */ + roldq(15, &mut k, 4, &mut subkey, 4); + roldq(15, &mut k, 4, &mut ke, 0); + roldq(30, &mut k, 4, &mut subkey, 24); + roldqo32(34, &mut k, 4, &mut subkey, 36); + /* KA dependant keys */ + roldq(15, &mut ka, 0, &mut subkey, 8); + roldq(30, &mut ka, 0, &mut subkey, 20); + /* 32bit rotation */ + ke[8] = ka[1]; + ke[9] = ka[2]; + ke[10] = ka[3]; + ke[11] = ka[0]; + roldqo32(49, &mut ka, 0, &mut subkey, 40); + + /* KB dependant keys */ + subkey[0] = kb[0]; + subkey[1] = kb[1]; + subkey[2] = kb[2]; + subkey[3] = kb[3]; + roldq(30, &mut kb, 0, &mut subkey, 12); + roldq(30, &mut kb, 0, &mut subkey, 28); + roldqo32(51, &mut kb, 0, &mut kw, 4); + } else { + // decryption + /* KL dependant keys */ + kw[4] = k[0]; + kw[5] = k[1]; + kw[6] = k[2]; + kw[7] = k[3]; + decroldqo32(45, &mut k, 0, &mut subkey, 28); + decroldq(15, &mut k, 0, &mut ke, 4); + decroldq(17, &mut k, 0, &mut subkey, 12); + decroldqo32(34, &mut k, 0, &mut subkey, 0); + /* KR dependant keys */ + decroldq(15, &mut k, 4, &mut subkey, 40); + decroldq(15, &mut k, 4, &mut ke, 8); + decroldq(30, &mut k, 4, &mut subkey, 20); + decroldqo32(34, &mut k, 4, &mut subkey, 8); + /* KA dependant keys */ + decroldq(15, &mut ka, 0, &mut subkey, 36); + decroldq(30, &mut ka, 0, &mut subkey, 24); + /* 32bit rotation */ + ke[2] = ka[1]; + ke[3] = ka[2]; + ke[0] = ka[3]; + ke[1] = ka[0]; + decroldqo32(49, &mut ka, 0, &mut subkey, 4); + + /* KB dependant keys */ + subkey[46] = kb[0]; + subkey[47] = kb[1]; + subkey[44] = kb[2]; + subkey[45] = kb[3]; + decroldq(30, &mut kb, 0, &mut subkey, 32); + decroldq(30, &mut kb, 0, &mut subkey, 16); + roldqo32(51, &mut kb, 0, &mut kw, 0); + } + } + + Self { key_size, subkey, kw, ke } + } + + /// `processBlock`: `processBlock128` or `processBlock192or256` by key size. + pub fn process_block(&self, input: &[u8; 16], out: &mut [u8; 16]) { + let mut state = [0u32; 4]; + for (i, s) in state.iter_mut().enumerate() { + *s = bytes2int(input, i * 4) ^ self.kw[i]; + } + + camellia_f2(&mut state, &self.subkey, 0); + camellia_f2(&mut state, &self.subkey, 4); + camellia_f2(&mut state, &self.subkey, 8); + camellia_fls(&mut state, &self.ke, 0); + camellia_f2(&mut state, &self.subkey, 12); + camellia_f2(&mut state, &self.subkey, 16); + camellia_f2(&mut state, &self.subkey, 20); + camellia_fls(&mut state, &self.ke, 4); + camellia_f2(&mut state, &self.subkey, 24); + camellia_f2(&mut state, &self.subkey, 28); + camellia_f2(&mut state, &self.subkey, 32); + if self.key_size != 16 { + camellia_fls(&mut state, &self.ke, 8); + camellia_f2(&mut state, &self.subkey, 36); + camellia_f2(&mut state, &self.subkey, 40); + camellia_f2(&mut state, &self.subkey, 44); + } + + state[2] ^= self.kw[4]; + state[3] ^= self.kw[5]; + state[0] ^= self.kw[6]; + state[1] ^= self.kw[7]; + + int2bytes(state[2], out, 0); + int2bytes(state[3], out, 4); + int2bytes(state[0], out, 8); + int2bytes(state[1], out, 12); + } +} + +/// Reference encryption of one block: `init(true, key)` then `processBlock`. +pub fn encrypt_block(key: &[u8], block: &mut [u8; 16]) { + let input = *block; + Reference::new(true, key).process_block(&input, block); +} + +/// Reference decryption of one block: `init(false, key)` then `processBlock`. +pub fn decrypt_block(key: &[u8], block: &mut [u8; 16]) { + let input = *block; + Reference::new(false, key).process_block(&input, block); +} + +/// Deterministic pseudo-random bytes (xorshift), so the cross-check needs no RNG. +pub fn pseudo_random(seed: &mut u32) -> [u8; N] { + core::array::from_fn(|_| { + *seed ^= *seed << 13; + *seed ^= *seed >> 17; + *seed ^= *seed << 5; + (*seed >> 24) as u8 + }) +} + +/// Parses hex into a fixed-size array. +pub fn bytes(hex_str: &str) -> [u8; N] { + assert!(hex_str.len() == 2 * N, "expected {N} bytes of hex, got {}", hex_str.len() / 2); + core::array::from_fn(|i| u8::from_str_radix(&hex_str[2 * i..2 * i + 2], 16).expect("valid hex")) +} diff --git a/crypto/camellia/tests/electronic_code_book_tests.rs b/crypto/camellia/tests/electronic_code_book_tests.rs new file mode 100644 index 000000000..ea9f67f59 --- /dev/null +++ b/crypto/camellia/tests/electronic_code_book_tests.rs @@ -0,0 +1,28 @@ +//! `ElectronicCodeBook` trait conformance, via the shared test framework, for all three key +//! lengths. +//! +//! The framework checks the properties every implementor must have -- both directions are +//! inverses, the permutation is injective, the pair and four-block methods are indistinguishable +//! from single-block calls in every slot, and the key checks behave. All three types override the +//! pair and four-block methods, so this is what pins those overrides to the trait's contract. + +use bouncycastle_camellia::BLOCK_LEN; +use bouncycastle_camellia::hazmat::{ + Camellia128Internal, Camellia192Internal, Camellia256Internal, +}; +use bouncycastle_core_test_framework::electronic_code_book::TestFrameworkElectronicCodeBook; + +#[test] +fn camellia128_conforms_to_electronic_code_book() { + TestFrameworkElectronicCodeBook::new().test::<16, BLOCK_LEN, Camellia128Internal>(); +} + +#[test] +fn camellia192_conforms_to_electronic_code_book() { + TestFrameworkElectronicCodeBook::new().test::<24, BLOCK_LEN, Camellia192Internal>(); +} + +#[test] +fn camellia256_conforms_to_electronic_code_book() { + TestFrameworkElectronicCodeBook::new().test::<32, BLOCK_LEN, Camellia256Internal>(); +} diff --git a/crypto/camellia/tests/gcm_authors_tests.rs b/crypto/camellia/tests/gcm_authors_tests.rs new file mode 100644 index 000000000..0d61d218f --- /dev/null +++ b/crypto/camellia/tests/gcm_authors_tests.rs @@ -0,0 +1,201 @@ +//! The Camellia authors' GCM-Camellia test vectors, run against the keys. +//! +//! No standard publishes a Camellia-GCM vector and OpenSSL has no Camellia-GCM at all, but +//! nettle's `testsuite/gcm-test.c` carries a set it credits as "GCM-Camellia Test Vectors +//! obtained from the authors": the AES-GCM specification's test inputs (zero key, the +//! `feffe992...` key, the `d9313225...` message, the `feedface...` AAD, the `cafebabe...` IV) +//! under Camellia-128 and Camellia-256. The cases with a 12-byte IV are here, numbered as in +//! that file: 1, 3 and 4 at 128 bits and 13 to 16 at 256 bits. Its cases 5, 6, 17 and 18 use +//! 8- and 60-byte IVs, which [`GCM`] does not take (the nonce is fixed at 96 bits), so they are +//! not run. Camellia-192 has no case in the set; `gcm_bc_java_tests.rs` covers it. + +mod common; + +use bouncycastle_camellia::{Camellia128Key, Camellia256Key}; +use bouncycastle_cipher::modes::{GCM, GMAC}; +use bouncycastle_core::hazmat::do_hazardous_operations; +use bouncycastle_core::key_material::{KeyMaterial, KeyMaterialTrait, KeyType}; +use bouncycastle_core::security_strength::SecurityStrength; +use bouncycastle_core::symmetric_key::{AeadDecryptionKey, AeadEncryptionKey, FromKeyMaterial}; +use common::bytes; + +/// (case, key, IV, AAD, plaintext, ciphertext, tag). +type Case = + (u8, &'static str, &'static str, &'static str, &'static str, &'static str, &'static str); + +const MSG_64: &str = "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72\ + 1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255"; +const MSG_60: &str = "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72\ + 1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39"; +const AAD_20: &str = "feedfacedeadbeeffeedfacedeadbeefabaddad2"; +const IV: &str = "cafebabefacedbaddecaf888"; +const ZERO_IV: &str = "000000000000000000000000"; + +const CAMELLIA_128: [Case; 3] = [ + ( + 1, + "00000000000000000000000000000000", + ZERO_IV, + "", + "", + "", + "f5574acc3148dfcb9015200631024df9", + ), + ( + 3, + "feffe9928665731c6d6a8f9467308308", + IV, + "", + MSG_64, + "d0d94a13b632f337a0cc9955b94fa020c815f903aab12f1efaf2fe9d90f729a6\ + cccbfa986ef2ff2c33de418d9a2529091cf18fe652c1cfde13f8260614bab815", + "86e318012dd8329dc9dae6a170f61b24", + ), + ( + 4, + "feffe9928665731c6d6a8f9467308308", + IV, + AAD_20, + MSG_60, + "d0d94a13b632f337a0cc9955b94fa020c815f903aab12f1efaf2fe9d90f729a6\ + cccbfa986ef2ff2c33de418d9a2529091cf18fe652c1cfde13f82606", + "9f458869431576ea6a095456ec6b8101", + ), +]; + +const CAMELLIA_256: [Case; 4] = [ + ( + 13, + "0000000000000000000000000000000000000000000000000000000000000000", + ZERO_IV, + "", + "", + "", + "9cdb269b5d293bc5db9c55b057d9b591", + ), + ( + 14, + "0000000000000000000000000000000000000000000000000000000000000000", + ZERO_IV, + "", + "00000000000000000000000000000000", + "3d4b2cde666761ba5dfb305178e667fb", + "284b63bb143c40ce100fb4dea6bb617b", + ), + ( + 15, + "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308", + IV, + "", + MSG_64, + "ad142c11579dd95e41f3c1f324dabc255864d920f1b65759d8f560d4948d4477\ + 58dfdcf77aa9f62581c7ff572a037f810cb1a9c4b3ca6ed638179b776549e092", + "c912686270a2b9966415fca3be75c468", + ), + ( + 16, + "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308", + IV, + AAD_20, + MSG_60, + "ad142c11579dd95e41f3c1f324dabc255864d920f1b65759d8f560d4948d4477\ + 58dfdcf77aa9f62581c7ff572a037f810cb1a9c4b3ca6ed638179b77", + "4e4b178d8fe26fdc95e2e7246dd94bec", + ), +]; + +fn unhex(s: &str) -> Vec { + assert!(s.len().is_multiple_of(2), "odd hex length"); + (0..s.len() / 2) + .map(|i| u8::from_str_radix(&s[2 * i..2 * i + 2], 16).expect("valid hex")) + .collect() +} + +fn key>(hex: &str) -> K { + let mut material = KeyMaterial::::from_bytes_as_type( + &bytes::(hex), + KeyType::SymmetricCipherKey, + ) + .expect("a valid key"); + // `KeyMaterial` tags an all-zero buffer as `KeyType::Zeroized` whatever type is asked for, + // and promotes it only inside `do_hazardous_operations`; cases 1, 13 and 14 need that, as + // the AES suites' zero-key cases do. + if material.key_type() != KeyType::SymmetricCipherKey { + do_hazardous_operations(&mut material, |k| { + k.set_key_type(KeyType::SymmetricCipherKey)?; + k.set_security_strength(SecurityStrength::from_bytes(KEY_LEN)) + }) + .expect("promoting a zero test key"); + } + K::from_key_material(&material).expect("a valid key") +} + +/// The case's ciphertext and tag both ways, and a flipped tag bit refused. +fn check(case: Case) +where + K: FromKeyMaterial + + AeadEncryptionKey + + AeadDecryptionKey, +{ + let (n, key_hex, iv, aad, pt, ct, tag) = case; + let key: K = key::(key_hex); + let iv: [u8; 12] = bytes(iv); + let (aad, pt) = (unhex(aad), unhex(pt)); + let mut expected = unhex(ct); + expected.extend_from_slice(&unhex(tag)); + assert_eq!(key.encrypt_with_aad_nonce(&iv, &aad, &pt).unwrap(), expected, "case {n}: encrypt"); + assert_eq!(key.decrypt_with_aad(&iv, &aad, &expected).unwrap(), pt, "case {n}: decrypt"); + let last = expected.len() - 1; + expected[last] ^= 1; + assert!(key.decrypt_with_aad(&iv, &aad, &expected).is_err(), "case {n}: tag check"); +} + +#[test] +fn camellia_128_gcm_matches_the_authors_vectors() { + for case in CAMELLIA_128 { + check::<16, Camellia128Key>(case); + } +} + +#[test] +fn camellia_256_gcm_matches_the_authors_vectors() { + for case in CAMELLIA_256 { + check::<32, Camellia256Key>(case); + } +} + +/// Cases 1 and 13 have no message and no AAD, so their tags are GMAC of nothing under the zero +/// key: the one published Camellia-GMAC answer, run through `Camellia*Key`. +#[test] +fn the_empty_cases_are_gmac_known_answers() { + fn mac_key(hex: &str) -> KeyMaterial { + let mut material = + KeyMaterial::::from_bytes_as_type(&bytes::(hex), KeyType::MACKey) + .expect("a valid key"); + do_hazardous_operations(&mut material, |k| { + k.set_key_type(KeyType::MACKey)?; + k.set_security_strength(SecurityStrength::from_bytes(KEY_LEN)) + }) + .expect("promoting a zero test key"); + material + } + for (case, iv, tag) in [ + (&CAMELLIA_128[0], ZERO_IV, CAMELLIA_128[0].6), + (&CAMELLIA_256[0], ZERO_IV, CAMELLIA_256[0].6), + ] { + assert!(case.3.is_empty() && case.4.is_empty(), "case {} is not the empty case", case.0); + let iv: [u8; 12] = bytes(iv); + let expected: [u8; 16] = bytes(tag); + let got = match case.1.len() { + 32 => Camellia128Key::::from_key_material(&mac_key::<16>(case.1)) + .unwrap() + .create_generator_nonce(&iv) + .mac(&[]), + _ => Camellia256Key::::from_key_material(&mac_key::<32>(case.1)) + .unwrap() + .create_generator_nonce(&iv) + .mac(&[]), + }; + assert_eq!(got, expected, "case {}", case.0); + } +} diff --git a/crypto/camellia/tests/gcm_bc_java_tests.rs b/crypto/camellia/tests/gcm_bc_java_tests.rs new file mode 100644 index 000000000..5c507ae78 --- /dev/null +++ b/crypto/camellia/tests/gcm_bc_java_tests.rs @@ -0,0 +1,90 @@ +//! Camellia-GCM known answers produced with Bouncy Castle Java, run against the keys. +//! +//! No standard publishes a Camellia-GCM vector: RFC 6367 defines the TLS cipher suites without +//! one, and neither Wycheproof nor bc-test-data has a file; the Camellia authors' own cases are +//! in `gcm_authors_tests.rs`, and cover 128 and 256 bits only. These answers come from bc-java +//! 1.87's `GCMBlockCipher.newInstance(new CamelliaEngine())` under `AEADParameters` with a +//! 128-bit tag, over inputs anyone can regenerate: the three RFC 3713 Appendix A keys, the +//! 12-byte nonce `10 11 .. 1b`, the 20 AAD bytes `20 21 .. 33` and the 45-byte message +//! `40 41 .. 6c` (not a block multiple, so the last counter block is used in part); and, at each +//! key, the tag of an empty message with no AAD, which is GHASH over the lengths block alone. +//! `tests/mode_key_tests.rs` has the AEAD suite over the same keys; this file pins the answers +//! both ways. + +mod common; + +use bouncycastle_camellia::{Camellia128Key, Camellia192Key, Camellia256Key}; +use bouncycastle_cipher::modes::GCM; +use bouncycastle_core::key_material::{KeyMaterial, KeyType}; +use bouncycastle_core::symmetric_key::{AeadDecryptionKey, AeadEncryptionKey, FromKeyMaterial}; +use common::bytes; + +fn nonce() -> [u8; 12] { + bytes("101112131415161718191a1b") +} + +fn aad() -> [u8; 20] { + bytes("202122232425262728292a2b2c2d2e2f30313233") +} + +fn msg() -> [u8; 45] { + bytes( + "404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c", + ) +} + +/// (key, ciphertext, tag, tag of the empty message with no AAD), from bc-java 1.87. +const VECTORS: [(&str, &str, &str, &str); 3] = [ + ( + "0123456789abcdeffedcba9876543210", + "7a49673f1fc95a61bdbd4fd9991e69ce66e11221900db3fe0477c8db0fde7c3f86f9fb95ddcfd29d32fba91dc8", + "254bc51b6e3af975424eab7b4cf3bd25", + "23b111413e7a7d163b09f86dc5a9c8fc", + ), + ( + "0123456789abcdeffedcba98765432100011223344556677", + "ed112533b2cfe17a9db68a9c230c10a83cc3abef4991ee76baf0faf8d14bd0c87091ad693bd85a062f022c3fc2", + "157cb0bc12aed1c6a327cc7d0d7d93ca", + "cd362853de88b6f8d8a6b4a4b4a818fa", + ), + ( + "0123456789abcdeffedcba987654321000112233445566778899aabbccddeeff", + "a8f62afcade453f94e2773f6d2318693ea4d48319cd2ee0268ba9bd4c5c88f57b78226b445b5440e3006df2118", + "e66a02576a8bad35da49a0c073cae837", + "4ddd90b5409d15cf1a7b0469bdf6e7b7", + ), +]; + +fn key>(hex: &str) -> K { + let material = KeyMaterial::::from_bytes_as_type( + &bytes::(hex), + KeyType::SymmetricCipherKey, + ) + .expect("a valid key"); + K::from_key_material(&material).expect("a valid key") +} + +/// The vector's ciphertext and tag both ways, the empty-message tag both ways, and a flipped +/// ciphertext bit refused. +fn check(key: &K, (_, ct, tag, empty_tag): (&str, &str, &str, &str)) +where + K: AeadEncryptionKey + AeadDecryptionKey, +{ + let mut expected = bytes::<45>(ct).to_vec(); + expected.extend_from_slice(&bytes::<16>(tag)); + assert_eq!(key.encrypt_with_aad_nonce(&nonce(), &aad(), &msg()).unwrap(), expected); + assert_eq!(key.decrypt_with_aad(&nonce(), &aad(), &expected).unwrap(), msg()); + let empty_tag = bytes::<16>(empty_tag); + assert_eq!(key.encrypt_with_aad_nonce(&nonce(), &[], &[]).unwrap(), empty_tag); + assert_eq!(key.decrypt_with_aad(&nonce(), &[], &empty_tag).unwrap(), []); + let mut wrong = expected.clone(); + wrong[0] ^= 1; + assert!(key.decrypt_with_aad(&nonce(), &aad(), &wrong).is_err()); +} + +#[test] +fn camellia_gcm_matches_bc_java() { + check::<16, _>(&key::<16, Camellia128Key>(VECTORS[0].0), VECTORS[0]); + check::<24, _>(&key::<24, Camellia192Key>(VECTORS[1].0), VECTORS[1]); + check::<32, _>(&key::<32, Camellia256Key>(VECTORS[2].0), VECTORS[2]); +} diff --git a/crypto/camellia/tests/kw_wycheproof.rs b/crypto/camellia/tests/kw_wycheproof.rs new file mode 100644 index 000000000..822d06baa --- /dev/null +++ b/crypto/camellia/tests/kw_wycheproof.rs @@ -0,0 +1,73 @@ +//! Known-answer tests against Wycheproof's `camellia_wrap_test.json` (KW). +//! +//! Requires the Wycheproof repository (https://github.com/C2SP/wycheproof) to be cloned alongside +//! this repository, i.e. at `../wycheproof` relative to the root of this git project. If it is +//! missing, the test prints a warning and passes without checking anything. +//! +//! A `valid` case must wrap to the given ciphertext and unwrap back. An `invalid` case's +//! ciphertext must not unwrap; where its plaintext is one KW is not defined on (`WrongDataSize`, +//! `EmptyKey`), wrapping must refuse it as well. The `ShortKey` cases, an 8-byte key wrapped as the +//! one block RFC 3394 allows and SP 800-38F does not, are `acceptable`: this crate follows +//! SP 800-38F and rejects them, which the suite permits. + +use bouncycastle_camellia::{Camellia128Key, Camellia192Key, Camellia256Key}; +use bouncycastle_cipher::modes::KW; +use bouncycastle_core::errors::SymmetricCipherError; +use bouncycastle_core::key_material::{KeyMaterial, KeyType}; +use bouncycastle_core::symmetric_key::{FromKeyMaterial, KeyUnwrappingKey, KeyWrappingKey}; +use bouncycastle_core_test_framework::test_data_loaders::{Value, hex_field, wycheproof_json}; + +fn material(key: &[u8]) -> KeyMaterial { + KeyMaterial::::from_bytes_as_type(key, KeyType::SymmetricCipherKey) + .expect("a symmetric cipher key of the group's length") +} + +/// One case at one key length. +fn run_case(tc_id: u64, key: &[u8], msg: &[u8], ct: &[u8], test: &Value) +where + K: FromKeyMaterial + KeyWrappingKey + KeyUnwrappingKey, +{ + let kek = K::from_key_material(&material::(key)).unwrap(); + let flags: Vec<&str> = + test["flags"].as_array().unwrap().iter().map(|f| f.as_str().unwrap()).collect(); + match test["result"].as_str().unwrap() { + "valid" => { + assert_eq!(kek.wrap(msg).unwrap(), ct, "tcId {tc_id}: wrap"); + assert_eq!(kek.unwrap(ct).unwrap(), msg, "tcId {tc_id}: unwrap"); + } + "invalid" | "acceptable" => { + assert!(kek.unwrap(ct).is_err(), "tcId {tc_id}: the ciphertext must not unwrap"); + if flags.iter().any(|f| ["WrongDataSize", "EmptyKey", "ShortKey"].contains(f)) { + assert!( + matches!(kek.wrap(msg), Err(SymmetricCipherError::InvalidInputLength(_))), + "tcId {tc_id}: a plaintext of {} bytes is not a KW input", + msg.len() + ); + } + } + other => panic!("tcId {tc_id}: unexpected result {other}"), + } +} + +#[test] +fn wycheproof_camellia_kw() { + let Some(set) = wycheproof_json("camellia_wrap_test.json") else { return }; + let mut count = 0; + for group in set["testGroups"].as_array().unwrap() { + for test in group["tests"].as_array().unwrap() { + let tc_id = test["tcId"].as_u64().unwrap(); + let key = hex_field(test, "key", tc_id); + let msg = hex_field(test, "msg", tc_id); + let ct = hex_field(test, "ct", tc_id); + match key.len() { + 16 => run_case::<16, Camellia128Key>(tc_id, &key, &msg, &ct, test), + 24 => run_case::<24, Camellia192Key>(tc_id, &key, &msg, &ct, test), + 32 => run_case::<32, Camellia256Key>(tc_id, &key, &msg, &ct, test), + other => panic!("tcId {tc_id}: unexpected key length {other}"), + } + count += 1; + } + } + println!("Wycheproof Camellia-KW: {count} cases"); + assert_eq!(count, 159, "expected all 159 Wycheproof Camellia key-wrap cases to run"); +} diff --git a/crypto/camellia/tests/mode_key_tests.rs b/crypto/camellia/tests/mode_key_tests.rs new file mode 100644 index 000000000..20a841aad --- /dev/null +++ b/crypto/camellia/tests/mode_key_tests.rs @@ -0,0 +1,318 @@ +//! The Camellia keys through the shared conformance suites: construction policy for every mode a +//! key can carry, then the block, symmetric, stream and AEAD suites at the 128- and 256-bit key +//! lengths (Camellia-192 sits between them in rounds and differs in nothing else the suites see), +//! and the MAC keys' round trips. The Wycheproof suites cover CCM and CMAC's answers; GCM has +//! no standard vector: `gcm_authors_tests.rs` has the Camellia authors' cases and +//! `gcm_bc_java_tests.rs` bc-java's. + +use bouncycastle_camellia::hazmat::{Camellia128Internal, Camellia256Internal}; +use bouncycastle_camellia::{Camellia128Key, Camellia256Key}; +use bouncycastle_cipher::modes::hazmat::ecb::ECB; +use bouncycastle_cipher::modes::{ + Blocks, CBC, CCM_Packet, CFB, CFB8, CMAC, CTR, GCM, GMAC, KW, ModeNames, +}; +use bouncycastle_cipher::padding::{NoPadding, PKCS7}; +use bouncycastle_core::errors::{KeyMaterialError, SymmetricCipherError}; +use bouncycastle_core::hazmat::{EcbEncryptionKey, Mode}; +use bouncycastle_core::key_material::{KeyMaterial, KeyMaterialTrait, KeyType}; +use bouncycastle_core::security_strength::SecurityStrength; +use bouncycastle_core::symmetric_key::{ + AeadEncryptionKey, FromKeyMaterial, MacGenerationKey, MacVerificationKey, +}; +use bouncycastle_core::traits::{BlockCipherEncryptor, MAC}; +use bouncycastle_core_test_framework::aead::TestFrameworkAEADCipher; +use bouncycastle_core_test_framework::block_cipher::TestFrameworkBlockCipher; +use bouncycastle_core_test_framework::from_key_material::TestFrameworkFromKeyMaterial; +use bouncycastle_core_test_framework::key_wrap::TestFrameworkKeyWrap; +use bouncycastle_core_test_framework::symmetric_ciphers::{ + TestFrameworkStreamCipher, TestFrameworkSymmetricCipher, +}; +use bouncycastle_rng::HashDRBG_SHA512; + +fn material() -> KeyMaterial { + let bytes: [u8; N] = core::array::from_fn(|i| (i as u8).wrapping_mul(7).wrapping_add(1)); + KeyMaterial::::from_bytes_as_type(&bytes, KeyType::SymmetricCipherKey).expect("a valid key") +} + +fn key128>() -> Camellia128Key { + Camellia128Key::from_key_material(&material::<16>()).expect("a valid key") +} + +fn key256>() -> Camellia256Key { + Camellia256Key::from_key_material(&material::<32>()).expect("a valid key") +} + +fn rng() -> HashDRBG_SHA512 { + HashDRBG_SHA512::new_from_os() +} + +/// A 32-byte frame for the fixed-frame CCM key, within the framework's seed buffer. +type Packet = CCM_Packet<12, 16, 64, 32>; + +/// The construction suite -- key type, strength and `generate` -- for the mode `M` at both key +/// lengths, against the name the permutation gives that mode. +fn construction_suite(name_128: &'static str, name_256: &'static str) +where + M: Mode + Mode, +{ + let framework = TestFrameworkFromKeyMaterial::new(); + framework.test::<16, Camellia128Key>(name_128, SecurityStrength::_128bit); + framework.test::<32, Camellia256Key>(name_256, SecurityStrength::_256bit); +} + +#[test] +fn every_mode_key_enforces_the_material_policy() { + construction_suite::>( + Camellia128Internal::CBC_ALG_NAME, + Camellia256Internal::CBC_ALG_NAME, + ); + construction_suite::>( + Camellia128Internal::CBC_ALG_NAME, + Camellia256Internal::CBC_ALG_NAME, + ); + construction_suite::>( + Camellia128Internal::CBC_ALG_NAME, + Camellia256Internal::CBC_ALG_NAME, + ); + construction_suite::>( + Camellia128Internal::ECB_ALG_NAME, + Camellia256Internal::ECB_ALG_NAME, + ); + construction_suite::(Camellia128Internal::CFB_ALG_NAME, Camellia256Internal::CFB_ALG_NAME); + construction_suite::( + Camellia128Internal::CFB8_ALG_NAME, + Camellia256Internal::CFB8_ALG_NAME, + ); + construction_suite::(Camellia128Internal::CTR_ALG_NAME, Camellia256Internal::CTR_ALG_NAME); + construction_suite::>( + Camellia128Internal::ECB_ALG_NAME, + Camellia256Internal::ECB_ALG_NAME, + ); + construction_suite::(Camellia128Internal::GCM_ALG_NAME, Camellia256Internal::GCM_ALG_NAME); + construction_suite::( + Camellia128Internal::CCM_ALG_NAME, + Camellia256Internal::CCM_ALG_NAME, + ); + construction_suite::(Camellia128Internal::KW_ALG_NAME, Camellia256Internal::KW_ALG_NAME); +} + +/// The key-wrap suite: round trips, the length helpers, the error cases and tamper rejection. The +/// answers are Wycheproof's, in `kw_wycheproof.rs`. +#[test] +fn kw_keys_pass_the_key_wrap_framework() { + let tf = TestFrameworkKeyWrap::new(); + tf.test::<16, 16, 24, Camellia128Key>(); + tf.test::<16, 32, 40, Camellia128Key>(); + tf.test::<32, 32, 40, Camellia256Key>(); +} + +#[test] +fn ecb_blocks_keys_pass_the_block_cipher_framework() { + let framework = TestFrameworkBlockCipher::new(); + framework.test_ecb_key::<16, 16, _>(&key128::>()); + framework.test_ecb_key::<32, 16, _>(&key256::>()); +} + +/// ECB has no init data, so the `ECB` key makes its workers with no RNG and nothing to +/// return; the one-shot and the worker are the same codebook. +#[test] +fn ecb_blocks_keys_take_no_init_data() { + let key = key128::>(); + let mut block = *b"sixteen byte blk"; + let mut enc = key.create_encryptor(); + enc.do_encrypt_blocks_inplace(core::slice::from_mut(&mut block)).unwrap(); + let mut again = *b"sixteen byte blk"; + assert_eq!(key.encrypt_inplace(&mut again).unwrap(), 16); + assert_eq!(again, block); +} + +/// GCM and CCM are generic over any 16-byte-block permutation, so a Camellia key under them is +/// the same code as AES-GCM and AES-CCM over another engine; the AEAD suite checks the wiring. +#[test] +fn gcm_keys_pass_the_aead_framework() { + let framework = TestFrameworkAEADCipher::new(); + framework.test_key::<16, 12, 16, 16, _>(&key128::(), &mut rng()); + framework.test_key::<32, 12, 16, 16, _>(&key256::(), &mut rng()); +} + +/// The fixed-frame key's workers and one-shots take exactly the frame, so the framework is told +/// the one length they accept. +#[test] +fn ccm_frame_keys_pass_the_aead_framework() { + let mut framework = TestFrameworkAEADCipher::new(); + framework.fixed_message_len = Some(32); + framework.test_key::<16, 12, 16, 16, _>(&key128::(), &mut rng()); + framework.test_key::<32, 12, 16, 16, _>(&key256::(), &mut rng()); +} + +#[test] +fn cbc_blocks_keys_pass_the_block_cipher_framework() { + let framework = TestFrameworkBlockCipher::new(); + framework.test_key::<16, 16, 16, _>(&key128::>(), &mut rng()); + framework.test_key::<32, 16, 16, _>(&key256::>(), &mut rng()); +} + +#[test] +fn padded_keys_pass_the_symmetric_cipher_framework() { + let framework = TestFrameworkSymmetricCipher::new(); + framework.test_key::<16, 16, 16, _>(&key128::>(), &mut rng()); + framework.test_key::<32, 16, 16, _>(&key256::>(), &mut rng()); + framework.test_key::<16, 0, 16, _>(&key128::>(), &mut rng()); + framework.test_key::<32, 0, 16, _>(&key256::>(), &mut rng()); +} + +/// `NoPadding` turns the adapters into an alignment check: the framework is told so, and asserts +/// that every other length is refused. +#[test] +fn no_padding_keys_pass_the_symmetric_cipher_framework() { + let mut framework = TestFrameworkSymmetricCipher::new(); + framework.required_alignment = 16; + framework.test_key::<16, 16, 16, _>(&key128::>(), &mut rng()); + framework.test_key::<32, 16, 16, _>(&key256::>(), &mut rng()); +} + +#[test] +fn stream_mode_keys_pass_the_stream_cipher_framework() { + let framework = TestFrameworkStreamCipher::new(); + framework.test_key::<16, 16, _>(&key128::(), &mut rng()); + framework.test_key::<32, 16, _>(&key256::(), &mut rng()); + framework.test_key::<16, 16, _>(&key128::(), &mut rng()); + framework.test_key::<32, 16, _>(&key256::(), &mut rng()); + framework.test_key::<16, 12, _>(&key128::(), &mut rng()); + framework.test_key::<32, 12, _>(&key256::(), &mut rng()); +} + +/// `material::()` with one bit of its last byte flipped. +fn material_flipped() -> KeyMaterial { + let mut bytes: [u8; N] = core::array::from_fn(|i| (i as u8).wrapping_mul(7).wrapping_add(1)); + bytes[N - 1] ^= 1; + KeyMaterial::::from_bytes_as_type(&bytes, KeyType::SymmetricCipherKey).expect("a valid key") +} + +/// Equality is over the expanded schedule, so it follows the material: the same bytes compare +/// equal, as does a clone, and a single flipped bit does not. Keys have no `Debug`, hence +/// `assert!` over `==`. +#[test] +fn keys_compare_equal_exactly_when_their_material_does() { + let key = key128::(); + assert!(key == key.clone()); + assert!(key == key128::()); + assert!(key != Camellia128Key::::from_key_material(&material_flipped::<16>()).unwrap()); + + let key = key256::(); + assert!(key == key256::()); + assert!(key != Camellia256Key::::from_key_material(&material_flipped::<32>()).unwrap()); +} + +fn mac_material() -> KeyMaterial { + KeyMaterial::::from_bytes_as_type(&[0x42; N], KeyType::MACKey).unwrap() +} + +/// A MAC-mode key's `KEY_TYPE` is the `MACKey` the mode asks for: MAC material builds it and +/// cipher material is refused by type, at both key lengths and for both MAC modes. +#[test] +fn a_mac_mode_key_takes_mac_material_and_refuses_cipher_material() { + fn refused(r: Result) { + assert!(matches!( + r, + Err(SymmetricCipherError::KeyMaterialError(KeyMaterialError::InvalidKeyType(_))) + )); + } + assert_eq!( as FromKeyMaterial<16>>::KEY_TYPE, KeyType::MACKey); + assert_eq!( as FromKeyMaterial<32>>::KEY_TYPE, KeyType::MACKey); + assert!(Camellia128Key::::from_key_material(&mac_material::<16>()).is_ok()); + assert!(Camellia256Key::::from_key_material(&mac_material::<32>()).is_ok()); + assert!(Camellia128Key::::from_key_material(&mac_material::<16>()).is_ok()); + assert!(Camellia256Key::::from_key_material(&mac_material::<32>()).is_ok()); + refused(Camellia128Key::::from_key_material(&material::<16>())); + refused(Camellia256Key::::from_key_material(&material::<32>())); + refused(Camellia128Key::::from_key_material(&material::<16>())); + refused(Camellia256Key::::from_key_material(&material::<32>())); + assert!(Camellia128Key::::generate(&mut rng()).is_ok()); +} + +/// `as_cipher_key` carries the MAC key's strength onto the retagged copy the permutation is +/// built from, so a 256-bit MAC key labelled at 128 bits is refused at construction, for both +/// MAC modes, as a cipher key of that strength is. +#[test] +fn a_mac_key_below_its_own_strength_is_refused_at_construction() { + let mut weak = mac_material::<32>(); + weak.set_security_strength(SecurityStrength::_128bit).unwrap(); + assert!(matches!( + Camellia256Key::::from_key_material(&weak), + Err(SymmetricCipherError::KeyMaterialError(KeyMaterialError::SecurityStrength(_))) + )); + assert!(matches!( + Camellia256Key::::from_key_material(&weak), + Err(SymmetricCipherError::KeyMaterialError(KeyMaterialError::SecurityStrength(_))) + )); +} + +/// No published Camellia-GMAC vector exists, so the GMAC key is held to the GCM key over the +/// same bytes: GCM with the message as AAD and no payload gives the GMAC tag, under the nonce +/// the GCM key drew, at both key lengths. (The authors' GCM vectors pin the empty cases too; see +/// `gcm_authors_tests.rs`.) +#[test] +fn a_gmac_key_agrees_with_the_gcm_key_over_aad_alone() { + const MSG: &[u8] = b"The quick brown fox jumps over the lazy dog"; + fn as_mac(m: &KeyMaterial) -> KeyMaterial { + KeyMaterial::::from_bytes_as_type(m.ref_to_bytes(), KeyType::MACKey).unwrap() + } + let (_, nonce, from_gcm) = + key128::().encrypt_detached_out(&mut rng(), MSG, &[], &mut []).unwrap(); + let gmac = Camellia128Key::::from_key_material(&as_mac(&material::<16>())).unwrap(); + assert_eq!(gmac.create_generator_nonce(&nonce).mac(MSG), from_gcm); + assert!(gmac.create_verifier(&nonce).verify(MSG, &from_gcm)); + let (_, nonce, from_gcm) = + key256::().encrypt_detached_out(&mut rng(), MSG, &[], &mut []).unwrap(); + let gmac = Camellia256Key::::from_key_material(&as_mac(&material::<32>())).unwrap(); + assert_eq!(gmac.create_generator_nonce(&nonce).mac(MSG), from_gcm); +} + +/// A CMAC key tags and verifies through the role pair, several workers from one key agree, and +/// the tag is bound to the message and the key; the Wycheproof suite holds the known answers. +#[test] +fn cmac_keys_tag_and_verify() { + let key = Camellia128Key::::from_key_material(&mac_material::<16>()).unwrap(); + let mut generator = key.create_generator(); + generator.do_update(b"a message that arrives "); + generator.do_update(b"in pieces"); + let tag = generator.do_final(); + assert_eq!(tag.len(), 16); + assert_eq!(key.mac(b"a message that arrives in pieces"), tag); + assert!(key.verify(b"a message that arrives in pieces", &tag)); + assert!(!key.verify(b"another message", &tag)); + let other = Camellia128Key::::from_key_material( + &KeyMaterial::<16>::from_bytes_as_type(&[0x43; 16], KeyType::MACKey).unwrap(), + ) + .unwrap(); + assert!(!other.verify(b"a message that arrives in pieces", &tag)); + let key256 = Camellia256Key::::from_key_material(&mac_material::<32>()).unwrap(); + assert!(key256.verify(b"x", &key256.mac(b"x"))); +} + +/// A GMAC key's generator draws a nonce, its verifier checks under it, and the tag is bound to +/// the nonce, the message and the key. +#[test] +fn gmac_keys_tag_and_verify_under_a_nonce() { + let key = Camellia128Key::::from_key_material(&mac_material::<16>()).unwrap(); + let (mut generator, nonce) = key.create_generator(&mut rng()).unwrap(); + generator.do_update(b"a message that arrives "); + generator.do_update(b"in pieces"); + let tag = generator.do_final(); + assert!(key.create_verifier(&nonce).verify(b"a message that arrives in pieces", &tag)); + assert!(!key.create_verifier(&nonce).verify(b"another message", &tag)); + let mut other_nonce = nonce; + other_nonce[0] ^= 1; + assert!(!key.create_verifier(&other_nonce).verify(b"a message that arrives in pieces", &tag)); + let mut again = key.create_generator_nonce(&nonce); + again.do_update(b"a message that arrives in pieces"); + assert_eq!(again.do_final(), tag, "the same nonce and message give the same tag"); + let (_, second_nonce) = key.create_generator(&mut rng()).unwrap(); + assert_ne!(second_nonce, nonce, "each generator draws its own nonce"); + let key256 = Camellia256Key::::from_key_material(&mac_material::<32>()).unwrap(); + let (mut g, n) = key256.create_generator(&mut rng()).unwrap(); + g.do_update(b"x"); + let t = g.do_final(); + assert!(key256.create_verifier(&n).verify(b"x", &t)); +} diff --git a/crypto/camellia/tests/ntt_cryptrec_data.rs b/crypto/camellia/tests/ntt_cryptrec_data.rs new file mode 100644 index 000000000..75e0aaaf8 --- /dev/null +++ b/crypto/camellia/tests/ntt_cryptrec_data.rs @@ -0,0 +1,4052 @@ +//! NTT's CRYPTREC test vectors for Camellia, `t_camellia.txt`, transcribed mechanically. +//! +//! Source: , the test +//! vector file published by NTT (the designers) for the CRYPTREC evaluation. For each key length +//! it lists ten keys, and for each key the ciphertexts of the 128 plaintexts with exactly one bit +//! set, `P No.i` having bit `128 - i` set (bit 0 least significant) -- 3840 vectors in all. +//! +//! The plaintexts are not stored: `ntt_cryptrec_tests.rs` regenerates `P No.i` from `i` and the +//! generator asserted that every plaintext in the file has that form. Keys and ciphertexts are the +//! file's hex, whitespace removed, case preserved. + +#![allow(dead_code)] + +/// One `K No.nnn` section: the key and the ciphertexts of `P No.001` .. `P No.128`, in order. +pub struct KeySet { + /// The key, hex. + pub key: &'static str, + /// `C No.i` for `i = 1..=128`, hex; `ciphertexts[i - 1]` answers `P No.i`. + pub ciphertexts: [&'static str; 128], +} + +/// `Camellia with 128-bit key`: `K No.001` .. `K No.010`. +pub static CAMELLIA_128: [KeySet; 10] = [ + // K No.001 + KeySet { + key: "00000000000000000000000000000000", + ciphertexts: [ + "07923A39EB0A817D1C4D87BDB82D1F1C", + "48CD6419809672D2349260D89A08D3D3", + "D07493CCB2E95CE0B4945A05ACC97D82", + "5DBE1EAC9F7080A88DBED7F6DA101448", + "F01EE477D199DF2701027034B229622F", + "C841587ABD9A912E563774CB569D051E", + "1D9BC0C04546F0915C8CCD11391A455C", + "05E6EBB4BA167F5C479CEFF3152F943B", + "93211E0F788845B9FC0E4551FFE92AC9", + "B6D35701CD8FADDE383BBE8E6B70BAF7", + "8358F9F4EBCFEE348CB30551ACB151A0", + "D57516EB5AD93C523E40521BF447AFCE", + "66B2534C279C439133F52E5AD8B439A9", + "A71C69184A9F63C2992A5F18F77C1FE9", + "1ADCBE49AEACB9ECEBBD492B10E82C7B", + "27E3BCFB227C5561DB6CF7FC30387036", + "F4AE20365CC9D06B0CAE6B695ED2CEC1", + "3DD682F0B641ED32AD3D43EA2A0456E4", + "6E5D14A95ECC290B509EA6B673652E3A", + "F1CDF0F8D7B3FFD95422D7CC0CF40B7B", + "A9253D459A34C385A1F1B2CFFA3935C5", + "291024D99FF09A47A1DEE45BA700AE52", + "49241D9459B277187BB10081C60361C0", + "AD9BA365CC4DD5553D2D9FE303841D88", + "C2ECA616664A249DC622CC11196B4AE1", + "6E1A2D4794BB0DC08777A0BC7523E70E", + "6DB1F0CF59656BDD235E82B8CEF0BE8E", + "52F239C5EAF401EBDC54D2F011FF4B6A", + "6B58A08F648414B67FD6847D2AA51CBF", + "2959DD5367885A75EB48053CF3251A36", + "630B292E3B88EF641CDFD531E206605E", + "4BBB88EF82B70593FCC56AFD91540FDB", + "0A13055B118A45C606999257BD191426", + "5CF8E5C9F15D7E4F865020224853EB77", + "3898805042C7A4315C5EE51AF2DE47E2", + "8D3F96372E87CBB0B375425B3A10B9E7", + "4D9510A378BD784A70A66BCC75B7D3C8", + "70DB1902D37CFBDFB98F7C516F79D416", + "383C6C2AABEF7FDE25CD470BF774A331", + "47CBCB5288349B1A15DC9F81FBEE6B8F", + "21DA34D4468EEB13AED95DAE0FF48310", + "021C9A8E6BD36FBD036411E5D852A80F", + "6A459E2F839AF60ACDE83774D0BB5574", + "C19255121F1B933CAE09E58AEC0E9977", + "7BA949E27B2BE148A6B801F9305F43D5", + "E8CEB1026BCF7BCEA32E8A380EA76DB7", + "63F97747ED56A8F521B20CC65F6F9465", + "2091CFDC629819106188424AC694F75B", + "A91BDF8E8B88407942423CCE000527C4", + "73F9B44B9635A3FD683DBF8D49E9825B", + "9DC64B2133FAD5069FD9A7CC2FFFD1CC", + "28240F81FEC36B71E13F1FEA7A7641E3", + "20DD39FEE96CD2EFF972872A692B28FD", + "47A9E40483EC1925B635E47E964E8E93", + "9C0EBD822C49FB3D853DF5B315A87BA0", + "C18D813FDB45A594C6DC24E5A1F6CE32", + "7E5467FF245ECF80CB55C2D8E91F0711", + "394D4365B77954FDEA4145FCF7A7A041", + "B1D8311A492ED11F11E57B29221610C4", + "E5FBB947A63AEA90163AF04AD6951EF8", + "CA0627DDF580F0E7D59562825C9D0492", + "EF98FFD1AED295AAE1860F0274C8F555", + "8C698E5CFFF08FACE10C2DC5FF1E2A81", + "35A7767E02032C35B5CE1A6F49C57C28", + "AB36F8734E76EBA306CF00D6763D90B0", + "E854EB66D4EC66889B5E6CD4F44A5806", + "15B66DF1455ACD640B8716BCF5DB2D69", + "4C57AB5333E5C2D4B7E30A007E449F48", + "BA3E7FF28EB38EA09D8DB1440A9A3552", + "64E60227AFD80C40C70186CC94804C1A", + "CEB4423C20B4C91C2551F6FC227C9514", + "F736894B843EF32DA28576DE500D448C", + "58FDA98B678D15053D4B6C060368108C", + "E28CAE384E578F47657755EBCD97996C", + "0A64617BD4B5B166668240D105B7B6A2", + "4BD090C7E3D365B5EA80F19B4798881E", + "BC7B6CB9BFF4F72973BB2CD20A512C06", + "4C7ADDC5C867594E9EE75F0AA6AB9C23", + "1FBD05C71A36691AC6566A5298101D53", + "42D7D6B1F499D412F8793972BD968DA2", + "260EC86E2786FC68824576B934F32814", + "576C26DFD7046F9357F34BEA7DFB26A0", + "6D55E54BFB6F927174A02294C95E0F8F", + "1A6CE91DD458229C7675A34950D10E23", + "DAD0D5E7E000652825AA34D228EA8D8F", + "E68013F48D75EAD2BBC0B0BDA5E690BF", + "A07D92312FBAE37BFE8A834210AE4F9C", + "6EEE5F8544CD7D456366EB448813989A", + "F8E5C7FF4B79D7ABE8BFA2DD148820A8", + "C6349D75C7472BBD66F95B3A07C79C91", + "B85713C12D8658951CD1AD21C74D2CD2", + "907AA00B9F7D47A97623FB55BA911F29", + "DC3CD0ED23D11776FAB43A2A6A8F3557", + "4BFE58A8FD69179C14765B09AB70B705", + "A23996E0EA67EC280356E5F77130A551", + "CDEADE859B3AACD273CCA85A3E2E45F2", + "E0FC78489857D84DA03F40CE97147174", + "7615EA6351F6BB12855E8579C6995D8E", + "13E184344FE28C2E70ED0E4D0A8037F9", + "A5FE395F568482B87BC3EB208C81C942", + "B3103E11AF06C85565823F8CAA3159F6", + "7EBC2234D271B89C519C396985300030", + "0661D338F2E0C939BA1687820A768467", + "EC2B42667C0195A90715499617884DA5", + "AE077BA19D24E7188DDD3682FF196892", + "98823C24B9C65A66073C7952DC2B4B5E", + "6AB58432CBB3C2F503DA2D16796CC297", + "EEB5EBB3A53E4196C2F22BC1A4DDF5E8", + "33DC40AC5FDC126D38878416AF6C0FA6", + "38EDDC08E18B4AD982CEA921D2765A9A", + "7D6BEA038E9347C642E18631660A9558", + "FDA57921A473B5EE3700AD5ADF035019", + "699B4812E200337E9C1D2C397F0DFE4E", + "7A1EADF68B0807145D6C414852DECFC8", + "1645FFAA8AD76689C01DA8C40882781F", + "BA0C053BE702FA62FC66D8FEB12FC97E", + "841FD8AF69CF2C31F7D4D7B6959662B5", + "F675D59BDB33231861268F539829DA0B", + "A4967F45ABB4E8C7DC5E3806680F35E0", + "4D7E08081CC82F92ABA7C58C99F8343F", + "9AEFDB287C119B82353612B60ECCBFD8", + "979BB6A1553A17592A86E78DF144A699", + "A6FA8CAB06FD2E5BF3A858983C01757A", + "BE8511254C31E25420B91D6FEF1710ED", + "F589A908D18A21894971C0433581E1A5", + "4237585130E7C9F715235EB1D8C94DE7", + "DEFE3E0B5C54C94B4F2A0F5A46F6210D", + "F5574ACC3148DFCB9015200631024DF9", + ], + }, + // K No.002 + KeySet { + key: "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + ciphertexts: [ + "06C8BFAD83AA9AFD3A9AD4119BAB7A5B", + "1E21B2A57BA81A2D08A6968B4C76701C", + "75A07990AC4CBB3B85F66AB27D496AEC", + "5E3B232E289F45F36B7F10E93160CFEA", + "1EB5391BF5A64F86608F6E97F772261E", + "041C75DE634F46C411C6BA7CE7E784CD", + "9EFC9EAF39934BFC9DA87EA8A61A2DFA", + "DC67C904381CE27C4405BE31752B8CAA", + "913FB46D8F9B5818771EECA0C03CDDEF", + "4BD91167ABFC5818E59DA28C44212EB8", + "16E4E8C1A7F12252EC768CD631D0E77A", + "E57473D1E46A7266D52B6AA243DDF5B0", + "9051C9655435EFB29767E3E7A24E8156", + "7DDC32F41C9A3BC1B1435653A602A654", + "9ED74952903C1E70E36323447969629A", + "C192DD8319DB220E8C35D73B4DF75F18", + "93247787DD909BEEEAFEDC0D9E1BC060", + "FA22B53411DAB95027D94362EBBF9284", + "712E3DD55F3D2202D49B37A3F3563C4B", + "AEC04616D702DD7051DDC5EB17951845", + "989A141B92840879B4E00727BF952B3F", + "D98E3CA35031958793882FE7A2E3FCC6", + "FA956E34B3D020C0FA52BB00DAB5A63D", + "0217324FEDC68243628F6D6445D52939", + "4AE64317B2F5F628F423DF074FA4B119", + "50B4AC330E62FBEFB9CC97BC4DCFC2DA", + "F122EF053BE41E2E7CD52F8B8176D121", + "B253B2F4635742FBA04D247F4162A617", + "7DC385B48C4D0BB842AFE6367EB9A904", + "407F9E2C3169912E72EE05AFC7C60533", + "5C91EA85BB6D93792480F53F78CD7ED7", + "6BBB3D4F88D065B1EB0CCC523AA81E5E", + "B525883960EDFD6BDA70F84DEB091A97", + "CA45BCF7F957D396C7E681403EFE474E", + "9989B6C19790EFB7318729362699206A", + "AA9F91468145061292BEDA1C84223F36", + "744559B57D407D6029F2DE447D41AD41", + "48EE2891574F8510350BC1AC646B43D2", + "FC0E875F34C4B8FBFF1C452C708BAE4F", + "ECFEA6E44F077DDF7C6EF25F2AA9A1A0", + "B8A9A93F23F7A9BF0C95B4D0CFCFCFA7", + "FCD2C14ECA7D06ECA861EE5DC31D6288", + "A78EFE9BC798E11A61BAF23A63CED43B", + "1E898CF0FA5738E780CEA758C0E4C91D", + "503C389E38F34AAFB0C9FC52913B2585", + "170B5A681B55B11BED3F9C10084DC7B5", + "AB29C25E919AD8759E0629238AC3C985", + "0DE23B0D2572A9CBE5BEEDAE605FD5BF", + "11D71E6A33220CBB4ED08943E981C7ED", + "9D3ED01B9097A65B4D12932F53ED89D7", + "AC5F87B359FDD303CD21437ECE2D9941", + "BD174AD035AA328F284F55F8190C3E58", + "5B9DC1D8EF2D325647947B73C56A36BE", + "FDBDBEF79D2A4C5A036A4B9FB50517C1", + "A082888EA28C0BEE273893B3A18AE5BA", + "C4E23555C189EAEE33C7B6B9D010FBF2", + "E4CE74751FCC30966122CDB40B5DBE02", + "65AE16A97C4D67A9DE30506CDA59CEF3", + "FC9DCB814BA874A49F3640D6959E4BF8", + "CC988679EA0FA6FAFF26AAC09F3DB5BE", + "DAF8D657328AFA5280F2AE7419AC7B28", + "DB4D508B542DA4FA21A6956CAD867EAB", + "8693653289274BB0ABE3CA8D81978DBA", + "9CD9E377E73D37D3BDEA0B8B59663548", + "06DFFA494CC7717033183B4DB6A1B3B5", + "FE69DE74B98C7018E53BE12C40485083", + "C0A180F854BD8953C30726CC35E1248F", + "AFAFE31E09831BC9C5B9F8D4F80FF31F", + "39EC86D31A40131ECE0BF31E9AB31B34", + "D67CE449D37BB78C79DBD624F260ED3B", + "5F840C0C06D3E1DABF54215D03A77E46", + "96E682A2B9822C1FF375724494715D14", + "5B63983B18C2B6A948714D64983C708F", + "45585762BF3171F6E3FC44BAD533656A", + "2E81545BE336B68D9328FA92B09D605F", + "09480FF15DBB491EA725645CE5F03972", + "2EE474310A7EC173A4ABD1B5BDF14E59", + "35C02A5B2D6EB53B2F9FA817BB9D3F98", + "111C9DF7BF61E517B6F9D483CE29D3B3", + "77AF9892E6FAAFFF5B8D05193B1A3A1D", + "71D7D9511DC5BF0C38B43F3849615347", + "0C26359876F637C496C2583B3A262318", + "2094B58F8DD4A7A0D8F53EE607E989E3", + "400D63C72685FA7EAF180266A2C97E9F", + "3E78D2FE504D5C9B957B612F63FB33EE", + "128F29C79783E2013823E9FD8B0877D8", + "F0A7396CCD08EBFF0609D50B01A85475", + "42347D4DCFAB73287BEBB6A549B15B60", + "ECF4E8C61D67486060733050A92F57BE", + "28FE34E171CF08FF93CFFABFF17E79B7", + "A3FE0A4FBF3668682C1BA9C584199DD4", + "1E41060E299B1B0FF368FDEE781FF2CC", + "98FBE84D83EBB1F9487078CC9ECCD670", + "F53C80607C829FC64800CCEB8A318AB8", + "72BD58A883CB5D449F1622B0D89976BA", + "A87B89EBC4AE26A1FE770B16B3641E5A", + "A343113148FAB0D5024CE8B1C3A59FE0", + "1AF2CD3EC8BC64C1506B5FB220D80DBC", + "B9077EE73C83BC8DA735619CD84C3029", + "859318CCEF2C484994D480CB37C2D190", + "7F292FECF6688F035ACA26507373E27A", + "3C851F3B751EA94E073A445B2101562B", + "A1F5E665E26C754B054700D9E408CA2D", + "A5429EBE26FB17BD8616082440917967", + "8F6A9ECDA9A179D31CE82E0EC23FC2D2", + "6EE08E68BD04D3309FD867E255323CDB", + "229EFD2E09A00AEEBD3C78DC95F7AA69", + "727EB5B8EEE3BF0BC42D896A3484FDF9", + "0FFAF9F0FD33E1491C9D10943702EBA9", + "06D2E5ED763CB4CEB5767F7F68851BF7", + "6E9A157C5EA4FB963AD19AB9386DD85C", + "0E02CB45A9193341CF9F9CF584734691", + "BABAC96FE6FAF9B474A83D786820F3CA", + "EE3AD4E33A759F98B67D6843587A4719", + "78D7AA83817E8D692FE41D5C42854CAD", + "DC847010E0E285F77F1FBE5C4B6CCA1E", + "41402502600214C4B1E0D58553184EF4", + "DB67E1158855AED8F1199ABBDB96B0CE", + "08316D1255256D2C5E88971510A340B7", + "15181E7C4696D7F20997FF78A40D5FF9", + "65A682A9B7DFC2CBDFCD699A74322E45", + "B84B0275A7B8F61F137781CD3A3FF784", + "8D65E47E8C94F9B6DA46E8086E5B04CD", + "274292B4103745A65D6D7899EFFB878C", + "4AF78E833BE90E1696ED1977B61B38FF", + "1ED0EBF28AD3AFE0B50CA2741565715E", + "8249CD11A315F626D76674E3517BD612", + "3C8F50453F9D0D67F33845D77D633AB7", + ], + }, + // K No.003 + KeySet { + key: "0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F", + ciphertexts: [ + "FBA47572BCE606E42E4CC2DEF9C8F724", + "38C716DB171CFCB72F11C514AA70F618", + "0D8A8E45B1F2D02C77A14B5AED647024", + "49B88D6314F4579A68AA683AEDE16AB0", + "AE04D70AD8EA2521469C2D45823ED54B", + "6ED7AF96BCB503ECC7D2B44B993C5F70", + "6B584FD1BA9A652E6989CE2C00887104", + "FC56DF7979933683F7B70D3DB1B81296", + "E89EDA04F25F43038F89CB4E685CD3AD", + "D566B703727F1E330362B1D5B8260E74", + "3AD78E8F409C7D89651B22FC88544BCF", + "C6D3D439D6364A504D3A162E8BB1810C", + "257EFEB5E59CDFC7440712BBAA0D0C0C", + "24A41B403FB8E67B82E5610D4D602F71", + "D48E63DFD51C6741DB6D7F9285227589", + "8BA1A04637BA5346EA1486DF9EF7B1AE", + "841BB1FCC878843737300B48EBF98479", + "DD086A8B705D82B2D22DB650D60DCB9A", + "5E1E0CE416F89AA59F6ABA9F0117F1D6", + "55709A35405EAF5C7E5FF0E8CDADA0AA", + "F384EAA5F8B57DDA113ACFD19EF5B934", + "89F197CB6DBE072145515C41AB2012B1", + "0B890F34EC0366EE8499BA5070F05BAD", + "C71D9E88531E2E095FC5B9732490FC16", + "681D6F7C9442BB6B73B8FF7240DAE678", + "4C25E2A9FAF3807FDA9E5C5326723595", + "B9FD10B88481992A43F3C675F58EF6A5", + "4EA5BB4C04ED4BF6C417CB58DAE6ED3B", + "AAC6EDD8BD7D592F05EDFB13E28C152B", + "C04F62C32140D3BE445DED7EF274B37E", + "11296704518ABA2FF41C9C05B7CD3A30", + "B60FC45F14CC9E493EFC5D383407C2BD", + "11459D8D7E406BEA50097AAF197D289F", + "7A08A190551C10BCA2B66BF754619E69", + "6F3839B64FAC8FB522C3FCAFB85A765D", + "A19FD94ED449D14EED27F808B89A18BF", + "0AA15C353F3B8661346F51FA2F91B3AA", + "902C1D82A7CDADB43E20EC7C9772B2E6", + "8C4177E37EF479572EB1D160C6D3B619", + "CEE7CE1585A561613B8463AB23463F3E", + "D869AEA69FD9B8074CF21C2CD739DE80", + "F9FBB0BA5AA936C06AE650153CE25DEA", + "070E7F62CDB9E44703A458938D87BA49", + "9D36E5551E57EC14DC3EA5DD8B00E06D", + "5F977527078DA084672908F4387256C0", + "FB224859DA102AAF5595E96445D7958B", + "B644012E041B75446A714AAC5C1B493A", + "4FCBEE3736C73920D05D5B59FFA13A6A", + "607626598E57F220E15F0D75BC468831", + "D7EB82CC97340D154419092A82D48D28", + "604ECA7CB92F98946649F862E07C5337", + "D1923CB1754C52EF927F14C017439CF1", + "2CD435807B8DC2F4708D6ABCC05F6836", + "CE868B38023E2B8EFA6D4D858FAF25EA", + "C812A512D5F77EEBD85796783F1EF73A", + "92FB4FEF6583D31BFE6A6EB361BEA1DD", + "06F44B8C19343B64B4ED9A74A94655BE", + "991233D1DF2595A24C0AB7AD841BC508", + "72D7D11A361E4420AAB9EAF2F40C3468", + "3A049D28C53B6B47198DF03169016C23", + "823405F86E4B0DD6105374A5C2BD33EA", + "6E453DEC85760C60506A4BC733EB4372", + "F2FFEE70EDFB2077131CAD2048D6AA52", + "63B4C09D4555D57230B702344499826F", + "2DBC79D8F8A057AD8F5BE39476299572", + "63D9133B9AED09D3E07B082450D4D6B3", + "A26F016B4217683CD71E3B604E94C318", + "8EDD5181CD66FD2C9406DE2E6B122245", + "563FEACDBEBB566D2B7E473F95609AC6", + "844E1529220C1044E405E71169066208", + "6681FBE76527022005F1646F7C8C6AC0", + "8A7BC62F628B0642678572BEE861DA00", + "4DCA79C74E3D3672E0F8252E6E672B8F", + "40A32A9E784EB409E181C5B64D84BDF6", + "89ACC8B7AA5AB078D1E2CD333D1FEB67", + "14C39BA644D2ADF5DF6E37557AE50D77", + "C149C31DE86736DCB7E6B62DB41EC673", + "CA85FDB30A2B3675756BCCE96C79A388", + "08D05A5390BA7331FF6BC8037B8B769E", + "FD76C43B95C75ED7CF44839E65BF68AF", + "546AC84850124D29367783B3D6974D24", + "D129E64F5C01D72E670C29C16B85E5D8", + "BA9C1F2B7C31D4AAB2E21820758F0D1B", + "7F990F9C7D44ADDD53B732E002A1E2FA", + "7A8476EAD626F61AD8960D1C486A26DD", + "6EF2301F1C8751F988AFD5F88B6065FB", + "3460B8603A6E71222D7C56BCB661F1EA", + "45A82A32A5EFB40F079B69C57A916D86", + "E2C874B46975DAE3A35BF226908A31A4", + "D033F2C43F982729FA2C11249674D15E", + "04BE60A3C507898F1721562DFEFCF5A9", + "86882BF45099B81E94E70CBC68850B59", + "E4F9ED0B3A4AF738900844C14E207DC9", + "63A72A97AB92DE01BB7E3636BB156336", + "B7D56DC599C4D4E82FE5BAC167417801", + "CD1E1651BD7131D33C148F159B04638F", + "21C5C6CFC5CD2C64C20D9740AEC16718", + "F5F4309F5AEF05722FECFD7D7B8DA673", + "6A08E3337742A990455F0F7A9039143F", + "214C90F068283DC5C50D31D5E4A81481", + "A7F60E5CAC0FD910112597C6D57EF0B8", + "249A66B70CB009AB5F1F64FD043DF87E", + "7188B20B833803963E3DFF942E64996F", + "044CF9921F14D212D07B01B64BB1EAB2", + "DB51CD5BF95DC97A06D0930F42C80198", + "15B818838E9DFC38C455D0FDDEFCB4EE", + "851FA8F573C9C48B03A676496615D443", + "77FD71C3F637BC489D30355A8267DA90", + "85FC64ACAC44F00CA407DAA32674D1C2", + "BF0A48A0F8D9D0C5BF578FFDBF613949", + "2139238DA24EFC7D231DAE62A67AC9F5", + "0C5E95241D13D1C13176FFBB09133447", + "AB5552C71FE8F0BBF3CEE4B6B2301B44", + "B330B7F671C3B319A15B1571C909F907", + "5C252E6FD519001B83398319F306E00B", + "56447FC15A598F813300193BD53910C7", + "06CE22CEAC983C819717B69E8C26298C", + "833C09AD25C622F7EE107F5078FEF671", + "8B7BB7E6F6C44BCFBA866BF85328BFCB", + "74AFEE48658D5CEA47233AFB440C4B2A", + "192B5FF20752451F9CFEF20DD35DFFB9", + "239367CE402271125F1D70C7997AA142", + "87A93FA66145FB3371B9B4475A886BA0", + "04DCF98B939D8C843E615C75A227443E", + "679DD66691761F2D0A870E573BAD7C0B", + "37BC53723204CAC34F238EEDBBB703BB", + "F806D79B83B0125ED95A9C4A0A18FDA5", + "DFA1796DEE09701CE42A3E5BE5A42E11", + ], + }, + // K No.004 + KeySet { + key: "F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0", + ciphertexts: [ + "B4FE7BCCCDC91C2742AFC654654D5C55", + "E9F5CD89056B7E0498958269826BBAD1", + "F366D5EE9864C01B8BE094C8884AAC0D", + "FDA3E9C83B12BAD0ABA3722D2B909AED", + "3B7655E3572C4C2154BF429E42F49530", + "975BBA5A0F45C52E7AE856F05DE82BFE", + "C3AE01DF89B9E5EFAC63D10BBD657719", + "F0B96F66602F2CF82B710BF7D88B80F3", + "6637DBF2A9E418FD25C41EDF1797C99D", + "7C2B4B6E8E43B5F5449BB94594F96013", + "EB348DB2B376DBC6BB4FD21A68FDE2BC", + "CBACFC4001EDFC05C9F812557DFFECDB", + "76824E8DC7958891AA3682A2B21B78E4", + "1843FDACA86BB4F3A409799863BBC2D1", + "8A5B0BBD5DCA5D649FF5347920358061", + "2725CA668460E8F323C4DD925994F617", + "95D6FAF36BB39F17BE18F4F484CF995C", + "6C0EA27F6F56D67B23AFD32D00618976", + "ADB7EDEC3FE37E4546CE93FACA4E94BD", + "94B6554BA3C02D79AD7DC562AF993A78", + "D0A03C80CDFCB7A9CFC0486FE181829D", + "62764C59A845E7AFB726F3D37956A8BC", + "39FEB5495F62FB1CF476F0B646C93ADF", + "11862B12C3F5418A2402FBA78F72FFAD", + "165D36B209D0D9928C695EC82AAF2288", + "8D185260A0C1CD894EC36A44425E5825", + "C93AC81AAA34314C22C3A9AC0B8A691F", + "91118F4B1BCE384A21C57B84D8C05DAC", + "98CDD3936109DB6F2B9F9C2FD3D0D57D", + "E8E7F2C41F5968B39F0154C8562E9D87", + "B1DBFC5954D48078846F9F8306991564", + "F07F2A74859D3E9BE4318679625319E7", + "7887EAC22B4498E4970436AD62CC94AA", + "A3419D3F33F1A57AF2608078A73739D3", + "98E25EFB3C28E7D0D25BB575EFD8EFB7", + "E29531B721E1FE3CC995E120AE79FCE3", + "6040088BB92C6A3842F0443384525980", + "6F5A19F63E85B38F221A4195ED81675D", + "CF9A3B0A0C9B26A44F11CBB4752C97A4", + "47C0BFEA24A34A77E5C294DA5B1AD1B3", + "41C8CC33A8676AAF4CE40AE075FE72FC", + "EDA6C3C1F7B055A236B4FE1BC3985DA4", + "F19BAE53AD5899E5CDE72A66DCC1CE26", + "09B5198B8FE944A5C29EBB79A2BDFDAE", + "1495C70DE7C0FF30CB6FAD001B09985D", + "FD90D5DCD248CAA1AF65D4C3AA42311D", + "8ED255B69E0E1E452752D5049D468027", + "C0D8F04B50DE3CBCB7D53F9784CD3676", + "1C2054DB730B1EAF2687A4793F60E278", + "C84F53032493D405BD9885D589471D42", + "9E3690731BD2961D605AA494D4BA6139", + "109FA73534822EFBD7EB405B4ADBE61F", + "FD06AF3A972633A9DCF38C5DE2C05B83", + "98308803480504C2CDBF037071CA9B92", + "BD42B326732825B3284EFFBCC8FE960C", + "2EDCBF7C7C85AE8FDBCD92FD3B126A30", + "EFAF4CA41267477C72DFBEA7F8705B91", + "6693839F90A587966458615A08594401", + "D0BD26AE558F6D7B6A6495FE4A4DB84E", + "14B8144ADACD2C40EEB39A02C3162D30", + "495E6016BAAC79A27807A19633C7B375", + "47FF54B4E02F575315901B5B144EE3D8", + "8CA2345FF3786157CEAC6157202F48D2", + "74F31DE780051752B39FEC7A50902868", + "5D4AB5844432EECD98C4DB066EB57F54", + "295A01EEBA15DD98D6144135EA5428F0", + "D2C4DC9612F8329CD8499E8E7E537C4F", + "6235407761E01F2A3B4ED3E93B0D8224", + "0A6F1FC6FC4442CBD5B6582C3C305303", + "B84681F16A74229CA7FE87B3D867CD41", + "BD71BCE5C3731529C20BA98CC4A46E81", + "8B08FDD204383E363069639E22D503A6", + "0D1BB033151215335A63E5783F9ABF2F", + "45429765A6D5927F448E5A0436667D3A", + "F26F367E88D3EA22D0AC3A8068D78664", + "7C966A239CBC91C1E78A6D761A6F047E", + "659ED9B4EC95FE2F0AD1937C55D4505A", + "7CA855C179F9FF130BCE34B0CB00C158", + "0AE92654EC34BC2D310BD9DD2675C8F1", + "D3DF15708915976634B15A8938BCC571", + "44BE467C6A90E5768FEBA72D78F35A37", + "665B8D5F806E9F5F81645DCD361B976E", + "83D8559D5D6EDAD68C587713B15A7974", + "E906FC4A80FABCCDF50529AA9C3509B7", + "97C93E32754ACAA5367E019DDF68D1FA", + "118A551D15326D38F8D850DD8644E7C1", + "B498968B7785F9B4905356EAF9FCD2A1", + "DCD6A2C251604A55B3819E37F0CD9039", + "E0E2AC2D31163930924996E06BA625C6", + "5DB6AED0DE09D26955443CA23A70035E", + "AEA9E2D0825FD71D65EF176811F8BADA", + "71DEC9E175D163005789A116EEE8AB14", + "0E73451633FED5F52DD4D573DB1267EA", + "98DCF4896AC2C46DAF690F829AFBC848", + "B186867AD10863B24B4985A3A9BF6173", + "3FBE4EC3F23F3CF927323D7200638E48", + "8C8E45946AAAE949D82E2DF95AE197CE", + "2C41E8983A220B9E515A65495D42F85F", + "D92F4565B2E40C438555168BD52D776A", + "F1DBCF3AF0040A686926B5E5FE6D6AC9", + "AA7B073AC076ABCE24F45CB09EA3689B", + "732D38948D6DC6B0458543B7E29E5F18", + "F9A6D95585B48465FC3683B08B74E6E7", + "F4EAB36917FD5704F2B18A7257EBFEE1", + "3BD766EF81B5AC6ADB12FF45EF35A0AE", + "CBA3488EB25262F1420B96D32F9340D9", + "D28DA172DCBF567C3A796814CB56F0E3", + "DE08903A0740ED613D7DE6F9366A9512", + "B2B5ED24B5C42346D1201AD81D0B4278", + "DCF8FBA2F4369F2078DC19151C19805C", + "58E5AC251C2F58E26FC42B50C3CD1493", + "63E8F9446FF3607B3434A0DC1D649FEE", + "0B1A30E840A970554F3BFE2F03833EAE", + "F7322290FCA370187935D2341F1E4CF4", + "50AD98651A70FD6BD7C0D52FB9EA091A", + "55368BD684DDC31AAD58A78224E4D95D", + "7A8DE02ABA87059D99667AB0AA1804E1", + "A68F495B1CA56EC4CB6DA1D73A426F48", + "754B2C13C3556C9341E7B4A764C54D65", + "58AD2B181D7E40DF1D5EA8EC6432B115", + "DA56BECC01E1B7B59AB980570543FF4A", + "D449CDB52F6A9AA5E43BF9CB9B69FBBD", + "9AE73F97C8EBACA636ABD1D41F4DF328", + "7C951A1B1DD6CE835EEE14420B7F18AA", + "D72665E2B163522A7B0798CB8B700F28", + "7C1467AFABFF067962836C2F59018432", + "5EEF67277FF52764D2ACFE1645581379", + "225BFB015C2D99F89389577442F3364D", + ], + }, + // K No.005 + KeySet { + key: "00112233445566778899AABBCCDDEEFF", + ciphertexts: [ + "7CA3E2C371E56A1B0ED76BAB4A099992", + "774F7F1F0ED847B6E23C761E4E700D8F", + "AB013779EFD509DF0C4E0CF83B89AD0E", + "29D2F300E3B14606820E64D6D167FB95", + "F7B0FF19E5E17FC160652650277752AF", + "BF52F191AA56119C3EE9EB96D5CF2CC8", + "932FCAE2A5B5F0CC71F093B36266C233", + "44F0466539AA68AACC202763084D7497", + "98D38ECC8DA5B84725ED5604B888B497", + "DB9E4C96D11E2E143902D5D8E53EE5BC", + "5BE0E619D2D5F1BFDF4AF5D627E26137", + "440FE3EB452395B3D1593D504D375F59", + "5AD4782A0899D0D4E276EC7DB191FF6D", + "4C6ED7B0FCF49371F667FB4EE613C682", + "E668D500365715B1930BED3213BC2A2E", + "FB473C8F2AD1F284FAFCA147076F30C2", + "24AF50175E4CEF7A19EC38865BCE9152", + "E7317B72B2D4A37E123A078EEFA8B10D", + "1CF39BED7A35EB2644E67ACCA6E3A8C4", + "28445547D6B7CA319316FD5FE6FE954F", + "05E44D4793F50DDAA6F81A9C112AADB9", + "FFD99F7025825E404EF10322A012E574", + "1A17643CC9C6A7E6398DAD1EAEE47EB8", + "B2F270D5B866EB68A450558F035FE56B", + "B13C70964BB2260320A75FD78BBCB6D8", + "F4EEBE235B0BE5C6FED4DDA48F6158AA", + "175DDAD6D3F10870ABDEF5F2CF211706", + "C573A8D7691EC89A6939971373CE8E38", + "BF10AC2A31360C3280780954D58881C3", + "E47DFA57250C2FD91655DA630E3598D2", + "064B4DCFE52640D90F013D293923BEB9", + "1A2F77C3E45133573B94B3F18DBB80BC", + "A5AB33194B1CBBD289A4BBCA6FE8DCFC", + "D34EFA57A41484A2987A678FED65E3B4", + "761783C5ACAC0E7EEDB4790734A181FA", + "494AAEF562FE09353783296D81327373", + "6A4F8DEA8EB4EACBBC22FB004020CDCA", + "4BB345BBB952BE87A2D28FED9531008F", + "170C6F8EC4B54433FCE17C0F843EA032", + "373B3B1D7099CA1E2295E15BAB394546", + "B31942F388D71905724030C09FB92C45", + "9DA886940CDE4131848D69094A742600", + "3DFB2032427F686EF939447048A50515", + "02573D859A3390285EE4384197860B40", + "CAE1C7366D18631C775D7DAF57AA1C69", + "60FEDBA349C714894FD77349663DEDAF", + "CFAB9F930F86033C39FC1E427BD49716", + "AEE419D78DC5BD0BD9F00AEB6C7C35E9", + "059C26AD3DBA92CB471F67BFC94D5D70", + "3D1D8E371E3642D17A8A3954F8760831", + "7DF8A0D87D39E821C2A37717DE4BCE7C", + "CA811D49634C446185CE05EF239FF62C", + "BCCB2653437C8BD407A1E12B51788182", + "685EE32FB84265FD650C0969E2111693", + "21495D9615757D0C23CDB25FEAB80EE4", + "BF999156B21C6DE4926D1FEFF1BECFAB", + "D5F3BBCD51D221A0E516388CB9F1204D", + "A874433698C0CF5346BD025BA4F29808", + "4609392600A149E03A51B40A20042349", + "348B4A4F8A46B24779BCD866FAE22823", + "7616EB792BDB8606D421EB52BB71A2E1", + "5DABDBFA9332F2E40842516531DB32F5", + "BC01F4FEF92EEFFD6A2E0A75309F85C3", + "E4B1828B01AA99A47218CE0295F1F375", + "20BC527807BF21BC809CC0A9F0B8C96A", + "241F5649EA427A9EC5E49CBC3238FED4", + "F55B5724920A0C0204690AC93A27D2A9", + "2EC0850D581923CAA50E09B9626E5756", + "9693E4D5B32F76763FF15E04C947B976", + "8393599CB2CDE518BFF13A88A87623A2", + "470177B349A5EDE73B38C2F4E79AD22B", + "36BA133D284B0507C786C380A4CEF6DB", + "39090891A28F257A56904D75137F4ED5", + "13A76A95CE77590833798074A26F54DB", + "550B0EC29D93EED0EA8EA84D8CD6855B", + "267EA551A4FF50A99278FEA3900F9D3F", + "CECAAFD2F259CA5C50B482B782DDB677", + "229CD96B0C999665732EFA2BD45A030B", + "66E79464A69B3351B2F71379C54900FC", + "F29615323319204427A8A590D4C67CBA", + "EEA18EB459F9CA21D694EFC95D280DDD", + "12FE1201866E31F2D632C4F3E5C6A552", + "0247E89D08D63B450A276C1743FF22EC", + "4904C6C2F8F2F4959410E965509B0651", + "F524D2F3F3BFD6B5D2B70DECD0582663", + "608B5FB0BE6DEA93BDD1FD8F5C717F18", + "7B2AF9581956EEC4949A21AAF216A004", + "5A200C5FF93144C7F1B0353B7BF069DC", + "0D7F4C64D0C468387CA33D48775FE741", + "315FF370A7012471DC8AC066464CD268", + "347C16F6C4D721A260CC5C00715593BB", + "4AAB48812BEED3693BD39ADABFECEB6D", + "132C92179037AF5AC7563E104704E39B", + "CF86CA02A41F606FB6F829C514BA8C91", + "F5C652FA50777FD029275BC2B89F6997", + "D7F562B8E59B91C95A4CAB58ED0D921B", + "60D1E1CA73F8132EFF3210A24786B94C", + "C7AFED04538964ECCEDF7FF44AB19197", + "FA638BD56696DBC98E798260C40D61F8", + "B93677F7BB69E94D6631AA2EAC467E78", + "C27BE31FF39FBA449EB8E7B5CD566D19", + "B0A786E76D1AAA8E056F6E2539306C88", + "C3EF815E93CA359A0734FDDEF22C1C32", + "2FBAF8F5B2F3D459D87221F2075F2961", + "FC20AC3EF76E1A395250F8BB1A5236A7", + "1C02A272D62A6FF8EF412126CBB482BD", + "4F290C344902C84169E1C9397CDA3BA1", + "DF5F94B3C89350FD997D960A283811BA", + "2A551CFA4BACB794BEB37D972633FE61", + "2003C5629698AFC238127C4C27A8053E", + "8A96122281FA6CAF8E697E6727DC6623", + "67120BA82722F385332B510570B95372", + "D311A05DC5DC16046FF3B853FAF78482", + "3B3AFF7791E5AD4FD00CD1F3C34A044D", + "ABF50588B56D99A39CF5E72B60A615CC", + "2A6B4DD4173C1E20B1B909FEF4E70EBB", + "4FD8CD73AC418EC09DA7670A68660EC1", + "FB81B687871723DB3468FC1D926A8E30", + "25CF41B895DFA5FC37F0A6F4CA65E1DF", + "B823CE84ED836C99AB490BF334931234", + "22FFA92F988BF697A0F4EAA587D6D2CF", + "E24668676723FC64AFFF169D2001199C", + "35B1AD8B7598328F07F082D3C58F2BAF", + "508279DB6CB14E38B9D6125DEF5E5376", + "FA9BE427CDC898993CC625B9B7F0696D", + "B6F5D85111C28D84F1817490DFF6C36B", + "90C105EDD3D6378E686F7E244FC9B633", + "144D2B0F500C27B7EC2CD12D91596F37", + ], + }, + // K No.006 + KeySet { + key: "FFEEDDCCBBAA99887766554433221100", + ciphertexts: [ + "E56569E065F2EE26EE7A7B9F81DF2D1A", + "D257F745044E0557AB89EDF36BCD3186", + "AAF9F7F28068A1757FFB9D911B697895", + "516D1CD4BFF2CEC1CE893BB63B71B834", + "A5DA8935AE828B9012AD5A5A755BE1F9", + "B2C8917071492D1BD2D4185DCA7F115C", + "EB71EB1635728A01BEB0F6D7E7EC2847", + "7FF6DAB2B0EF514F9EECAA3D8ED16159", + "EB9FDC814A1A32A1F418182D839E0E77", + "AB8D04AC12BD47ACBA04B85F7ACACD4B", + "ED30E4A100DE3FCAB8D8D6CC0DEFFEDF", + "73B9468A19D435BFEF317C55B8318F3E", + "42EA11BF6221C9D6B8A4BAAE1381B1FC", + "8B19CBBE6399DCC9C18AB1CBC0ADCA80", + "23985B749752B83528971D4D95FDABC9", + "F9DD4501ED9B7BA1F34EEF7D1DE1D933", + "A671193006F062AE6A5029149ACC18F7", + "39F12BE7026F3F51E81852C12B3340E8", + "D426E30DBBD8609890D14744E7157709", + "FAD22EDFE9579C89E22B1EE7C5302CC4", + "D227C4A18392608BC64C60E72BB603B3", + "011E4AF96A52EA23F575BCBCA6F7295B", + "F2BC07CF81555ECBA810D3A73E16FD01", + "D56D7047BD8D6352F971D71F888A2AC3", + "11E72EA26807E50BEA269DCBCFAF81BE", + "C29B8CD27C94E79D72FBC17FC034EBE9", + "58C83C6A994782A11D2AF27E3F880A6A", + "936AE7E510A72C285432899BA93B2C42", + "CAEA575649415DF419D310AA3EA80ED4", + "51416A9F48E4BF966314C12CF1CB2D38", + "1717AE3A9A5D5E58EBED1FF6E4BD3E56", + "0E5F370987DA53066663054D81A89ABA", + "3D6FB533E1F40CB40D92968B3BF1F391", + "6AAF80FF70D62F97E9A1BEB951BEF0D5", + "3A39224B5F23E6F5F3B16A6AC0EDE03F", + "054902C3BCF7B33663C1BD629BCBDC6A", + "041D671543CB0742BA2043877446B710", + "290B505205B2BEFF20D9B978BF5E2E86", + "D8C6034B7D1449FE7D9E4DBDE8538938", + "3026178ABE26F7B1838EA548487CF8CC", + "4FEE2D921461E913446630CD5E800C93", + "EBA43B35585CD57E1DC33F806657D7A7", + "E85D1B39DD67348C9C9DDAB61B5B752A", + "5422463FAEE8E63B194707319EFCDE19", + "5F855F6EFC837761F0210779C83DFB31", + "39E0E1F9ACEADE7E4D5A0958CA9BFBB5", + "E1BEFBA1B1E64DF33A9D3D7528B65C96", + "ACE778299249DA559406A5BC1633C49D", + "ED3E67739425F9D7A0B647BC47D89FDB", + "EFE29B814DF0E8E4C439746B7FF65577", + "7542D6914F9EBF7FFAA9FFC370B87B1E", + "7570CE3B42EE60FF2604EC65BC7F40A6", + "F416B6B2D64B4DEE07C8A43C61E3BBEA", + "3A431AD5D18B8EF303CD6049C7158DD4", + "197D3178BB9ABDBC30384D2D2646F94C", + "32BA27E8B9C4722FC5864627D04EBCE2", + "A567D0E5B6AD35A7BFB3F7BA25188D66", + "3897A06DB4896E348450B9884E834CA4", + "8275DA403015836DC6AE206022A0BC0B", + "55B479CB55D77F653CEBCBF880EDB001", + "A638B64168057B280E664CCB9C495337", + "37D38DB65FBB5442330EBFF5B6B07CB0", + "734709EB8F54DE30DAE2B127C8E12089", + "305AE49362C58F2F9DF4B23405231E6D", + "235E54E1318232D0E763289F5FC7BFA4", + "50CD373BFFFF3E678E7ABAE35A7D78B4", + "2E826A745E54844B232B53028868B41B", + "52A5E37160DB46209263A5C0215E1FA9", + "5C762863AF79596BA2E693E2B4C4462E", + "6494976C4062FD9A5CDD55E2F5428671", + "788C50FCAC501970943417BB084F4BD3", + "E1A8AF33414E2C6D42B725B7CE1A1DEB", + "DD0E8D98CA0C49C16C11D42DF3E92A76", + "3E22E6AD36E38140AF433B0728C9D293", + "86536843618A2FAD02215E056C7E0792", + "3960590C63C122CFE0557A0D676FFB8D", + "8814EB58A9A709D8E476EE3C5A192D7F", + "8965E29AD9B158AD58F69C924BAE5043", + "F3A3D167014606A4F09FF90C2DA0C343", + "AF77A9658715DFC9E3659C9DF1667DB1", + "BFF7BE07F51BDACA3A719CCAA58F8DAA", + "F0A8ACAC68B62163F4EC9BCAB52BF672", + "CFC21AA75C4491A1FDE0555D049CE707", + "1FE207E1C2F91CEAF069D48A8765A89F", + "AFFC751CE474261A717270DC90319E3E", + "46E8CE7B11E4DCADA71036B2A168DE96", + "9874C5A6285790874361BAE2A9DA53E7", + "C6B0D442EF7363E83F7614E128666D33", + "CCDFC0422D5E740EEF9B7877633AC984", + "97340CD1BB8E091E5053974ED7B93823", + "721B5C56D58CDF243B06BEFA913A5F64", + "E38EADC0A0C52EDF0A2A6AA7A81BF4F3", + "0F743C7AE407CCB0B6A7468BEEA680A0", + "125DC042741499D4E88024DD6D64B286", + "FDECCE97EC6FB4D3CEF1B771BCB84D20", + "F5141B5EA3ADF8C3B2C089C74E4CF3E7", + "9718E4F46704A53CBF2A88150F635FDE", + "D1DE5B02804DA4B98DB81BD900CF98D8", + "DF03F105E7ABFDC69182017486ECA802", + "5E50886845589B6F1934781A0946DA2E", + "04A0915A1C1FCAB38D8D81AAFBA1C71D", + "EF3530B5731E9F68A08434996B0B1BCA", + "49D3587CC81C85BFFDA267D653B8CF3C", + "F1D6C9F3FB41AA8FD634A5FBB505768E", + "ED03F6FFAA84CF764F38685261EF399B", + "8E3044C234936AEEA1CDB5BAFBADED7C", + "DEB184569149074D6E8B1A66B578029B", + "24A0754F5F9805BC6C4CB0A4FC83C864", + "7C1FB36CF79D025694725C2AB1C04883", + "4B7B3905E857C7CEA4BBD3E221196AEC", + "7387806AEC2EF1354D59ACFD8B54501E", + "BA86F6C1F10A6FDED84FC18280A62B32", + "CD7EE5437F838C281E3846F0DD6FAEE8", + "AE0EADC234BE1BC3A326A684400A4213", + "74C6FF0309B9EA2FF6643680063B08F7", + "116070B7A1C6FE2825CC0E84577BBF47", + "1E9054BA891DD192D4F1B2E3E3D148D9", + "7EAF3B7C81E6278222CE79DBA7062404", + "FE13E0CD65C0B249AB95AB7B346FB542", + "DBB8BDC1481F8F7FB0C0D04F25784380", + "9B891DCB6BCC494BF3B4CC839C4AEAAE", + "1317EE5E6BA99C6AA30A6930A33B6AB8", + "4353B1CF578941E939CBD9ED7167D899", + "6808A6E1BDDB8B05DE95AE46024EA035", + "66A69680EF22B50C229E2B2E220F1EF3", + "E34C20E81ECC3A037C1CF8C31BF2F1C9", + "04A003F877E995EF87CA3FE74AE1068A", + "182B6C357B6B5B1C78B05C0C7CCE90DF", + ], + }, + // K No.007 + KeySet { + key: "0123456789ABCDEFFEDCBA9876543210", + ciphertexts: [ + "44B9CE77671EA269900767F6DD5A7845", + "A50106522C01E1DFE687CB9EABC55894", + "EFAA0EE4981BB6E52438EAF66BE8569A", + "995F077D08F15A67D03930F10C2429B2", + "34469D65BCBDAE1C7CEFE9B8D465A2BC", + "F48E6EBA58BF967A9C7CE8C703BA1293", + "99E190DF46533DA17F078262E8DFE03E", + "2F5031FD89D499459D34D1E11FB7981F", + "F89A84502CBCDB987E0FED52F0451046", + "4CE06DF31088525DDE71A23846CAA32A", + "85548A2BD5BF416D12456E0F82C44FFE", + "2B82113C5F2ED7F0BD5C239FCA9B8854", + "507079B3C94D49F1341DBC423EF525C5", + "FA00C17D0983CDE5CF72C5669C73E085", + "E8C2E54F5543C4EF83BCEB3A4D41924F", + "A4FAA3CFFD08C22D175CD3CA71C6DDF2", + "771F20DB81F3293BD4C22CD269FA0B5A", + "A6037B31B09E61926998A3B8126B3898", + "50DED5C807E4EABF1C5377D5A59CEF51", + "E775FD5B7D97A9D648612B90C70721BF", + "DF2BD86667B19AE862FA7C595177D5FD", + "2C84256934EFA0AC9511F260038121D4", + "2D9D1978C18C596C2E1E93167822C726", + "1E2933BA29DE0863E2DFDCDD27C0B5B2", + "70955DB119D4BBDC65C51391BCF680FF", + "5E844E0113351D90A96D57F357179050", + "7BDB9D3F2C97AA317D7B9FAC1ED210CD", + "A789C809980682945352C3A611B6841F", + "25B695F2482D36C49C67222D71AC238D", + "F9C8D1A3BFF10F59C78B2E0375515B47", + "05758C2348913E7955BDAEE71E053C02", + "9D910C50CF59D80300AA19062B60E54E", + "5BB343224EB9E419C7062EE6FA520EDB", + "4AE09F411CBF4D224FE0472825E4F293", + "560438DA3371D0E04F25F6B64157FCF4", + "223EC674357F99043C14133B28174395", + "F5276B92B6EAD7E3D1413332F8CF6FD7", + "C67FD769C0FE701E66FA1AEC20707F3A", + "2E2AA05A95DF7DBBDF871A290316FBE7", + "1D6BA9EA48886D5E64359EC7FB502121", + "D0AEAF0D8D508BDB9CDEC0C378540669", + "86903D7AAFBE36622B2461FEE8C74986", + "F119931FDA08BA2B1BC47908D19C01CB", + "4387EFF649699EFD11F13B6BD7BEBE01", + "AD7BAB1833B01D7197C63F01A4D2908A", + "0B853F27C22194E0AD8DBFA9AB5C463F", + "E2722B90D59213AFAB999715F7A6F5E6", + "B256415B20F7F6175F7842F9B152D6F9", + "7FCD7DD74C0BA91A7D84C8DD4EEF3767", + "417AB4CF3C7AE402571C336A268CD1FC", + "59C64FCDF6033DAC10C49E739AC6399D", + "730098FE9788FE7EE108E276FF3DDFA5", + "2C6FB84CA141DED46C2579F32B876A35", + "08312A5A162E126DC1F56B40AA454ED7", + "E4DE4908E679258EE4B3ACC13F680C5F", + "F3D032392A72F8D7355816E0B0FF4ED9", + "242C0987898CBC79B1259D6E14011246", + "8E5EC3FF0EE87D9C229A544970A21895", + "B6FAFDC5DB9D55407518050ADAE47BEB", + "1EBC34F9F74B1B6E557E0E69DE1A3C8B", + "FC4BCFC02A590A05D0F62EF14334359D", + "4C8D49ADF43D23679B094E7D47DDCAF3", + "9A049FC744036BE2E00E08C5692A669E", + "4317BC709A0ECD97ECCD1FB8195E2C50", + "5E3E33778F1BF868515CCB10423CB136", + "28CBCD07341A80719DFB7CFFE81216C6", + "1734FBC74ADCA6A44833573DFA4ACB08", + "34D2C3F941C59082E49DA60C86A885CE", + "E65E20949149778663CF7BB7273DFE16", + "212B778CE6D41CF2C7F7306D76D80A79", + "5864B7BAA52296B4C34D43E117779B3E", + "5290CFF50993E8A946985B85C22DAC08", + "9A154CEAE164945B55E83208243E4858", + "0251BD1AD9CD6CFA0FA930A9F8E46391", + "0C55AE0AE34F505103C463F3FEEEF901", + "996F3B69C034DBC13433AB53300F41B8", + "4E330FF3D6A42840FE24C68BA5CF589D", + "FB9AC208A2992DC9A70C109BC3D228DB", + "761002D1F2242E24EB3309311FD57C45", + "4840AE72E3CFD077A1491FD3053DFE0F", + "C76C16CE0DA57ECB2A0FFE7F2E8D3A19", + "57638711F383B2CE5AE0E3E4E178CC78", + "467B91F8E5CFDD6722D783CDA1D756AF", + "FD375C1A532DAAA663863E5DA6EB177A", + "C03E848508ABF78FFA72FF36261592F5", + "FAB141D22C792E4B5704B60D3F4E84EA", + "947AE9F8B97FCC90A6E440DB16C43A26", + "4749148825B65CB23891E191762BB276", + "08C5723DFF19ECF05A07A666B481D3DD", + "1855C59246B6C4837FC2998E9353EBDE", + "92C46302093EDCDD899A65EFA2867BFF", + "E9AC5AD36A459EF8BBFA24A9B1AFEF05", + "4DD445815C9268E283358B6EC382211C", + "E284A8D6C3474D807645F6278B260364", + "51FF823CE16BDE24C0A088A08FC39CA9", + "38CB7C3AE85FC3F182A1DF1FC407D5E1", + "D12D388BBB106629D51591BB1A0FC486", + "3535A40699806E97A6AA9DBE0A9329CF", + "DDCC14ED654CF05CC5F2D940F07D3A56", + "1F611071825BEDDC1C7FA8B081533F81", + "FE37CF462779906A2DA94B2DE661948B", + "9E88826B5D26BF4EFF10D83580B2EE3F", + "32FD15A9C508E3946A483E64691432D3", + "8B5FF25AFBD836961C38D0C8F24314E9", + "7BF2CEC1867C0BBED697B2D5E6C076A0", + "35F6DF9DB6ACEC3F00C6557D876796D1", + "5EA461EAEFFF9F5A28DF14D301FA09CB", + "D64C5F51C9725918C9D944543091F250", + "2EC57A892DA49C2486115B54261ECF40", + "29BD60DCEFA4682C9E995E5022E4CD98", + "A79289719D9BBB70259D14B5D8BE3D17", + "9D5E746FC09AD39531288B3510540CC4", + "9D58900D7368A3C1F33A1B8814967E40", + "6DFBAEF3950F257796498778F544A67E", + "87293CCA19E40F9F9CCBDC69E8852FFF", + "2EF2A6569316704AB99B46979406CCE7", + "66153D27A02DE1A9E4C88EC7D2F0FE09", + "CFBA7E2462B4DF5DA372CB31C426DEEE", + "D41B812D44470B1F5022369956ECDBB5", + "8FE50F64EEC530A12E751E7A0BFBB77D", + "C61BC4866792478C0A09397BF76F03A8", + "7D3B9515DC52BAA4985C12BBE554EB89", + "2AD2CA0B32573B8111F962E2F6BE269F", + "A32F79FF8597FDAB806332D6C021F1B0", + "1A5C99894F5C194BA2F02A0FDF9A70B0", + "9560FB1E4C28D420C8231CA4CEE54AF6", + "798828D637EABF1461672A1AD87A3205", + "28BDD24D5216811C3C897F5D3E15AC62", + ], + }, + // K No.008 + KeySet { + key: "FEDCBA98765432100123456789ABCDEF", + ciphertexts: [ + "7A8924FF8E5C6724A353CD8C0852BA09", + "F76E4C725DBE6994F078066A25957C8A", + "E1DBF8E024BA9865F82B01D2DF0A2613", + "E1D257A09A51EA6F7A9DED71EDD2FDFF", + "0793EC272F9CC3FA45CFCA59648831CD", + "09AFC466FF4C08244CA26B1138D221F2", + "310F3EEE24AAFE216B68D850338B2899", + "4C0FE6D6455EF5856324E4CF992072F6", + "30592DBACD16A479A4FFE6FFB8EA7DE2", + "A3ED084835B94E228CF028561BFE73B8", + "6789E24800A9944A471B712576968D34", + "A6B1159F56DBC55B21EC320BFCF7A7F2", + "281E7C5C325EF7A0D8C60ECD6EDB08A2", + "338D8024CBE11CF92C43497D677BE969", + "C745781EA69B3E14B4AD503BDCD3BBC8", + "AFE286B6CFFCF3FF638A9941AF6118E8", + "C0A8204CD40389B54FF123FA4B7D5A41", + "6288656A1ADA2BC1D8245518A16010C2", + "21D1F42DC6BAEDD64EA194C8BD2CCD46", + "BB68469E134782E9255CC965F03852C1", + "CA5790AD47200912F526282F54B21E45", + "C2447985F66FF731D20343D99742ECD5", + "727DF16FA10CB937B9067E29CBCB4AD0", + "E5132C0D38083F028D2114A81357C521", + "B83C045C606D1E8FE9703BAC48352151", + "DB8040998582D778F47020BF22AE7623", + "A43D0293C7A81BD8212B7EEACD99272D", + "4ED36027D2405FA89559E670ECE8A32A", + "71E7E01F2CD85145CDC4E69E0BB346C2", + "2634B8AD2DE72EF4EB87AC080E910656", + "262D07CA510CF498A3DBAB2832CB3219", + "55FDAC8169B2E8820831674836F1C01C", + "2E3E20612DE81AE132933B8D98B969A9", + "A4E7034CD476913DF994E7D70D34047A", + "8E0C1E55E4C883FC5D0D983F842DC022", + "242F48C41019FCE463A6823E61E7D2B0", + "75A177FAD9603E6AA9A72980DB591642", + "EDC301FE4F77DC90319DC6770728E992", + "6044CF7EB36F2CC3143A73B16F1389CE", + "8713137CB6637A66F5B76013B9FC2C8D", + "E14D52978D4BC5856D5795CD2022C37B", + "3659348F0CE616FAB952EEA1E503061E", + "C6B18C2319E901876A281220C5FDCB25", + "D7AC6389A61B5764590C2498A44434F3", + "2E3D4CF045DA68A95D7F4D41745F7EB2", + "BBD9EFA5E99549DB22B8BEBB69CBFAE1", + "806E7B7281B9CA2EF40B126900EA4EDC", + "16C84F2DBA0A1BD4C44B9B27B6A37CE9", + "9E3696DAFF66635ED96927F665FCACA9", + "735565EE86949DB15B1D17644658C349", + "98413E3816B6897828BCAD2F8C8006B0", + "7822708A880C1CE0066A26C4114CDEFD", + "FAD2AFB35AF12E693ECC0F28015748F3", + "A659A839883D96E6947ADD393395DB63", + "F2DA97CB0EF50E574A214465BA3CE117", + "E16183EC5CD0E7D839CEAD9776E55D52", + "6912215A1C8C5F2AADD22FACE59001CE", + "A2EECF7244AB03F9F06494CD93BF7A02", + "7AD6D5A3A3E2CFE9F0BAEEC4ADED74E7", + "CF9826CA7649D02206870BDED402516B", + "DED1126B2339254D293CD03C5A8A4619", + "50EBA9F52EE6AD1BAB580A187875B875", + "1CD4C1EC526C0475AA96799EFA120565", + "34784B38817219DD08FCA27EE7D0E320", + "9A48DEC1C7F720FBBC79714E449CACBE", + "78560476858D442EDF4D3E2677163E74", + "613776B942BC0956C64FC15B9D51B321", + "A4FA18F012F21B4B23195985131DB37A", + "C75281B112F4FC9FB06C4188BEC4F86F", + "993F8B9366BC945C966A9CCB81C15CE7", + "66405B8290D11AC93F7F49B0ADB76773", + "3BBB720BF91CFFF59F6855A0F4293866", + "7F7A0BC2CD57BA6609141311F55B7BFA", + "85D00C985FD61A7D0FCC95C7FB742370", + "4502BFC5669021DB68E28B599633E123", + "5B0B83CF1A234F4EA0D4672A14D40735", + "3419EE59BD3084FCD6311C23A2C7B4CE", + "6BFD2830810095DF24EA48BAC2FFC1B6", + "C9598A6B3369B8D9E08C61EBD159544F", + "93EDFF29CE96ABC949B296759430DB12", + "667E607F7FA771AAA55CBBFEDD0E2BE5", + "8E9A5E31AD7D3161BBA2F8145D56724B", + "668A318C11EE000BBAE8625E0440FA15", + "DDB3805FDC98A2A6484EC4FECE5A540B", + "F48A7330217EE33EE7CDA23DFB7408B9", + "E4053BAE41A15786D87CD100267AC7EA", + "804343A3A566DA973B4625147D1215ED", + "8EF727AE7FD9E94D5945C83E48C5AF8F", + "B36138AB41B73BC43559BC0517F87DAA", + "5ECF1C83A9F82973D6B5FD767A701FCC", + "019E2024AC9B0F80CAA6B7376C981339", + "0F8C1F804F5322B3FA75436F212C5C8A", + "CAEEC5993E100114C03D8E2ECC6A4BE5", + "BD8D8748D00B308DB7A2A6B938C2E036", + "E75B5D4FD57598FA443630979411F9E8", + "5546039D6AEF14300920A7A05136AD03", + "105E9BC36762E67F793B2BE90EC8C247", + "D5358BE399295137DE27B2B70C80AF9A", + "58F9A4EE38934C134A8268664205BB1D", + "5E50AF2EC1BDEE8283BB61BF651BF7F2", + "B29DADE5CB85EB80980B361F838F34CE", + "0F2042C03EA9651ABE7DD018619C0331", + "103C86C707F67A9F074FE88D4FC5930E", + "8B425AA516D470B812EBA984E24043CB", + "54DCCE609207C8150129894CD350EA88", + "315EC1CB417D5D15CC7A7B8E057796F3", + "3F32FE75DD437A617EAB1A3CB29B527F", + "C001D7EC01846A3436D5C270E98A15AC", + "7F23590498F52F5B1DF1018903234D93", + "E9F1FEB03648C01C0F3BBD8749094395", + "2757C00EB9ED1CAA4BF64F7E23FFFB1E", + "152814247FE6E119B480D3435EDD5C0D", + "4D73D3048D85C10557DD0170D910F393", + "9D031BC46ACDD2FBB009C2D2AF06D66A", + "7DC1AA8EB13C4130F7F63CFDEAA0A670", + "0273C4BB91B26BCF3B2D211C00490EA3", + "A13CDE3EB8560A65CE9CD5D14E5C81F8", + "9DF76917B2426632F255310E56BA9BAB", + "27E474AF0ADCF8DD346298EA6A753608", + "98064192EDB47CE905CACD14FC99A4E7", + "BE7BD47D42F418EB1EE5FAA6E64D7B11", + "ED193DA4D48AD128E78EDE5A6B9F11D9", + "2351A1F2995F8E1BA7907484BB469BEF", + "75682AF1DD562F26C04873A82064E881", + "DD42E5819DDF98A4D5000046240270F5", + "CAA860D64F5A06D7C05B63FE52433E56", + "42A52AAEA0A072FDFE4E3345544EAAB6", + "D24D56572FD7F13A13991FA09678CAC7", + ], + }, + // K No.009 + KeySet { + key: "1032547698BADCFEEFCDAB8967452301", + ciphertexts: [ + "09F79A7349A335C76478C4BEBC7A8474", + "91B4F6C3D6AD4DF3C06EE5166E934F8C", + "C6AD780D7CF9A92C3C0B63D9A8220F02", + "410C2669B77BFC9F299EDA8F0D43828A", + "23BC29448C801B37E942370A7B2F57AD", + "11C5ADE7E0A612AD0E86993DE573434F", + "2285C3BFE16476A8C6AE6F0695CFD904", + "876EEEAFF7B6755E289D56272FB355EB", + "18DB948368BF0DBE0A165AEB3385521A", + "82EAD093129D671464DB723CFD0BA630", + "F65C4C65855899DBC9DD0E2290360598", + "740836D7E7366219E22DB0DC7CD10DC9", + "5EF783536693ABB07FABA4CD6C96478A", + "C1AD7FBC8FD7C301062243C900974E77", + "C3F7249D0653104930041AAA2E13E289", + "A9D88D86829F9BEBFE965B926348B736", + "5885A032F1DAEA79F94C4EAE296D1F02", + "A7DD3876DF759668240D14CDB3885892", + "6814547D8604DE0C4C61C996D5F58EA0", + "586BA78E7735AF497D95709517EC2C8B", + "7731B553F30C3200123436BEFA4A5ACA", + "C41A02340F7C17829F88E3979938D95D", + "161C8113A8AB09472E7DD954B1248004", + "B14CA8EA2B18F5FCC1E927EE392E2B39", + "381695078763B837606472A30B77519A", + "F227A42F4A650B53E46C942F20DFE494", + "D5368ED795087C2419A623C2E6A5EC52", + "7A51EC7B391C667E9E34A478694F16EA", + "9044482C34BB5411B078D7A842FBC18D", + "C546991CA90CA1A436FCFF2C6DB8E6D4", + "BCD06AF8F173C1BD40F79062C4767F04", + "2E1C91A7A4E046CD61FACDC5D060D4E9", + "1D0259DADCCF707F06DBF94ECF887D76", + "CADA2A396EA4A180251353992D1406F1", + "A1731DF614BCB95ED05B0716558D4DA5", + "DD73005D887B92E6830BCDF5DAA28D46", + "E140AD433CF5E414C4EACE74E05D45F4", + "1D9B8ADEF18713948170F12549AD7790", + "4407B961076A14EDACBEAABD35DB202E", + "112BABFFCFBE466C6D2CBFAEC1C92914", + "42997999A45AAC84A99C1EA672236A0D", + "39B18287117B944F8A1FFE85CFD839B0", + "0DDAAE33B9BE004046BE3778060CA510", + "0870BCFC32E4EC732C1DA5E700CC261A", + "C82A3AC3DF1B713CE689036D0784D528", + "20962F01289BCD282B3F3993753BE867", + "57CF977860E6CD8828F993CAADF81672", + "FEFE893BF34D4902AF950AECABF9982B", + "3C2EFA5AAAD90514EE2E0989B452AC7C", + "D45E9C913ACCE27AD8680B033911321B", + "0CBB77663379B26DAF04E7A3DAAF5F4F", + "637657BE860A39A5C3C9A6F9664500BE", + "C88EDAA3337402DD39DCFF1987D0BE94", + "BD0BDE6EB23D5D1C4732D38EED167DC2", + "41EF05CE5110AECF105A85D6B377D76C", + "0B3283358E92989F27C6E12887451579", + "967303666B0D70383EE6D761B4297A69", + "162F31462A389AE798677860EBBB3DA6", + "3F27B55700689A0AE1F5456AE1FDD35E", + "043070DA7E1AD0F2DC0C9C67C64C2716", + "88B74F4B6EFCEBA7D34F9F19C4787A8F", + "7E519C5922B8CCB386BFC5DB7DAA03BF", + "0D17C2684C1D176FFDF29FA6E59292FF", + "6434E88309C0B930933747224D31AD34", + "0CB339C20140FD360897D7445A11124F", + "97898B7EB5F4B6FB4F7A48BC8CDE9F5E", + "E917BEB73600398FCF4DE3C25CF6598C", + "13DA443B6825A15881C49939A94DC11B", + "E922D87055CED3949FE705C9CB5A92CF", + "EA231B0071B559C26A3E5DA334008B5C", + "9EAF5AC5CB8EEA4A18DA682CDA5E0E55", + "F63EA5A489A1AEA166B3C0A77DE0735E", + "7C842F10A335DF2DD4FD390283F54CCB", + "658948C88F7EA007554E334E807683AC", + "59ACD6F252D9E388FB9458FAE8FF1687", + "4D6192E23E8EE37D2B02C2345214CF8F", + "AC55E3739B9F3AB05D4D31F57150CAA3", + "C12EC50BF8571C5E2D92DEEB33A4AB68", + "9C6FE80298E63BAC7E64E78F36780D79", + "8D7A1021C49A707881141BCD70492328", + "FB6260E2EF65DC5443C7EFAA3107346A", + "F5E2F98272CD078E7BE0333498608E20", + "7749E8B03B39BD1C052263AE891A15B9", + "585271F704AF766024ED3E1A07B1E88B", + "C521AE32055B7E07D8749F20A57F1BB5", + "0F59DB65AC3016F70E03C2CB732164A8", + "B2B4883075C122BAA0011FE54E2CFB9A", + "B3989C18BC59146C5E5F0C6C5BAE6746", + "BD490EB7CFE0394A66F3A0DDE957C801", + "4B9301EB3783D3917C6C960226DB984C", + "AAF6EB36D3779EC95B6E8B1471E7255B", + "DFE008D242DE8B948B047E36297D062F", + "9258F4B6825526EDD8C6693A2D4DA00E", + "D4BF35BB718BF5D63B1E892BF30363C0", + "3CEF1C8AD29DC31EA5497BB9A607508A", + "E7940B4921657E389B1E7EC63B752E84", + "36A446481C65E283C15A1D17A54F2EF3", + "2F31127E45D2FF967F1ACA7BB636E104", + "F245AB909B44D59F01CFCFCAD7D83FE1", + "EAD9E5178AF95D0EA1B797161146735D", + "59665A381CC39BA862402865E4164A87", + "3EB03C38E15592D898CED7CD9C92EA75", + "E0F4F8FD2C5AAAEC1B5D02CEFB791C6A", + "4EF0221F0118B920A0F10D7EDD13846A", + "A3786CF30B814979B06423D4D264E8F9", + "8C18EA552678D3FF986C3E3FA8BD538E", + "BDDDCB2ED6B3E9F244348F733CAED45F", + "883E679BBF79827A8DCE0A384C84D1D7", + "40F6AECDDF159057AB97BF09922CA1C1", + "3FB75BD6A4FF24CBDB21CD6225052396", + "0654640579EB2434CDCAEB8C91148546", + "A54872BC94721A2318EE9BBEC3558B82", + "8D6596BFC6F493190698AFFDA1A65C3E", + "AD266E99624389864E6B97CAB0227037", + "BEE010479E4597E61FCF632190C5683C", + "C92295744370AB36934433FF821CC38B", + "656052FEB17927AF8DEFA735CEDBF41F", + "6BBB0AD4D890E8CFEDE8EBC2A7326C42", + "AA32FC6C905D9028B19C352D4710F406", + "612BE102EA1D46A1B5F3CABF0D5A6885", + "71C5A591C479B5D50D3DA1EAB206078B", + "3C656EC3DF9E2384893C0240CB554592", + "C0A771D5290213013B0C9570B30D1C2D", + "A147D0B28475D17AFFA894950A8C0B7A", + "87FAA946B12B557DDC6EDB9C841040DB", + "610121E929C2B9D2FC69C64565406F55", + "D6F22A8CBBFDA9F55CE4868C2D3B7CDE", + "F11943FC43BEC8D7DC4659355A658739", + ], + }, + // K No.010 + KeySet { + key: "EFCDAB89674523011032547698BADCFE", + ciphertexts: [ + "03F92E647B50C5F2B5FA558E41EEB1EA", + "B05DC698A53B0BFED38AAA53E84ED7A3", + "6E7F99F8EB5D0C32385FD44B7C0FF132", + "D7353AA7E4E8533B8B0780A0022E2AE0", + "887628AD6706BB95111C17884702EFAB", + "E30CFA8A5FFA24583C45AB3FECFDD252", + "3966607C0D755CB16508DAABFCFB4B57", + "1C42954F86E6748556C128947286B6C3", + "804CD70F94BA669497BB7DFBA738D949", + "4A61C824A6D49DBCB2C505292BBB2574", + "8D2D9486E4EA301B159185BB40B0926C", + "B042E418B7E135E17B659ADFC8046DE0", + "D94118A33B440BD1CD11D58B12FD90D2", + "3E697BD8DDE93E08AB720FBC16164130", + "95F2AD88A82F5336B884FE0AB0001FEC", + "55404D36B9F10845D834490770EF8718", + "D9A45CBF86E307F7FB1C08AF5E846B9E", + "0FB3FBA6D38F33AD56B8B5D589433F3F", + "D25AF3E824D5CE08BAF82370E6176965", + "42350D3DBDC0D2D019A16A5B678941D6", + "40CC2D1749BEC84D67B0D86529D6BA26", + "33BD9FA9B358E8CC26E5D0B80AF590A3", + "632C1DDC9924081B6ECC85BAD2837B55", + "02846FE69CD706A408A7E6ABC992ED67", + "15C2D74CBD88A11587D7164379C6AE51", + "AD870B82E5C0072E92FDB0340F4EB7F5", + "C9D8904F1C9A439E26AA77B97D53AB9B", + "66A44BC0499626538739DBE500C4AD51", + "1F156792E40C7978F9B45E2160065DE1", + "DE93BACE8E9C0D7CEBD7C45F7779BB2A", + "AC8575EBCDA6F7402F597AB88E17BB55", + "2E4A703CCE5E513E474892B62F6112A2", + "6B1A09A8267905FDA9B2B2C79BFE69BB", + "70AE6AFC4C2F93BC88AFF97982BEA4A9", + "9CC7B5AC2E914000C401EB6AE394489F", + "7CEDE8BCCACC26B1B7F5BD8E0E8FF8F8", + "28C92FBF2B6520992FC4E763C6D42C0B", + "27102AD8D22AD7109BFDF33196EAF04A", + "90342F5DBE15EAA6157F541A9ED3AFCC", + "62289B28F2BAF83A0B53CE07A0E4D8DC", + "CAE32BA73759B75D08DE5F0517086FDB", + "F3340ABEBEAD9A56F73A0FE27A1EB690", + "6616AA99731E5A65268CD427719E7C40", + "CB4291AE95000E368076E23BF37BCC21", + "924F9438F25C9EB9E1B57134DA61221F", + "DD98A3B0E9A963B75B1D47B404FA1A79", + "14E2E980EC9546F5EE617A79DFBCB5D1", + "C0782F1CA72458A551B7ED40FBE9A9E6", + "24A73707C046C3D8F8F1677277C68C00", + "81503FA70CC247E844458D7348528929", + "FEB924774B78BAB4F3C47D1FCBB93D96", + "21238791B1909298F2241F5BFE4662D1", + "9FCD5E130E26B451F83B60C76A68908E", + "F34AC9F17A4CBB0FF7E035590BA8C693", + "A4730D8B8D83476AAD87208976582840", + "F79BA0C139558363E6265E81DC53E73B", + "5A190578F52C682F442FBD97F62FDCE3", + "D6C7FD95B934F71D53AF6E2522357B2D", + "9E3F6CE85770D925963F77BB23A6F841", + "50D6F00BEEDFC2F51351FDF1197555AF", + "C804EA9EA1B8C9A830A46C3C88D80235", + "C8B17BB3750FF0D48C6B6F3BA3C4E3BC", + "0F125846D19E1145E96EA9685FAF9CB0", + "0A0EABDD711A8623BFD9C3E42ACE1C27", + "6A26BE05EFAFBFFB6F00C55AF48A8A76", + "7B5B3E38C394C8769378975A3F009AD2", + "72963BAFB9DE5B4CBE73FC7EF98D5730", + "90B118F8117A4A890107BECC6FEE0164", + "D6D618465EAEE41325F058B5303BCFE6", + "379CF3D26F57B8B4F6750CB582D49CB6", + "97A71C8E155CE1D26A4C75DF55826E18", + "1E0D4411343C9E618C6800AA356AB1AE", + "B0A9CC293AB01444896809A08CD0448D", + "68669D9CD03486C3E69C731D922A781B", + "FBDAF160A20018D6F62AA5F173589CA2", + "44A7663BFE97F95192B3B49CA6CBDD17", + "FAD4E2DB19F45BF9BB02D9C9B9FE7F7C", + "B323FDD2E0CDD187DDF17241EF0A4CF4", + "088DBBA8F886C0E1128C6BD7CA4EDFEB", + "5119770D548F90BFAE381454FD987DDC", + "1F2DA82DA22D55F25FF8D634D2D34B13", + "2648C4AD3299268B1599F6A324631FF8", + "FE955973E2E6717B7033DFDB7737505B", + "1D9A4A5D9C49DDD685FB16F6B0333ED5", + "9FD816020F941AD658341BE093CA29E5", + "BC9D18D40914AA0C3929EE626475ED22", + "A9B7CD1FA523F93D4F490A188A1C9FA1", + "5378FC4F64640507FA8887BD299CC28C", + "7E0BBAAE786975EFBAC85207195A4B90", + "DB9C3B7894F69547C5144DAC4C1E282E", + "B625247B4F02540900BAE22101C002B1", + "07F65B641C58AB92DFC13BCA64DFE201", + "6DF0532E6C707F216FD7755EFB2A621B", + "7C94A92E97E536047BEE1046BA27CB43", + "3024EAA552E3F8386B4E08D2BE93E823", + "9D799945B204F8A0141E3590CA5136DF", + "559DFAE130ED657FE7B42D32955DFAE1", + "20E1B890DE6CA30BD7E85BD037052B96", + "531F5922C19DAEB4731DAC2297987F34", + "E84E631E137D37238A8164F34901EBA6", + "47DFA1678E6887280362FDF8FB9B0B78", + "322293034348E43FF431CA48E819DA96", + "346C0DDE5B08F5F470768A78EDEEEEF8", + "1ACD3F4BB6E8891019658CCD6273D111", + "B7DF11359FF63DDA83D28EB1F7C9ED32", + "60F1BF6BCBD6929D2D491CF2D1B00D4A", + "47F71B3C551C120701E834958A0CAFDB", + "8132FA83AA93E42E3679E4B2758CF425", + "21E25123A8B65BB1FDC6D6286ED2CD68", + "B9247A642C2F0529A32057D03CCF3807", + "6FF29803ED5DF5DC14198291745378A3", + "D9B0B19E8F714A2D6E15A6BEC877957D", + "A6F3415A454F1C0299FB5614D45F8F61", + "30C88425F1A3653ED56BA84A315AA4AC", + "0CA288B02A33E39BBDD98BD1296E1ADB", + "7D8D7E391D241BC9D9E520D9D7D07DD3", + "4A785F04C2F694AFC144F251ACB7E061", + "CC75099A1BF3EF3A2E8BEA3DF1D70AA9", + "93E61F6665859FC36033EF2540664756", + "F5587E5F6B16FF1ED3A05D892373ADBE", + "A73A0EAEE14FC93E0B0C6A67B3CAB309", + "E31740366F83C68D60F52881408A2CF2", + "E5EEAAFDCD80517411991669C44E9AC5", + "FB20BBCF571C00161EA24E9C0B303C20", + "4B7D127A10CF5DC7EB9299A3BB7A5175", + "E774E4D1080E2A1FFA6A94C58864243D", + "68CDF9518875B3CAFA4C2B4B5563059A", + "ADF3B4EB24E3E7064271703FC854F4AF", + ], + }, +]; + +/// `Camellia with 192-bit key`: `K No.001` .. `K No.010`. +pub static CAMELLIA_192: [KeySet; 10] = [ + // K No.001 + KeySet { + key: "000000000000000000000000000000000000000000000000", + ciphertexts: [ + "3EB6CC5618EFC98455B5992050D474E7", + "A2C645044CBC74DE5A4A161C6B2E98B9", + "36A9A8C164BD90D4972AB1BE56C96A0B", + "38965592D728F9B765140C0A36A1BCCD", + "94CDECA78E10827914A49B5AE7F15643", + "11C0DF672B45CDCD311EB86A7560EDA1", + "030CAA9B8DE6F8AB88882F9596D9B1B4", + "FA02C8D1CDDD08B1FE3650DBD8E43C4F", + "10ACEC25736340600D712338357C7FD4", + "BBEF172E9E18679C6546EA2D9357BDD1", + "707CF6F582F5921765DBC6E1C79C45B6", + "3E9206A85F9FE99CD5538FA196E58147", + "6758B118659E9BB40BB7DC8C3D15ECEC", + "9BCA6C88B928C1B0F57F99866583A9BC", + "53D60CF8CA0B41B3991EF892917FA26F", + "49E438685E189FB95791C655FBF40B3B", + "6BFE6661C074077EF95DC499CA30A6B9", + "FE82A6754DD56ACBD1895F8257597B74", + "AF4551CFCEAEF2AEE1933C4AB5F036F5", + "5175E53EA4CA77E085363B2948B77B17", + "19F544B2B2AAE4AF00DE2853F83349A5", + "45A4379AC855738F6FEE3AFFBB2D839F", + "73A390407DD07D4ABEB299A5051A8DD1", + "923B1E3525217E5C7A41CE3BCAE7C083", + "F58098D6E68E975C922B05354C0E2094", + "371631601CE2BED9B7706FA4254BBAE5", + "794F34CD64B44095BAB5C470B36E60BE", + "1A4CE8CBFEDB4F64B1A64D926B9BE3A1", + "11C391C85F8FCF72EB03E1C4CC40B529", + "9D8ADDC48EC36BB449234C7C06BEDC0F", + "952A1FAD7FAEA148FA31B50C244CF5C4", + "613E5E9BBBF1B9943B3B5CBD3E69C98F", + "5ABF9CB600BB50DB64211DE2DEAEEDBA", + "14697658FDA5B1F14C3303F5951CAE70", + "2A29179C05F2F5F5909A34130B92BB25", + "60A9DAB8068CC085F3B9853D0C1FCF07", + "D625356ACCE7B9F874754AE52FD1C7BF", + "31196A29DAA0A41E982819C26AF0567A", + "D1763FC019D77CC930BFF2A56F7C9364", + "BBC9D3C96666B01D0C33CC067ADDA228", + "4FC9284574F433DD6C5ADEAB6DC64A06", + "7176B9E3628380ADDCF02493DB254B01", + "C6B124A17B3AB55A983DC2B6E8253FF1", + "5853A6B6AB0FC47DEBA33526B628DF6E", + "416945C1D1902238C42955CFF166D705", + "2478F40DC7B7FA98E59DA21F1D2140F9", + "6A912316499FBECA17D1683EAF79FDC9", + "8A41DB2271FD345BC1DDE61A427E4E3E", + "B6C62C6A14D2276C8FE8D1062C1E8080", + "D23F90169810210A45BD9B8681B24C34", + "EDB2A77815A074B50D88C6C2B15AF814", + "2D6D81C8FDD2C7D5B98317488846969D", + "92F2805613A82EE25568B32ED7550DCC", + "E321480A1DE5F36040F1FD170F24802B", + "3188FFADE35652067E6E2228130762D6", + "B3A3A43D68A82EC54B5D437346375584", + "023ECF3BD9FEB4891366ABE45EC1728B", + "50D8160676748E1718A030F4F512C1C2", + "30DF20541978D9C96D43D609DEF39C00", + "BA1AA1682750C0CEB2A87E1A46A7CE0E", + "03AC8261D8F98C90B9CE9C9E47A39AA5", + "4C6C2FDC2693F2A43EAEB180AD8190F8", + "B65D2C8CEE12BB4FA127356632CB0ECA", + "6D785867F379BCE03580ED9DE83C0EFD", + "D2B25B3EECB454DCE070D11C408D73B2", + "8035FF5E625955D6328F570D53188C0C", + "A8BECF868B0D964E04012BE5F8121A9C", + "AA76DF2E83C0D31ECFE66A62E16A91D3", + "BAA324177EA5AF61ADBD27F594297278", + "40BBEB33938AFA9BD566991B53B0FDA7", + "6F58204780BEA9102506C477CBB3C8FE", + "D296BCA9261A3410E47FA289BD70B955", + "4C57FB4234A64462C6D441A782723777", + "33478DE51DBDA949E17CB82373DAF866", + "7CC11B9A6A9E2CE13D3596686C624AF0", + "0C55ACA2BDA80E8F84A3879FF077802A", + "885B84843BADC6501CBDCBEA4386AB7F", + "DCF23815FEF1697B0618E205B637648A", + "BF5EBE09157E65743AAD033473B0DFED", + "1E9E5E1032307B75915E9BD48205FEB8", + "0EB8AC09A10303A7CE9762C1B029F0E0", + "2A42627713BFC603A88AD1D66292B80C", + "D7E9512485B9E5E409FB51E26D269795", + "57CC59F8B92D73E1B38EEE405A8EC12F", + "161783F5FFC9A383E36B80A2032A71F1", + "F5B24CE20FFD8702AC63F9C844BC5730", + "440930601D4013076587D882A1958280", + "AEA4C3F9E520651C5FE38B915423843F", + "E300D7417C4F547DBCD5FC84E3833A7B", + "5543860CE9247B38E8D0E7B216C0B5A5", + "C20449053BF90C899899EE02794DB3C5", + "AC0CB3B34AC32244CF196AE49E94D380", + "0CDF3F25852287E3BAFAF490DE18D125", + "583BB44512CE75268F72E6BC6682901B", + "217140522F0C505FDAC4BFDE6E9D9A81", + "CFA59EB13DDD780A2EAEF89E83737C9A", + "75E473CCD4D116426753B44900D919A6", + "E15E4627F7F8A3F09424D3D5CAC1C777", + "B83E20A23802D8755A2E850242B64EEF", + "E6790AF3911360F28FD17886DD311F88", + "0A6304DF33E409C8A21E1C19187183FF", + "51966561DA7ED5F30130B55CD108B5BE", + "0ECA40693BF4CB41FDD15BCFD8C9D9B9", + "8731B42742ADBA2D89C9BA90EBD4E42A", + "BE4C6C18AA231E9BB13909242CC92EE3", + "39AC45537E9AFDC6C8BDD4204039A218", + "AEA354F16E1E8EECEB5A98D88418B1A0", + "4F5D37D7D0DC7714E62BE4A0331DB07B", + "9603F03C3CAA8C2F0ECFBA1374891007", + "C58768944996884B46A8FFDDB9AB87EF", + "3BCCF2396A97FC1C0CFFFB6ED41716DB", + "DC299278DCA45AC1B6B08ED4B62D9BC9", + "E195AECA31E10241BD0EC4AC5418A25D", + "B397A4983ED647A0EB806ACDFE7BCB34", + "BC8F7224B0447E8A1CF0F5506A060F3C", + "FFD3ED02E7F64A5D6B37A9DC5E531646", + "BC6019EB208B7AF8EFA6AE7B4CA0556B", + "D2915AE2779F8F70E17CE953C6C1A380", + "B2AA4B1ED2285C9DA4088B6E9681C690", + "BE0D64EA88A3FF27C8DFCE13F13A4E1F", + "D7629F1DD395A985AF9497F6ACB4EDA1", + "33FDF72DA1D8815DE2DBE81D97DDC6F8", + "D35742045F3DF8D184D6CC58EB9DE323", + "DE6469D10C044ED53CFEB523C8DF34A2", + "2FAEAC3A41CCEABA8140BDA9C7AC7740", + "7BA6691787BF0C526F3697E2ED659B0D", + "8F9C0AA2549714C88BB2665E8AF86D41", + "BA9AE89FDDCE4B51131E17C4D65CE587", + ], + }, + // K No.002 + KeySet { + key: "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + ciphertexts: [ + "99B235859839170B1EDDA50EBB2F0B81", + "2E0ECBFC863994D753C512C9B4C44292", + "A56C7F41847E14DD2C68603ED8AA6314", + "7A0E09C8B43CC87DBF4AA9D5A5604B38", + "832A613AB8B8846A2D1F2E6B63FEBA0B", + "D9296CDD4D8DBE681BB496A04FF17C6D", + "0559DE35310C906DE89061B10465E4FE", + "A01ED4256BDE6944CE7A569C48E9735D", + "F37EA27BCF5B6326BFD93DE0174BDC84", + "75EDBA07DFB850FC12E6C60A06A87A12", + "DFDC00629D422E961FB50DC190868A80", + "624707851D3302430D1E3882BD96C304", + "B3E0D70C2C6026EF32AD748A78F22C91", + "A770EC2324BAA53CC1D1CA529AE93D92", + "06EC41EC3E1731A170F1D091C12DA93B", + "317D83DDE2F5542AFE1681DE1BDCC568", + "64873A421B672403425122BB498FB078", + "7008EADEEC7F9199861ED348E0FD67F7", + "98BA2CEF2B9DFD2E3AC39125D0EE6A97", + "C7613E8203445FEDA6C8EA184C058605", + "9D010F6BEE6F86D527111FDF968287A9", + "1D3F7B7019C2A3CBCDF42A2382D220B0", + "02E6BC6612381FEC365182C0C054D8FD", + "27F91B23E4F1600DB6A05252B363FAA8", + "1F53EB419539FF49C68721E14D15B19B", + "8FA7204FC203B9AC422EDAC7DAC69E3B", + "A57164E5295B0D5292BB06EEC7D29712", + "EA53806FEDE8689CA891569740132953", + "BC9644783E4A50DDB1B4DB6854164AB4", + "1491340F265DAED3CA549401F68F08D5", + "D790C8DBCBD4A4706B10280775EA393F", + "B94F9D7DD0CC98E0C639EAFF228B5F43", + "E35BBD818CF2373B6BCB9CAF0CBC964F", + "EFAA610384361FAE70A31AC18EB854BF", + "930FD93610984FB2DE36ABD433B5204D", + "6FC99419B9B5CE40B7B3665294F8698A", + "9336B5B04DA745590EA8A605AEFD0B7C", + "09C7305173195AE4BA9F6680E3E4D50E", + "BAE84C28B481246ACD37897E3C962071", + "8F4003A7D34C9E33090B84EE2DB8F3CF", + "1FB1F27513234882FBDBD1297AE96039", + "5BDBB9EB02087A1DBDD4238A5277763A", + "C8C450720737A7F18EE40F12CB7FE835", + "AE1F013CFA5D4B69C78260143F481F86", + "810FC0F52DBC72FB9AFCE21409EE83B3", + "E9C20EEC50D20E2D6710C5C323778FF5", + "BBBE2207BFB1D8A5DE5A6F4E0D059989", + "ABA80324690EDC07F5098D95EB52898B", + "9F5F7FD2A520D37ECF815D0449D16134", + "6DBAFEE05B3A915E55DF3EB966400D37", + "E0AF6200906B831944B91E6424735F01", + "FD18009EB58D912EE9A73EF74B4D58E4", + "50C1B71EE9F285C88E80D26E9DF4AB44", + "DECD2D6801B778DFDA26DEFD03CADC8B", + "615397480E98D3B82CE07702539ADF08", + "B8FD69828AD0742352640556E2BE0E41", + "475BDF35658CDA849C7DEE77ADD076D3", + "941876883B8414289D31950B3B709ACC", + "59524132F0A2130B214A100958807218", + "B0AFF58906AFC907C05D7FA97C2B1226", + "C63340129C47F7D9CDD571E75E475B8E", + "ADCCE71D0174992879FDE7A7EF0BD783", + "D395C0725A7F30002D969FF19DD8C1C4", + "A255F9604D20990E1EA618865BFD196E", + "8D0B592D078A1825535D7F799E3842D5", + "8973D6629A0116F9AFECB5ED9FEA7CFF", + "C0A35632858B7315A2D5045CB2746808", + "0268EEEDB5A113CDDA20285FCA9519DC", + "E3AA9D3D08B28811071756186F420F3D", + "D7D80AE36E021E0E8D27B9FA3B6C4AE7", + "FF12C0CEEFF30E380D7C1921FDE713D2", + "E4B4F079019391CA14CED52930509DD4", + "234E8D8616408FED16909A6A3E3CAC52", + "242F17D619D0AA665C351011D62DF30F", + "CE3B4616C8E70255B874A12E3AACA2D5", + "D4F1C183B2FDEF3F16828DF6419394F5", + "EA21DA2FDB28EE91B51CEFE462F1B722", + "336406F2B6C613F5F32DE5B66BE502BF", + "D2FB8DEE647321533343AFBD2D36DBD5", + "BE3C616D9CB8E0856D62174E83002720", + "298482FCB4EFAEB5E5BBF291B6FCE77D", + "E64FE7374A0FC876D76C9405720AC404", + "5A168E19E603BD1746C1503D52035A9E", + "ABCC9DE6DAEBDE1FEB6DC6023BA9B195", + "60747C36E8D9123999CCEACECBA17EC6", + "52A0F557B152E2D62B1606F8C9FD1C32", + "6C7A2F8EC2A3AC33945858CE353EC6DA", + "579A2ECB0F23891AD4E2B4E223C2A727", + "CD3A9398798198B038D4DB2F4EC2D328", + "97DA0C9610AFC0639AABED34545588E7", + "005E8447F99E2946397C9E69D0A27193", + "BED4855272DEFD3A93D477994264E00D", + "C538F6E9174380125D9372A7D7E83FE0", + "25C8AA803C6B219CC72D826FFA76105D", + "D044D873C61FFE77238B8EE4E6FCEA9A", + "E6C7801CD2DE0F8B1D49DD9C003B8A8A", + "7CEDE751EF5AE9E009F89CB410F39513", + "FE439B9F162122B58F82B5370F5EA43C", + "383DFB8081F9E023BD6B4A839DB1A845", + "ED5485F9EFE5D7C27D4D45FD2BDB093D", + "86E558AA0D206AF14609EDE169890B74", + "4FEBCB505D1D78ECB322A20103A5E6F2", + "5BE37446012432432F156E86DFF4DBC0", + "B85D1630A395CAD0B65F196BE535FC43", + "748677AE2415FE220D26FD730D748649", + "762329F1D087E81BA1EBA3419D01BA61", + "5A3FAEB31512795F6AE547A643CEE775", + "862C75EECC73D4F2584EF04AC7B9882B", + "30386A8A5C8F49BFD95B4840CFFC4842", + "51C296F137AC3B112E93A8681C001427", + "E4C4D8C6B5D02EE25123A53C69CF7D9E", + "CD16F9EBBC9BB76E42467840525080EA", + "836901A997A3325029BFAEBF2AA13831", + "68E6BC2A46BEF064EE2CC1E885C2C6CE", + "79D1FAD9C32B7A8312901E832AA36721", + "53090A58D0304A163E741C7209E5BCAB", + "32E1AB0BF801BD3567544CA1400C589E", + "9DB9F504FD6D9C766DD5CF1F910DD476", + "B16E28C74CE65A47F5B60FFD4C50E298", + "3D2F4D411A12ECB79A33847B8B111B9D", + "3A7B30AEEBF5CE9D898023CB4846DC7E", + "967A0923D925629DF8184FB5CB19C8D3", + "49AF8EC25C59483FA22ED54F16B50220", + "EFE2E9F112BFA6E893FD69F708762E49", + "748C3971032501A8705EDF81D0C5B7FE", + "659B440AF48B18B049ED3A689B1C8E76", + "1A74B1EF3373D8DFAE4394D2A47DB662", + "8A8E46DA5B9BB01412C222BABC92B8CA", + ], + }, + // K No.003 + KeySet { + key: "0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F", + ciphertexts: [ + "396A7722B273C114E4CAEAED4B63664E", + "BD3E333AA4D14EAA6A6FB27382C1EC71", + "1591A7EA2AB5559520D182A9A74B1807", + "4DFFC27DF886B325D0423A639DD3F9E2", + "E1884F15D83FFC8F073B8DBD0D8F368A", + "33B0201A29AE51E2544CA75999304461", + "10FCCF785B17FD4507A3ED886A8050DC", + "FFF3FD8C31D42089C886FE105570DC33", + "686D0E7B5005C5A54F6150340E06C7EB", + "FA3077E1D41B425341A0C64DA3FA8579", + "75CAC1A436CF030C276FBF2C1A120E31", + "4859F278AA626701E43691EDA816309B", + "E4EB991B893EECA951C7EB39B0F08053", + "783D0CF1C7DFBF494931C4872B2092B9", + "C13B62C7BCF902F8D5C612C24B8679B9", + "4E79B35A96515F8F34318B52D1417828", + "A5677246DB57D9D13B3D474F947F2E9F", + "FF040741264BCA47090B522DA0D05F4D", + "DF476202D8C23F242DA2006FD9E920B0", + "918ECB18C358ECFC6027D651414BEFE3", + "4CD39531F9CD06169F57A5BEB04A2C9B", + "9239448CBEC82908D62F0AF9D8E5E237", + "633343B62105D348A076C172C715968A", + "E98437E76A2F3CF6D854A366EAF10EAC", + "10DDB79B9D833DA3CA6AD94419829CF9", + "82748247E4AD4DEB45E963150910C72F", + "AC59D31A568737B1353C76F99229E7DC", + "E434004A8543DB20233D9AF2D96F45ED", + "1D48CB930F51F54115809CD808DA7E7C", + "40C2AC004DA85AE5FEA0C55C2C6BEE82", + "C201E988491CE65A9501B75576ED8C2D", + "5031BACCE7553B5C7DEDB2D6E9A678DC", + "62B752E4C7AC73300DDFEC6CA8FEEDEB", + "DC13C024A691AF24FC289BF43685203D", + "E42A90E4B3B9C7EF10A8F6D249D35874", + "A04C3733CE34C5135A2B17840778576B", + "F4718B8A1130B21FECEF70B8269E84FA", + "C6F1B5D0FAAF10A702FB919B8F003FD8", + "05AD991637891FCFDD47DDB7F3B961D8", + "A5A427EAA76C2B2860F0E6B7F310B6F0", + "C4BA3C6F7555616BFEA2F5B3E21E9997", + "9BAE9D13A81C36D7690B7862E9BC26D2", + "B24C2C100B23CB8A876547FE07D510E7", + "0FFF6D4BC6F61F02169DB645DE2F21DA", + "EE5F11CEDC2DA8B45F8775E3B840E1FB", + "89EA6A7C11FA5B6622D626EB6CEDD908", + "CB382D9BDC2ED0634526619696C164D9", + "FE44540C0BE9F48260A5E5CE1BB1E99E", + "93851482E46129D06E9D19669FFC173D", + "9CBDCD657DD419F7C958A407F33E9018", + "402C3F17914DAF6E3E433E9ADFFA7879", + "65E25EA516E0549EC2FAD1FFC46D3089", + "6AC058EE7191D3190FAE75F7C43EBEF5", + "5B287D4EFF069CFF752CCFAB0E8DDF25", + "4859F4D565093ED0A4202BB6C2FBE0B5", + "C89F69A772850521C3AD3A4FFAE9DCC7", + "419B82DA47F3DF2F9D22BC05A42E7E0D", + "8C6E024909BF2518C457C9A954F61D0E", + "C8BE06DCB506CE4182DE5AD2592D9EDE", + "4F08ABF58138200F96A880FE6D8AC074", + "1F41DD8B60758E857BE5D8BB4DF4C56E", + "1806473D3771FF0C5DD1F01DB5460503", + "B2A9D0E3D1A8B91B2DB15E0DD9AE1B8C", + "D883E838A5A644065710D9524D62F799", + "C05236C08BF3BA90115E909CCC7BA6CB", + "6DF270B286148EC90D2A57F61E3FCF66", + "476241768ABC95469E0EA1EC5B2CC666", + "1C7269452557BCAE2EC57499F6922B28", + "72F3140A945D48A57321FC92ADD4C997", + "4E68A7BC46E28904DB0B01BB6CDF0222", + "C9FFC28005431E5A717553D7FBFB2767", + "41F5C5CE02280865C52EE05FE09BF12A", + "65A2B3BDCDF6DFB4072A00C120772F23", + "0D01FAAE77D1737324D38A1B97CD9213", + "2354776AC06A7B35A0DB407994125534", + "5D28ADFD57491A41B61D706CC2536971", + "3AF248A8AE8C8993229470A3DAEB2283", + "0009A7E027549F0D1591C5046DBB9EF4", + "97C0517E1C8CDD3D5BC8CD414751E654", + "692DAA3794577F027DA46A3249B72ECF", + "6F96335AD4304308BAB8FD381B6EB535", + "8CA296F38192128E145BDC8186E0877A", + "C8F87BCAADF3C35C16E1AC0599AB57A3", + "1E565D8C18ACEB22673749DC464D1ED7", + "ABFFA22B8DE061C230F0E3830E7ECE3A", + "2D9AF5FF5AA0D70444EBF2A98B2E8AA9", + "AF721D184196C317FCDB5E4BEB22703E", + "4089B16D6F04AB47B625148B7190DEDF", + "9291CDA9BEE4228B75851CCA5954217C", + "F229D74B9FB2A2F0767229F8649D3E00", + "F1321E70DD44BA40FB62DF576FA774FD", + "1EDD6B6E291CA2A72001D0AFCE113FB7", + "5C14BF431BD6C7CD3101D06B2AA3426E", + "C4215792391FB40C2F9AF7731B683D1A", + "7ABF7FBA412F2E76D4DE1ED742033783", + "0D9DDF9AF78C10C215EF027ADA4C40D7", + "C82553985A9D752688D996A6128F3DF9", + "6CBCB3CAC2633F2C29F0043B446786D8", + "659A9C9D8313B1B943282D84DCE4546E", + "AC1412333AFD050114FB101C60ACC2D5", + "5E5FD7D13F0CA10105902DFCE30005E5", + "7FA55E0110B869966A02E8E26C540038", + "7EFF5CAEDA9FBF92FE2093FF14AF5432", + "E0B5FE44E7286162629C4F92F1FFC0F5", + "C75599E880742529B3D5DA670D9868CC", + "5B9B696A28044E12C3D0EAFA133B31AA", + "41F6008273AB0632EBFCA53CC79C0F36", + "C482C4ADAA6FB68F70BAA497768D7874", + "433E889366AC6D50BA4EE7BC85AF69D2", + "F58ED6B088532CB9F1875B6C74F1A1AB", + "0A2F5EFD1377281D0C0AF95878446D38", + "C84ECB7B433DE0A7665217B6F0DB6393", + "E61D60E608879FEF7F36565F7A15B7E5", + "77CB174C6D04EA279264B9D42AE290A8", + "1777411FCDAAEDDFBA18DEBAB61FA1FB", + "80F0D5BEC7F799063DCD9AB0E661CC8B", + "BDEA6B80D8383D6246510A6BF78DBD76", + "6A65C657E5B41BA34E7851F601A1F01C", + "BA8B7550F739442837465831E8E43534", + "354A370F3E366099C74ED4B60ACFF876", + "8DA4266781459119DCE6EBAFE565A5FD", + "4A1BC4E395226F0723D5687B13E4AF7F", + "F1F2D6D12080C8873D91F48D17E728E4", + "8890E3904491B54A9181AF90C1B1492A", + "25D8112320E0E1063C76FCCAE3A39B2F", + "07E35AB04EB74D11A2172EE97C752CDB", + "C685E2FC351F5FDFE9754AB47F409F91", + "464F6E728D8133C545A712A26DBB5582", + ], + }, + // K No.004 + KeySet { + key: "F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0", + ciphertexts: [ + "DDFA39DBD692A99367227F4AEF48CCA8", + "7D7A57CD0BCD6C872C8076A58C7C2159", + "9646DB735BB075108FB76951BC16C89F", + "79F50C066F95EE68F0E096A380FF98E2", + "71FF566F70A5092908C222A725DA0E89", + "37C46E61121A36346CDB160FF1CBDC45", + "5C32A4DE18D1C20BA445C4DCA4B0871A", + "68A68F390AEC4195F04C2FCD2B8D0762", + "3ACD233EF7A4E70D1CC6947E23C92B7D", + "9E94860978C433F808C915F0EE4BA02B", + "4E38E8B2BC49D3B3820BFE2242B4A8B3", + "5C35D8397F637E7CB99952B50873CD31", + "F2B0B54F2055F944A47ED60B4BE2275B", + "08D4C578C31EB3E1074638B3E4270EFA", + "BF92602B83DC18E1B4E2F67B9443C084", + "D1E539BC79AACF831447AC8EFB640F60", + "54CDCD24B0367A5CD08B63DD5CEBBB94", + "59B1087B37A9DE95D1941A8A31AEF266", + "1AB8B4E96474A9F968D23096ACB9276D", + "16790B43AC2E8F9F4759258FADCA2B8C", + "4DA28638B0BBC10C4E290F4145D19D42", + "A7C197E40A1C38B00B04EC84048F5508", + "BC1474C8514C4EEEFFCE005421BD284B", + "1C5564CAC1E736A3169A5FA1FF8B1476", + "89080DD1F5A45BA4D69D84C533529B2C", + "8E8D347D840A424A4E56442FF4484295", + "FB916A0C9FDB3624F2D5CC92961C1570", + "650A79696F278D1C893F4E683E7B2297", + "D7ECEAC003B46789B6A5891FBDE7E96D", + "8FA5F23D9D55EB387975E431C0BBE4C6", + "33AEFC27409CD7F674078B55C76C0A89", + "586E815C0F30B1C0E25172EFA53AF715", + "D725A7CC0A3283B7CEFFB76EC5D0E31B", + "FBC0A37EA5C80F42E0116C8C5D864F89", + "4CC18821B9BFE7C5521871F5EC809FCF", + "FCD3C573AD8554EE1C62FB46E906C1B2", + "78E9358460810743A75264633EE1B883", + "CD38A2FF27FD355F553CACE89428AE32", + "5A111C646C6B1C0C6CB09FA131321937", + "1B58743D8A2B107E1F4938E645F9929E", + "7BBFF3E05B62365620F7A733119A20C5", + "C4A5A9D28B8DC8928F0E730B43408A18", + "C14155DA085D050EBDAD4C912D4AEF82", + "79C9AC399A3D3D50F31D3C4CB04845C8", + "83532B9E046505359185767EC95289D8", + "A3D61EA35FBB80FDEBEF3F4E99050D1B", + "A36FCC8248858138BDC57559A070EBF1", + "210337A975289366047F63E374596AAC", + "A95274B624E4F09939E043586C799D12", + "21BA92C0AC11A1FB194AA290F9727A25", + "08D695B1725653E205C9C09F01616D07", + "D1D71641D1BF7FC4352FFF81D7AD0C1C", + "E60B6C66BFF6F3798FB96A0C514F5AA1", + "0003E80FE139DA589AC2132AEA5CBA65", + "B0C4F55E0B786B48DA9C4DC39DA73C2B", + "A34C66B4352A5FD03DA2F58EBD25FDCA", + "0A0D52B3753DADC498EAC0277CE9E915", + "4A6674F6F0CA6C806DE59CDEA3F18066", + "B8B7F026A4A2738AB0D8AF10FE9F7F45", + "9F854C5F5AE8CA76AECF525523728207", + "A989C4A2E090DD64FECF8B414C437A78", + "4AA4BD0A7FB823BFECF7BFDD90A52F1C", + "09B934A8EF75DCB1DF019989DA71131E", + "5B5FA196F90FC90FB6A04AEC2AFC780B", + "4A08C90EF329BE17A24DAF58CBA395B4", + "0B9798CBD598134EBDD817A090D55BAF", + "8F0B2DD1E50034DC4B025E071B508B93", + "B629B5D478A5A9E7A65DD3601D3268C0", + "7C6E02BC78A4F148A418F64CA3EE4835", + "E7994F2731FB5D53183F2BA6602FB686", + "3C3FAD747DFD39944D4CDD8AAB015E75", + "3BE0716D6074D6D1EE661D586ADA16D1", + "48D38C252CB81ADE1EBC88B835FA4CC5", + "FF48C366E1C39A511E617F524752B15C", + "9829926CFD6903C472B0C49CF90CEDEE", + "47174B113BEC1C83970D9FE3BF09EC61", + "DDDE17B0D02B4D12F942323FB987F5C4", + "237610FDF7AA947FE3D7192E78512872", + "6BF2280A97393CB4569A6E2F9C06017C", + "63AB5F8B1CFE0C3CA9B43A028154FBAB", + "E71E047971028A42E92012EBE39FB90B", + "4B46BE989922546C50A3BCDEDB7026A7", + "AD79DFA0EDE4160E722CE2D0D4D51901", + "3232522A13049F76EB38DECC211E35A1", + "EAF65D13204EACA5A00226F1446DB7D2", + "77C95B25CCEDE33D1EF0399FD7332C9F", + "4CB8006EFA8B956C1B3BE10153D771B2", + "C1CB861EE4950EFFAEF6F883216A76D0", + "2DD7325138B403BF9F20A1DB3C859324", + "12B341A44C1866EA29B2FF5E06C7C6FF", + "3330808A707D3BE085B0344F46DE779D", + "035193DE46FF0F27E42C240C78807444", + "6A97524C724A8980D765F70AEBFA68B6", + "914AA691BC649CD4BC0F10E25F718441", + "54A758CD9B7BA8278A604B9AFB02903B", + "1563115CDEDFF24358532A8A7C119317", + "33D04DE3BD046B125E31837BD34932C2", + "63682EB7CD018B56D83435813E05B40A", + "355DBE698417B2D85E553CB31D747F83", + "C4D458BBE3E18D020F2FBD86A77BC6F3", + "4827EBFB1CE6FE58DCDF20C06757633D", + "8F5AF1D5D91237F06BC676235D9F5E95", + "B91F172C1C943FE82FF4166069BB3F30", + "1BC68CBEC86ACE10730CCC6394C13D5D", + "359D32B96F8C469DF5D8E091C8F42726", + "71156E2EBDDE4803140847A2ED94C175", + "4323B0437D34910DFD170E217B6AB7FB", + "97AE956DD90CD6F3E1D17843A7E1A4B5", + "751C157E5B96DAAD0CD08BCC84112AF5", + "8C007FE007CAE9225E0EE281CD6CFD21", + "31C10E02CA6F24C5BDE8A880F299E4B0", + "D0E939B6FB19139C5E7224B15CCAD7AB", + "8777C916F332F85A65250A8F00F3A936", + "649340F43C3B81B9BBEBB1915E49888E", + "09723478AE62839EB0686E255BC6DABA", + "EFC7E71561DA7661DFD3A5F7B9D274EF", + "09F7883F840E8B709B3393EA313CF2E2", + "F6D70E26711A823EA05E19C5B1E98DFE", + "3117705378B7FAFE869BB58E801C65EC", + "BEE9B15AF639F2ABEDE0AC1E98D9589E", + "9FAC9168A164D57798A4E3649322AEAA", + "0F108CB3B38D91BD107A0B2671009ABB", + "FB2AC400466F6C9E8A98880C6EB7A10C", + "C335A71D865E164058A326621EFAFCAD", + "FE8B7C19DD1BDB4AC4DF6BADD53EDC4E", + "2F7E1CC5F9C5915822A773DE3F840C42", + "ED6A6823E1AA381D3376FFAAA70B9DB3", + "FA65972FA54899E843F662D41F337260", + ], + }, + // K No.005 + KeySet { + key: "00112233445566778899AABBCCDDEEFFFFEEDDCCBBAA9988", + ciphertexts: [ + "D33F70E7C9A0545FB6AA6E2B3B0868D5", + "00FD3BB42D2B26249F33FC118873112E", + "74B5F5778D9452460B26A4600ACF96B1", + "BA7387EED3081C4D54677CCD2A7812D5", + "CC937B61673376EB6D72EF75D728C4D5", + "A7D356F58071D71E529E45769C70A83E", + "E25F85D906C6D8A1DA74513FA6755912", + "CE14642AFB1DF5EEF139C5591690A847", + "90882BC394390A4F382FA0A6740BD28E", + "43AFEB90466E6AD5222E99BAB9AE3A4E", + "0AE3C58786F82C612BAA15931C012508", + "247ED5C9753ABAB01E2FC2BFA9A74653", + "B57DA9A1AE8D7B2D98457D2F1AA97654", + "4B59B0430FC6B0DBD33FC26EC7399F53", + "49E48CFB103907E774403C5758387A3B", + "90C999DA17EB3E2076D9CA78BCCB8A81", + "0416E26B479E0F771D40120534D364C7", + "EAC523CA3054BAB55E5A4007C7901EA7", + "87D70F845E501CF67FD9F9E134D43F34", + "5917369EDA89027389A3F84A9749D087", + "90AF5A8EB9D9C68D671532F9DAF31515", + "EB78EEA321CE4868567639EAE3173975", + "48B3A5E63B9940D8866DE45CB2523324", + "1B8287EB9822EA93432DA7751B4EAAA2", + "E263A980464CCB0493CA9BBD94704BF9", + "4E9B05E02314F1103FA94A83331739AC", + "3AD1A0D976168DC723AA2CF8C6406ED8", + "CF2BCF69499AD2E5ADD2355191F433F4", + "BDAEB58E71527D50E14793190C5F9448", + "E405CBF41D47BFE3565C1FAB50C2AC6D", + "EA1CC7DEFD0BFA77281E10BB8C10C042", + "6003DF27907D70C6E3407A03BEC00C57", + "02A113A3593D869C26A1B881FBDF1402", + "DD47FF388BB71ADE25B75029DBC686A1", + "C8ED74FCA06E3A65F2EC688BCE56098B", + "DAE29EDFB82CBF53EA44FECC76D3C69D", + "9AB8DAB0600166E82BD060607A57D5E8", + "67A93B579972BC1BD0BECCA7E7EF93B2", + "CCE01DC74D6AE5C98F57925C55490F51", + "C19EC8107F57C720AAE6623F75FAB5CD", + "0C89D59E1CC6250BD2F875D4C09EC4F7", + "6F8E66F54D9625557F7A6F6BD3A62FCF", + "C9480DA225293902022C9F41B558AD8D", + "A796EE215304498AF296FCB0B2C55064", + "B433005068DD6209CC1D5A27B63651AC", + "4B558FFEC24D651B46A406B9DFDD0E6C", + "104E1EE0BA5A35F221A27B8335121402", + "BCC01D470EE4BFF7CF54E7B3E3FF9782", + "3D768CF2A6BEEE3CA2A5E4DBCFB071AF", + "455F9D6F4F458ECACC26A5DC18BBE277", + "3A59E4DB8D64180EF857174A12A20D98", + "4DEA3BCF8609C2AD10C50C3CF59E66EB", + "80129F3C26C77380E640443048DF9A44", + "705F5137674817AA5FA6AED34F5E513B", + "998B6B49FFEB34A124330E0A9DAB4611", + "EE8A788B82072655588ABDE86FCA07F4", + "9D0A1EFEFF011FF3C064E702D452CF63", + "EB1BACB0E40D5F6D7AD637A5D3501487", + "48E5BD8EFF7572B1F94AD904E3F776A6", + "3C7D31BAADD03D43EF8B260B357C3003", + "E5E2BE75AE2403AC7236D2C64BAA318A", + "700B6B98042F40D46C9766E34F3784BC", + "36BC9592C81C15343456C22A8533C5A8", + "46B3472D3593754A43CE47A65B8E3943", + "8D48E2376B239F90F01221FD03E1D249", + "7928783C41890DE9BE52DEF9F97821AC", + "B8634CA69C52E4C21EC4FA3E358D25FD", + "7D612309C38AB66EC812FE141B71BE3A", + "B1DDC10E6F6B698EF7E4CBC9E0B44655", + "604732AF6960B8A329F351CCACD8C441", + "004D2B8FE865F365BAD6B9AA73259C92", + "25BA93165A0A54AB0B6026D68EF2DEF8", + "F63739F6845DFAB864E45372904CCE04", + "237875683FD7214ED864354EED1C8512", + "F512E7F087027517E534342F88E167ED", + "A916628191D9DD23BD6B989721ADAC3F", + "846ED8A07A4CD11699C83C1478AEE713", + "7B9838F5871D1FEA61AA254CC99CC7BC", + "9875E635A0706B897C790B4AEF50BD87", + "20623396932078852F0237B2F5AF352C", + "01B9351015CA7BD51ACD5D0F125F8140", + "79A1EEBAFB15EEE72DEFBE8D6B3F2353", + "8914756DF527AF80927097EC5DF47428", + "BAD4747E481FC36FFC29C0D43E425D5A", + "72553437A95E9F3924DD90F46AEB7B6D", + "509AB89C3EAC9B22FE164B8D7D5CD4F8", + "9C10C8FB9DC7D3BEF8CB448E8F8F7B54", + "4C6CC3A857D52EB9AFDF2404FDD78F09", + "E7A230E1409E427E0F3381BE778A1745", + "5CBB872D53906C062F7F7F5182DDED80", + "A4D05D59EE93C39D522128CC377F912B", + "566C4E5EF26178F78F8621D57369C086", + "2FEDA3F62D3107B02C0FA523B6E2B606", + "267CEA8C8862D30E49C8781A503EE4B0", + "3900A6E9E20D69241787186E82D16982", + "6487C49E81C448A46DF4B829D5F53656", + "C5A051B66163F5CFA44301A98360C41E", + "4CAB1CD329C475FD649283ABE4867736", + "FDD323DC59B3948CCAE36CAE72662129", + "C7AFE9463CAE39089B28E18F779DD1D7", + "7961D5046399352510073A223E112498", + "950FB4BF666343C0918F29911E66BA49", + "A9FDF4BDB2DEEE2BA58D7129D8773B51", + "5EB17D4087B57D7430A9068FB08D5F5A", + "1BF66BA16346B133A1E09262457B0195", + "937503106E7EEF4988496F269DE670AE", + "B925331DD83F88036D76DFD5B574EFA1", + "E8289EE28CD896B72B1B75B79DCB1EED", + "4073869CC84430439A993AED64C9CC32", + "E6991D88D4D1DBDCB2B9A92918F72ED4", + "204F4B1C92C74CEB5DA378867DA58626", + "949F109402A82DB3B76E9223591C9431", + "1E2D5E03E764478E5DCBC5198D667B8A", + "B09F3018B4BA6DBD333B8600CABEC3F4", + "93D6316C897B9FA732DEA660E2F87C02", + "DAA02E885CA8AA1A7F695CC8797B8574", + "3EDFCEB6A8091FAE3779114AF4FF377F", + "F79EDF50438597F6CE27A8B766C2DBF5", + "7CB76DE13C1D22A2BC0AE4EA8B7D7503", + "EE6337A1BE632626E8A488430CA73C3B", + "AEBB33F434EBDE41C64C4DBE0AB14219", + "EA426C77C93DDE9589CF88B8412F5E46", + "9EA5F4430D745E3AC20867242BF96FC1", + "0F78EEA0D2C81F98A51782E474ABFC45", + "59E180D195950A200CE2C3AD7821FB2E", + "B134662CDFAE919BE6B65C4186CE6B3D", + "37A73CEE6ED202A85CB9535A10046509", + "4ABAA587AFC585B0E31E7D583651EC8C", + ], + }, + // K No.006 + KeySet { + key: "FFEEDDCCBBAA998877665544332211000011223344556677", + ciphertexts: [ + "30E57B92953F9E13EB4BCB0F654B887B", + "E3AC2569B9D92080C5F69E9E45BD0A40", + "8BE2F11EEB566CA14C5DBF13F36F7B7E", + "A53189F0EA01FA78AE7E964AFD8C80C8", + "896CE3CAF9638D1B7ABDA182ABDFBC48", + "3FBCE248C6DC2108531A1B0FAF47320F", + "168AE00603C835062E0945ABB4B16E72", + "59B27BC6442F8E030C3EAC908258C8E8", + "00D0730DE2B0B8FEC46074D468193D48", + "FED491801F7BAF4B9C7F383646238CEF", + "C931D134A62BD4F20121A9FEA1621163", + "5E68CCA9D8F317924B0D77F5426AA86F", + "72CCC704BB58CDDC5B082E90AE50C3F2", + "A5F24ED5A5F2F44A295C47C58D8B36C9", + "DBE0D5340229FA3D77209FADB0CB9CEB", + "C09C1D95397E9F87C9B687A41BA35D36", + "79554FC3BA57625AD64907F371533526", + "3D6701CB4DE26D6652BF0028ACEA5ABE", + "AB35E93D4B3F2D44522F872A4680527C", + "C7E331364395D8B0BA1A34D466DA1D3A", + "7081C1C86E93A39DB65D9DADD81308A7", + "C12EE3F7864DADE70C0B46DF05251341", + "C2BF4D5B0A83463F49F648C623719B35", + "163FDCDB7323289384050CEABB66A7EC", + "BAAEB13F784D9E9547D6912A386BC910", + "DE154A413785D9D50906CA86E4CC79E2", + "446B7399D53AD55CD73C169E3CE6153A", + "F8B7CF661077BE75B73D6FC272AA4206", + "1E12B407EB1D7CD9BDC6B46999CCE563", + "BAFCA297A199AFC2382D6AC6D35829FA", + "CB537CF6FAC97D42BAB4C7DB642D3E12", + "D8FF70670C61B56AAC6C6B93D786C7AE", + "ED66C773DEE735E618CC3620100D818F", + "DEC5D54EBFBE3110D7EBAAB05221DB01", + "6AE302B0D8C651D67ACAB08D2D3D683A", + "6340282897FA420BD64882D7BDA0D07D", + "214E64243D2077F27A3152639C5F6FF9", + "F68376716C2B7EAB7BE5AC1411CA1C5C", + "3753DCDBE41AA8E4DA9A859B1208E96B", + "F7FFF9AB5E6A6A248C9A4EC983849841", + "1A9C0152D8934539E300179EC38DCCA8", + "0F6EF443187C452185AF174EF2DE2A02", + "721DA47EDC9D7122A593F0D8573DBAF7", + "2286DC4B83F96A99FDFC814C7BBDEC0E", + "6F6F0DC282102277AEF6DF6DEAA48865", + "0F6CE02389A8E6E431C211A5A1588B05", + "50A432C877EB4E154EF8B0F40D74B996", + "0BBDAF8A57F6A9AEC6F6AF237270D992", + "0051BEE96D8BC0A809C06EEA35C994DB", + "D09C61EB8481D6ABE6DF799A9B56A3D7", + "EAA3129C86564A98B9A13F021BDFF512", + "DA36B7A65E59E1AE39771C7AA01613A4", + "F8FBC9F934B2E4C932F7FC7D5F7F1D96", + "511BE62CF8D32F645B8ED7A972E4A0E9", + "F52C360EA8922DD24ABEFEC0CB3FD148", + "0EFBCBED5DA79276F69E1A1818A9C469", + "FA1B8025F8F522609E75016C000E8DE1", + "3DB7DEAF47E9FC3337763F3DBC1B55FB", + "BE751FD42282DA0B65FE262E03EF000A", + "903E4CA9A085D2ABCF9DF6F21B1E6F35", + "5344F3CDB8759EED06F9D1AEEF64FAAE", + "2CF90C481FFBAFEE35F3169050C8E566", + "5CF81ACC7DDE4D1B1289AD4A7A639DF6", + "08F7A557C2D17FD5B500A9F5C5001971", + "0F7F29F5D2D57C4497B102165154259F", + "761FD7C15607AB443D59DDFBB11D4ACD", + "3D0DA2CA3FA106D289193AB99702A58D", + "9C6CCA1D02C7A7FB87462234A1E37608", + "B070B31A4CCA4EB52987A735F5BF33C3", + "5A9599A2F33F9FBC4C41F9EB74DBC330", + "1C3819F238A91460DB68F0E238079F40", + "7845D47D85659621197849867779B1BC", + "4B71CCE550E10ECC6FE213259F91DAB3", + "07A58216FAB501A0C0197DD1F8909021", + "C468B3806214C1D6A5A0629C4A923EDF", + "B5DE656DA03D57453026E4C91C8C59D3", + "878BBCEC39E1A263622FE1BBDFF8784E", + "AC38ACFBDF552EEBF8F4182E7FEC930D", + "851A3583886A732661B80AEDA4554CBE", + "333A0DB6104804847A1203B16B5E212E", + "CF8C3B33CA4ED927C416E2D5194A42C8", + "60D768E50907947FB488D149678429C4", + "E160FBC8C14C71D0088CA9E9984356BA", + "F40D81A1ADFDE2CAE8130863C28CF0A7", + "F56884AD1C78FA948732D8793755013F", + "8E8D2D0596814D7113A4951113F06479", + "7A185FD1DCA129C396171D4E2076B461", + "C9090021A8D145AD27105EE8E945A7DC", + "0DBB216D812F2BFEF26D6F628A25401B", + "079AEB2B5DD558BF11C21A1FA30606F2", + "D6AB263F06CDCD53EAD8EC715DDA0BEF", + "647E93BFB1C7361862335BE8D8531A70", + "BA99B0926DED2FF0AF1B0A64FACCE3CC", + "0161732204AFF49DB0CA682A324B53EC", + "F37FCFA0969BBA108E95A8E04FD48274", + "B5C23A19134FE533E7BF9A7B49CA4E56", + "6FA7B63301A096B42CE2968EEC05FD26", + "22B212EE3A05E8DBD90ABC571235A5C8", + "D03CE1FFEE4A56E373E411B62957B7A2", + "DD6E71D83432446606D7D87E3C5F4F37", + "0B47D1E5BABABB7EE49CD312C6D6E77D", + "B0013F7C314B4BAA2DE714B5EC178A4D", + "36217444F5EE5FFA6C43B943B52D7498", + "27EB13257FEC7F58B58E1E0A4ADB7772", + "1327201233651D54E538683752F392C0", + "EF760D67C8FD4341D21FB2BDEACEA76D", + "0EE85D8527E8824AF810F9F4A3091077", + "05DCEC10F8DB6044F485AC36934B8559", + "2D98A9F401252FFA1D8CB6B03E510044", + "F96330429DADA8FAC09561CED7AEA326", + "8A8E9AD2AE5BE7782B78AC8CB0058386", + "E7C945EEBB38D99135A33A15C794C8C8", + "89AE3D05938CBEA9836DF0A2D10CE6DB", + "CD2A0CE5D95BD96E6F456A90131D4211", + "0C6CA358B1256133FC98B5D96F041EC9", + "2BAF2F3BE437B7D4088E47B0BF715CFF", + "8E565D70DF0918CD43885AB36DB54EB5", + "339069982F7CCA0E0E6982E613D86979", + "D0D7B883139B4CB4E276C693FC8C7352", + "FB902504E49C419E2FC7BEAB6F867063", + "D1B4AA13410BA6235C5298EFF1547B82", + "14178C2DCC58620342DF43C12EBB6D68", + "A6F9F504374B5620EE3448577419CCC3", + "A22F90FAD48343B99D97A6CD294D01F8", + "F9CBB3FA0B7892636043B536D8764C4A", + "407F949A1F0068146186EE3CE3B4BE2F", + "0A6D281F90A3EE433DCA489F6F0E0489", + "8ACE256FAE07A7C6E10901A88E8D4159", + ], + }, + // K No.007 + KeySet { + key: "0123456789ABCDEFFEDCBA9876543210FEDCBA9876543210", + ciphertexts: [ + "85BA4EDEFCEA6533E2033B33223EDFFF", + "1E04D42E959531CF59F6CDC0BBE0E3EF", + "FFAF72CFDB6C5BAF878DBF56F9E55299", + "BD1E3922A89B5BA1C13A40DEEC3CB41E", + "82A9A6CA76DA3DF4583E002B79250A93", + "0C32D3AFC3E2C27D997CCAD8F0352B8C", + "9102E73550B2829475F2DE4FE14A66B0", + "4A8F7AB4B02C9ECF1C67CECC0A6ED50F", + "157579A70B4A1ABC61546ECA28A4B937", + "0B551D0548B81A0F3F5819AD4691AC02", + "6F1E2E8EAD692E4051CC7970FB311A17", + "156E9323606B9A4267BE1CDB4993EB59", + "221F874CCE15DD8BC0DA9BB252268465", + "09D85B24969CE6675D0832D20656D722", + "691F6AD95B62860059F9B49DEE64796E", + "A151851EC4D0849CC4FA9E10EB139BF9", + "7B4F1E925A435C18614DDE6A4DBB00C1", + "3415EE0C03881568D99F91B2B2CCCD40", + "D17212186527DBD9BEDF54CBA1198407", + "3D0BAE28A32DF82AA308D0A3020055B8", + "5B140283572606A24119C9DE55B161C4", + "85A508D3EE72940DBB1ADFFD7053DCEF", + "C55C1C0D2071629D098025826718FA0E", + "37A16B737A6049AEAC0CFD280D95E6F0", + "03AEA298E06631C074F0F90529CE2C33", + "4BF6255CA8A59E989ED6D21322BEB1AE", + "4D29DC41A802A4A05FB1E92547805935", + "10B0A180E46366928A2B7E4D7D4A5A70", + "C4FE1B0125AFF368E120A41F138E6892", + "86BD657EB9A46CC68AF70319674BC232", + "4966EB70232A7E3EA41EAEE389A9F309", + "8D16C5626CA9368B193FD9FCB8EBAC2A", + "6FB60EEE3B28EFE2A7CFF3ABBF527398", + "06077A53C20B5D27B8598DEACAE4D4B2", + "7A6905F2F404677C904F32CA28F813E4", + "4990E395D4085327129EAEC11AF960DE", + "B09D2A95660E97D539593570493AD6B2", + "BF52D957FB0AF2BC1EEC02C961AD728B", + "EEF57F1CD0784E6DBAA526FC5D5B846A", + "BBBBCF5968CCB22CAE829AC3A5BEA6EC", + "A41472091947D939547DEF0F3E3FB71F", + "B3952E6DDCA8EE058204A8A51E375EBD", + "48AE393ACED0A7198F7C8C268C2D9940", + "13A35E0659DA4616C8D4C8CC95F4B1A3", + "9386A960BFABFE067C3F9D7CBF223C17", + "8037EF34B73AAD173C4E56F703511468", + "F7E6D4707CDF342FE3E7309EA0BD8CDC", + "307D7124CBE4723786BD7C7129FC79BC", + "5C639D420F7375C956B5C4754AC1FBA3", + "A619DBEFFFA3E2B8DF4EE3B43F95496C", + "B890A9FF856EA08B470A1C48B6830509", + "1F8143A722C70A32B61BC45B8A301986", + "78147861E8C4015656BF2DE0846A4F77", + "6ED4B94B1D4CDB3821A46AB30A6B2045", + "7D4C8E1A5A15C4FE0903E9F404196A73", + "EEC387EEFE55F7821594FECFF3021D94", + "A5C09054C97A7B005997D1E10AE90F6D", + "3A80ED019B866A4477583D207FC9ABE4", + "749CDC4BDB0E1987C55DE0BA4D74E5AE", + "3F58D75725A21F758067C951D8609214", + "F37E5E91134ED08854527EE94C8101B3", + "A9654E9E3DB13FB49DB2609D58F4B007", + "6E4E063207931723CE3FE6711B11F1F9", + "88DB81AE9507FC0C730021711F687CBC", + "590953266AB2D88729677D656BDB3D0A", + "FFEAB91631FE278A187FA3CB06654055", + "3C250045CDDFEC3B80DB1C9560536E1D", + "715C08A18F06137BF5ABA7A25A4B0EE8", + "0927ABC1D9517BA15D53988B1709F4E1", + "13E50FB47EB686382ABD2DEEC3CB73CD", + "45DB1E14B602CB0C9E660424D10D4639", + "E3BCC7BF084ACEED00AEB701B8EBF822", + "2B512B42C280FACE600C707C327883F2", + "83300D516874FF0A7205DBA39C319748", + "CD668788601939EF82CC9885F1D0A2F9", + "F8216774113646C751C25A71F65DE4EE", + "3F5DE26359DEF147660138117CF35651", + "B7986453F7B672795C9FF78A17806B03", + "258930CE3F3D84F7C974B642BC9C44DF", + "C33D570FC30A2275BA018D9618DCECFF", + "92BC879CE58ED1ACC2E1668F07410F01", + "28409DE6C90BA4048C7552EF10ECCE8A", + "0AB091E1280C12C86E5212F2E599A0C3", + "70103F022D0597F0D65F81E285EFDA37", + "E6FF384C0ADECF059EDCECD6622FFEEA", + "778167100E89838BF83C937CF1DD2F01", + "12BE0749021A7F5040CE50EFD983FC48", + "2C01E072F55083F90FC24098AFD706BD", + "AF6AFA5FC8C3CC50D7D2ABF0D0164296", + "023124FC257BE8B8DECF5A49565D4E8B", + "319B8B151AEB35F133DF9798A85B21FF", + "FAF27843EBD52B83892DE416321952CE", + "F7D2D7452330FDCCE07394C88412F2D7", + "A2790ABECCE3C1EA6976BFEF61C15EBD", + "5CCF9E78675017E239CF4067B730A002", + "B5E2AA8674C2B3B77E8517F59619F39A", + "21B59BF8C4B128CB2ADE782F86F8A359", + "A05941006641C4F4393164F086A64FE7", + "9126D92047CBB566D1B064CFD6CEA575", + "0F749FD0852D0C83DC73A9B073CF3ECF", + "61692E76FB0AD7AB9751DE62BBA42CDD", + "C82DF5F7E7E95C2669C4E8905AE30767", + "65291FE744F489D91F97B4A2D1E3466A", + "4103F3A1BFDB6D505CD535BC7808CE35", + "885AF6850B68D5B71D1B574FF9B1A552", + "F815265F6BB093DCCA9EF5F9DB6B5EB0", + "5545CFF83DAA487BAEA157AAC28348B6", + "187541AE84DE9F552279E5F6E8919FBB", + "341FDF46D32B0995D183D6F1066688B8", + "A26F9517DC6025C0C16A9394580D6A72", + "755E93FA3A976B92FC7315A01D976860", + "808DDBE73C6864DBC6738A11786B159D", + "5A6516A4E15666601BFADBFBCEB88B70", + "B914DE2C8F8C38481546900A0261086B", + "0C27852F4EC261E77E908BDE2F289931", + "24EBED4560D68E963DF0CD152E15911F", + "097D7F08010621F4DD08F93ACE2BAB24", + "F6BAB9F170CD7D17B705BFD18B8EFCD9", + "85FDE817C7867939EA8003A71AD3E6A8", + "2AC62C307A15DD1D30EA03DBC08D2A3D", + "FE0E7E0CB678E1D54DFD163E43C5D609", + "1BB1835478C2E335FED37FCDCED796CA", + "B0F3A7D26F2FA3BAB3DA8B6070AC5440", + "3A1B7A14118459C50181AFDB2971DE6C", + "478B2E0E0A3586ACC56D103F99D66145", + "0777C93906293DA5E3FF7512E340567D", + "DF56DBEDCF9C00908FD8C8583B961D84", + "F1CE65E2BA02B055AB22C04940B4FAE7", + ], + }, + // K No.008 + KeySet { + key: "FEDCBA98765432100123456789ABCDEF0123456789ABCDEF", + ciphertexts: [ + "74C7821DCD05FDE6A33DB007353A0E65", + "E15BD31603710F1B4B10B92E5E1EDCB7", + "2610970C3DA190C96171D86E54E59423", + "2EAE865996A69BA64326B474B4830379", + "1778A5D91CF9525F7E93680220372386", + "D873EA7BD9A2CC5185C2AFC0C5B56B0E", + "E858ACF9962E03E28C9794B6DCC4F20D", + "AE3DB542B68CCFDA780C372EA3212EFD", + "0FBF80572A86AE6D61F26763668BFFD3", + "608AD0A63870FECAE42E31E62ED221A1", + "E2342ADAA0D5A860CFD0DE7809DEC485", + "BE56E9D8101E43F2EB92CA9DD29CD631", + "85DAB3007A6FE086D2DAEA6F10D2DC31", + "FF2749C177EE49BC8128FFEB7654E1E8", + "5D8671418E26499B486AA53D63659B0D", + "BF7C313DE21170940A6DCC9D79DD215F", + "9481B1D99237962D82506F26B5074172", + "475CFF2EACB3E284DAF38A9E96C71360", + "F158E5F3A7863A7D5128BFBB1229FCDB", + "62439E2376E35D23A946AACC9154F205", + "190BD5DA48DB829B36903587A54C4D27", + "55DB467C1A22511BC4C5D362396D0BF6", + "B425F0D580956A4B11F9DD4E813E9122", + "DB1CBC3586D0FA27637EB9198636D7B2", + "400EAB1AC6DB3C18F64DE03E12B2A44D", + "1EADC90365008C940A4998AA6A188012", + "43746CEB98472D6051F801CCA595EBD9", + "F71EE137E8D4A85064D1BE754C436356", + "CA523AEAE59596CACD66AE4545E9C91B", + "65A328D7FD0F411039CAE5B6E087DDB4", + "EC2C9C5A82F3C9C416E69E8E9770D68D", + "3EE80B5650454834B670E46A1759E4E6", + "68B0D7460259F7D0063ED4CD2E1B221D", + "C8BC48C1FA5F08A87F160BCAF377B036", + "8D651EA8F0E7E06AF3DC816D99291E5A", + "768BAEB36AC434CCF7B28161CF53059C", + "EED6249DF760486060AD573B7B68617D", + "1E93074314D2AE39B07B86459CF80D5B", + "200E2347D492289842209C696E93FB9F", + "AA2D44C480086594A8BB61FF20EFBE2E", + "FF4FEF40D99E5C4F0F7E7DF0F948C4A3", + "7F4393F7A2BB14AD82AC9C3BF97F6D6C", + "2DEDE4BC917E041E0C860D7F818EF0EA", + "1EC3E5BDE0B216A8076D1DB2BB726892", + "BAAE1ED315FF5C6B3EC8F847C696A851", + "8B36FE2309D7EC239E76DE2772B96AA1", + "07319AECDBE8F1F76345B014406CB0E5", + "F64451FBA30DC5F87884A34C5695EE8D", + "4D5D6953522A03F3D93C36F609D91C52", + "C6687D7505377F6DB61A2ECF483431EA", + "8D090731B1D80A81A94A0F42CB768F69", + "2CF7FB820EA4A91F65256C325E182744", + "A34C20224708A06465603A465EF07F4D", + "36B7D90CADB46AE622FAE75C07B072B7", + "8832A2414A65D8BC050CB4EEFD164A2C", + "98DD0D657DFE8A9B96BBC2B7E751A477", + "B60F23B9D42138CC153E002291B1D7F4", + "C8854382AE5A0E24AEEEC09BFAD88AE2", + "70DD3940E54612ABB11ED2B950AB5BBC", + "106DD53219AE0250560C388A2EBF1281", + "89BC7D709054C6C83ACE007863C6B714", + "A7C1063578FC87308A5984F55D37B2B7", + "3870B145F49F98BF6555073758FD18B8", + "9A01644563F84B1F941DEDA9C6D1B11E", + "BD00A1025DE0BCE9C5773F3296E91447", + "06E7431DA76DB6617DC1CD905D26B8A3", + "BEE7834E3ED658FFA53BCA26D6E90C56", + "EF9F5215722D6A7342FF49970281BD61", + "8B6F2921171B36A10A959B9675FA6CE4", + "FC2C7EAFED94B7AB4567311F4C382CFE", + "D54E275E9D3478076D9DCFAB27D04D2D", + "13F4D7EE9864301249B9E81569EA92CC", + "F16535A71665030B4B6D0CEA43193F2C", + "0595083E54727696543DFF817FC4FAB6", + "4637DEC296CA0DBAF12E768059F7DAF4", + "51BB6C7A91C313E4D86B82ED576721E2", + "340E2C09C496C741A53196634B196A66", + "EBAD604CB673C4EE80B2E6418154664A", + "D3F22A6A7A4B403BCFC77A115BC21149", + "62D581EE1E101694256929894116F536", + "4894FE0C8FF92928BD5784CDF4336301", + "8C270006AC786F0E6C36B0ACA1AE3F96", + "4221D4C855970030DEDC5B1D83955148", + "B9A426ACB42A4A1CE77C883D1DB6B7B9", + "E1CA07ABB12779705DF65AAAC6E14960", + "25DDBB8E5057EB692CA31368F635C866", + "951CA678CD9EC4AC5EED964F24B7392A", + "65E902DA59D18F6734497B92D01087CE", + "C32FCD143CC7C42D79236AA6F4EFB734", + "FC34836CA626AF8B84733E5EC7BA752B", + "6CE02ADB64E87DB26981050E7BAF6BBC", + "5F560EA04C66BCC54387AC75C01E0006", + "C2365838B538CB1C19E6B12FA571A4EB", + "AE18340C1E3D74ABE61FDFD5B8999D56", + "B38E9AE503E6A203CACC7452A2D1541B", + "163BA06716C4FF7219ED66ABC030D2F5", + "08A83A2C75ADE1F7F2EFCB71B1DCE52C", + "514A530FBDD6C097B8E418C5DA7BE41C", + "93D3C2A4EA6C50C83172DD47D1B966C5", + "050E7DF64E9B1DBE3FA8CF43D4B3E807", + "110DCF3B3E6CA76ADA1D0DDF4FE7A4FE", + "477D1A8C98DF1127CBA58523246C5B79", + "A32CB6EC4ABE01D33501788132F36AED", + "6418A3FF584BCCA654655D88CFCE4355", + "6BF7CE75D798DEED004DEBEF04766B9B", + "570AD02B1B15D79EE15EF0125C2CF87C", + "72F81C7151EABC7653964D387DB4BEAE", + "BBE297ADE2585A6DBBE48C2DC8B1A8E8", + "5DF2C0CDB44210F7ABFBCFC2151F2CAD", + "1B501C8429416FA3F4C95B1B16A19538", + "683E0A0ED2458ED8D72F6F200DEAF73F", + "BD96EE98A9371E8FF5A6BC7D44C8DB9A", + "23BB4D08D3A0013D9F2B74B41EDFAB8C", + "51B3808B2ED74211A54B720F909C0705", + "E3694055B626734EA522F73AFDA87731", + "32D3ECD84B9E71CAA1B777E7690D2323", + "997643B2C4CEE981F32D0C9F4AE8290A", + "EEBB94FB64FBB29EBB9CDA39C261CEE6", + "4CC9EB85F000B243DE38B51E884C4ED7", + "54E3F4DCA8D8E320CF431CAF0E39E4D8", + "92F0F4574951B37E7CCA4B25A6B0CAE9", + "68D8E6AA34295370C86100217C5845F4", + "E3310A0AB7BDE72FC0EC1DC21CA3CD0D", + "618BD29E8F0EDAE58DD38C66A93A484F", + "999ECD3A39452CBEDC8A66A90FA0C340", + "CCDD106B009FC5354EE3D22323E9C920", + "3468AC3AF2A4A30E8859073082198297", + "02A9E0A13A64514B3E341490F2F39FE6", + ], + }, + // K No.009 + KeySet { + key: "1032547698BADCFEEFCDAB8967452301EFCDAB8967452301", + ciphertexts: [ + "2D3284BDEFC1FFE021B9D5A54C1603E2", + "0BB0EC7C00548CD17A6E63806891644B", + "470D25A5D3FE0723CDB2DD6BB86C6F21", + "9F8C1299325ECF242348123706C3BD0C", + "65F058E530BEBAEAAD91D16F50FE58D4", + "E5ACFB46BA214BEEDCE9CB1F4AA96424", + "3A8DA9C08B31461F34A96C7A5F80131D", + "9D4C392FBD48C48E3E2CF0CB118E3051", + "879F3EC2F247BF4FEAE1F03744ADE200", + "3FBAC2AC754C1E8A1DAD08FB07EAF689", + "D092B19DD7F3E8A98DA682FB97A5B7B0", + "603B077CEC818D28664D2E87AF822AA8", + "2652B9BDEF6E6216B50D8430761D9418", + "9E590A4BFBDEF70CF9022DB11BC28165", + "B520C41DA545DF16E3D3547DF477D01B", + "A7C854DC42AC14E9B5F3EA9A155A58F3", + "DF62311DB9C223272322BACCF20D63BD", + "A79F8710C75AF7DB0048C539BB88E262", + "6E53EB5FAE9909F1317DE009689616BD", + "38C7E55C91D137C35D7C67D630D0CB6E", + "03C76EF3DFA83AB5E3DDB85470019EBD", + "0B3275B1C106A5DCE09C29408A1F3CF3", + "D9425A30359E21D1FD89F697C0FECD4B", + "3025F8683C3ACD36247062810435BA06", + "A622F179484BB51BC070C898AD254EF6", + "81E2C96E631E72D1DA4D92C1C8750D5A", + "B64CF737A6E4A1569B26F4D4FB875C12", + "C2CF7D54DCFF74C2EF6B7092B0FD82F1", + "E1BC7833C30BC32544919B1BC0BE48C7", + "B55DB74B0856A43CD37120013C8F7035", + "53571A8770D7A44DC2494072559A839E", + "CFD47EB1CE3D3833388EA4D5588FBE58", + "7D9FCD68CE2F9530FBEDEB282587085C", + "2001EE8937066AD0A7F0D42D428DA29F", + "ADA0464D533C791265528F7F0C79FBFE", + "C19C14D6875FC712C8E53F3D8F442628", + "D136CF1D85A5C45C067FF4EC6C72B30C", + "157B693832B656B2E31DAB9620A36229", + "0DF4CB2DB8F650966A4BC0B267954FEE", + "D82B3012C9B9E387A7DFA681048DCB7F", + "D71E7841D6D036B6653BFE799E96B066", + "5F92ECE781D3D4285AA6A08CD9AA0B02", + "036642FFE3DA8516A39170B08BDE94A1", + "78E0284D53E3DD4EAAE4F3734F13CAC4", + "4C800DFAA75905B9A84F7DB8CC884AC8", + "FEAC6E454D828AC1BED6167CCAE60AAF", + "FD54380701E4676231A246119668B558", + "07AD7F37D65D2A74B959EB4758345AF9", + "558092EE6CE885DED0B7472A7317B198", + "2E182D73C4BFFBA7FF8789D4DD66CBE3", + "6D53E3738C01A596050079FE6281C67F", + "F796B7D4AA1440D69F047CBB092EC090", + "4FC8865731F4479A0077426F7DE446A2", + "135BE9FFAC3B32E669A4A8C42974A851", + "E8F9D2A164F2D7A49600DCAC89BBFCFF", + "9A20423A7BF658F9E14CA9BAC79F3270", + "B5B49B561E5209818FD7821E1195FC3B", + "202BC0320F2F9E0406B121B4C3CD43FB", + "5050198B61797C9B01B9EBE3E35B66DB", + "1F1E2337F1488D04CA388E0E68CA348D", + "E8042CE4990F3EF748818F092B14C426", + "AA61C375436D26EDEB2A9E2F6605E9A3", + "B20FD0194ED84C0C216196DE61A55C20", + "D9E634DC3BA54FCBAAB837D1353D3599", + "D3B8011D64C6EBB78214CDE8D5740119", + "DCF053840A542C5B6749B4EC44BF25F5", + "EA179A76CFF3A831AD9299CF1CB3C317", + "006F1460EE9D96A4CBED0E7CCE6D3F1E", + "EED2E052A6ADCB790D2E954AAFFF07BB", + "87B4415B77F235883E347218A08FEEF3", + "163577392574A20ED9C5159C7D2C3FA2", + "CD8227A61603EE3000E425B93BA070E2", + "AAE16DB0130CC9DE5ADE163E996B7A76", + "330B2EC37C189D7BF66D00968AFD5FE4", + "FA6666E139B6487630933447A541FB24", + "CCD84B2739E3E3D3476BFACB0113C42F", + "091581DC957060F414EE0628C1352D40", + "1BA6DA5397A234E15F0152DF5FF4727C", + "4A5FF51C1BB02B93556D2126DBB0F67A", + "9A1178ECDEC01CE420B7D7BD9E63D7C1", + "70B6AB39A48760C72EF2EE2BB2033AA3", + "B434F1FA38F2DA9ED06B8A9C06E1AD14", + "9965EDD17603747CCB741C665E2F044C", + "FB333E7108E4437F61BB3468A6F41FA8", + "6AAC29B4DE8ED8D4A397FF917C15CF2F", + "F0AAA9673F05E416479CF9A5C219DA22", + "CB9F7AEECD8FF13B23E1DB2D9901A9AD", + "F11E7B4D5C3D4E2549478E31CE4941B9", + "AA80E0473EEDD52939127DF966DD89A0", + "0248E8DC47C29553AFD0DE8AFD123964", + "41F6D8EA76267ACCECD1CFD031FDF484", + "45214F9BB65BB16C723E3C30708ED1DD", + "FB99403CC307BC1BF6BE43ED0328DE79", + "8E76DC2BB2584115572FA999553F7D76", + "536FBBA25EF18BB9873DB2C3CDC0CC09", + "55AEC95558758CAB9AF6AB073E8B1AE5", + "A5E3D745DBC5F493BA5B990FDC65874B", + "47B74CDDA3ADD925E9456C55B564D5BE", + "00EBB4C4E7F691EA070EF7464A296D57", + "02A847DE8D682D315ED59FE1D77926A9", + "50EFF1D1A97A0BE01C338B9904F86173", + "78C67E6B2970CD1FFD2C2595ADC87E78", + "9A993345F87CCEAF2232CE0AE595FF49", + "529F094C9D244F7CDCF131712A056E34", + "463D4C1E393ABD921A966906CE335E26", + "8558B42A44DD78B40F31C75E21B8F42B", + "32F9AB148E2A9591983D2A9FD414C508", + "EECC3DFB070AFEECCE6E4BBEAEA0D127", + "78BD2E3C953DF0064746085BCFFDB51E", + "F7514DD2E1E5BE39E20184CC72C81B84", + "CC31EC8B3F7A95FB52D28B2BB9A23071", + "94CFDDB232C72652512BAB0CE296BA95", + "09C27194F0DC3271A324E16BC65C984F", + "9A3D28182D195C433435A7BE5B76B335", + "DF425D426F1797E73B364414470AAB04", + "C6A744261501AECBCF8F406B474B5D3A", + "E11DF05FC7CA156ED97568CC44083A62", + "C3EC2463E511D7C0852F82980174603E", + "098F34E21D86A518E6CDA9450194E894", + "1ADD3409176913D1DBB10CE7E03E19C3", + "95EE10EED5D6A0863E8B21C945A9C7D7", + "46D01C301942D58388CEC3E7298B0A12", + "CF6CEA3EB42AB3F0F53336E55E5BE15F", + "A002092044D5919438E9BAD38A24D1DE", + "424117784815F4E0E17A00790A485EB8", + "97EC0AC78CA02073BDEB8E45E9F82F91", + "DE41C3145BBF5074EF3A0C3F110B4E40", + "AE42C843C3FE3BAAB8037506E7823A09", + ], + }, + // K No.010 + KeySet { + key: "EFCDAB89674523011032547698BADCFE1032547698BADCFE", + ciphertexts: [ + "1B6D3D823EECC0C29ECF09448670F6F5", + "C8BF0EE51F4CC101B8F7A1102DF737D8", + "9039554E55B169438BC50ECEDF1376F0", + "46E0A24B40E9CEEEF189425B59E968FF", + "76C0C93B17E93358BECB8618897BC3A4", + "8015321DA57D4912EDC31B8AC94DC96E", + "125EA3BAD64BE4D108E67B60AC34274B", + "775C0A0900AA828C06A8AE794260DF31", + "02650D837531E8694EABDCC01328343D", + "3C23CFD7E87C1FA4EC632B0B00563BCE", + "58E52A5D1B1E81CD0CBD1610EA40D845", + "9C55A8236EE2BF4F55528D7E4627033D", + "F7704328346B43FF19811B72BB8A477F", + "79B1B5874AEDB3AEB2E39F972F5E009E", + "CE745DBBB90A9E8C52733836004FC302", + "EECB8EADE237E02B456A38600CB3DA72", + "38F5254D336A1F3D8DC9BA83B2B580AE", + "6A69C7E188F5D4788CE8D0236386BF4D", + "3893482FE5FAE8246BB67923F00B12C1", + "06B8E6746B4388B70DC3A0337E8AC00A", + "5F8F45979BEA38B8AFC6191B6CFF5B4E", + "3149759C73E8ECDEEC8DABA90117F421", + "7ADB7115E417E3EEFBEABAB01B0B54D0", + "90DD8631F791B6F7FEAC8A5880034B24", + "1D6017954E356A11F3BAA55BB98E7A52", + "3CB7B6363B59E6D1A5F56F0A0F085433", + "A40EE9D914978475964E28405ED749CF", + "DA66984DE313D46950755E1CFAE3A12B", + "F8F25834467F02E309BF780E809BC47F", + "46590CB9D724BE0D2A19B72D07111BDF", + "4FDD2F76D9A8975B410CF1A3A8AFFCA1", + "30E316CAAD8A054EB36C173384DB4224", + "4AAA9A53203243067446D4765A0EC1A7", + "B815095F92A8AC1978D8DC623922167F", + "E45E5D3B39B0EA8A603294204B350AF9", + "739287C6346EB9E60E3CFA0853A6850F", + "9F6FBAFAAD1C8B4C333C33D16F769F2A", + "30F6B284A92B5C65553FEDE135326126", + "6F04D157CF3F82A440AA9A96FD560588", + "E5A4E2330921A1EB8FFE21AB1C2C2513", + "06F9A947C43567B0B3B901C1C9FC2D55", + "73977E6FDE76A75A2DA3A1FE0B37B63E", + "BC973003938B963C5A97CFDC69716099", + "E8A3AA5771829D159A893A8F338B1554", + "4919FFEB8D764993F8FB03736221283E", + "A34D89B23856E0A729B2CF70CDADD278", + "E879B4A674178EA57AEC198F77FED9B2", + "82B4B93E6F83CA49EEA2512F122D2690", + "D930DCD7F97A2460E6E5368A876E75DA", + "325C840F283828DDF25607C2F884D364", + "9D001F8DE8E6EF4683CE8F6AE6EA476F", + "3315D69CDABBD0E3ED35B5953B1C67F3", + "F65A0ABDBCA794C8FDE7B0AA4520708C", + "ACE5ADB7982EB3D90FF6FF44CBCC2ACD", + "459A28405872B2CF7DBBC355E137F2C7", + "72B4805C14C75F662070B9498FC3F3BA", + "4939302040DCE30127245F1D9FD4B28D", + "E159FDB1C1E2FA1770A01F073AE1FA31", + "203E33DCD203DEB93BC1B7D605FC8EA0", + "036F4544F020064CDAC7E2C208AA08D2", + "59B01C9E9BAE566A997BD513C661BB73", + "8DBE7E21FC8BF9CB9D37DEFDFFF46951", + "4A4F443EEC4007C23BE31C6622656700", + "D4CF7365C75AB184592C57F24A6F1D93", + "08B03581099F2038D8D7DFF1A67D7751", + "203A9E8E1BA0D6FFDB81F6B9951A3C0B", + "36EEE62244AC098DA5A7450EC1E20406", + "C0B2D3173EB145335E91FFF625AF006A", + "9CF6E4DA01D35B951915F11311263E88", + "9EB4515527011778434ACD923F154BF5", + "E40B3F28A77E40FABE919DCD7533179C", + "722FF579EAEF7C1A89B50A1331215EC7", + "A79BBBE0AC571A196DFA7EC0A63A729D", + "DE288AED2C41CC9EEA5E92802ED002F6", + "1F8160E72CF2A1F99B370EA29C95626C", + "85E4368DC20B150D78A1A6200F76C5E5", + "791A3522E39CEB6CB8E9A78BDEA9E7DA", + "B4E7F7CBA215368D2664083F437780DF", + "FE2FA429928839DA3AE054D63C2DD93C", + "61CFEA8BB96BB0CE4BEADB71EB0F410C", + "0772AC6A93888A0C27294B4373243A65", + "D9574580E7E1052A6470A91664346E34", + "850C49C2997E3EC2A8E1B3CB87FE9E3D", + "4C652A1C978587E8F845493AE9F42C74", + "9003710DA743077BC0AB9048CC9572E9", + "CAB7BA7B65AD3B73BD20AA1541721922", + "1BEC38DBDCCF9013F97206ECA77408DF", + "BF9C1CFB49359ADCC43615671E22DB7F", + "4DE33DEFD5212935434DB6E54A0EC3E7", + "52D6B71A26ACB1DD10203CFD0C647531", + "76BC1861E7CB8622B4FB9E18C78F96D6", + "4AC779FADC4AF49B174DAE26503F9DEB", + "13276CC603C166C1DD9707B6473262A0", + "72FD62445B14E685389AF0474167FF12", + "A0754BD75F111945C7AA408A814C02F6", + "31E8D69833F484900904CE1D7F0D005C", + "0A116418847FED0742C3B84D632A16A1", + "DE0133FFDD29F0102AF7CC4C140B7DB0", + "C6F84D09020126CBB548FA1D95A33EF2", + "6939AE05C9BCA4CFBD5628A5FD00900A", + "5D900C179D571844B854C9E6651951F3", + "F4C7827D5E02D7FD766B97B93BC3C7E1", + "C203B1842886BE151D86A4C77C7D069E", + "E8503D12D308FD89821BE0BDF21075A8", + "F730396F9F11ABD32D38409B8431494C", + "9347713D9B0004C401D8661AF7D9C799", + "5D4B3E6C5F1F96702802167408918879", + "8658D6B7296A294A1A171FD9936E3061", + "9D4DF675D4EB51DBD43260FADBF44511", + "47A897FE82E2EDC1FF99A0B55716E033", + "C342B3C25EA3C6F501BA6A561E36967D", + "9D9CDF48439F2A0CC432243CD9D8667F", + "95D58EDA851AA9F233AAEA7A45869D7E", + "D846B65806E17D1875D14484DA45C28B", + "03625B4CA28E883F0522F22AAF0D2AFB", + "F881991E16BD9BB6E7D66EAD80E97B58", + "A78ADC2908149DAF7B0A061698D25856", + "119D096BE52A527C4097EED7F47292E4", + "8FC76E1DEC0CB98D8921A85E37D0617B", + "6B9B0AD177FA86866F08FCA2290F75C8", + "588E7EAA6B12A57CC85AAF14645A0AED", + "9CC942FF0F0C15EAB3FFBFF260D08335", + "9C7D95074BE9A394D8E948D23DA54418", + "5CC760D3FB3C017B9066E75B1A14CD66", + "15FBA8DD215A0A4BA99D84550094BFC1", + "4406C013DE347A8797FA267D58951AD1", + "1C5FA60B9718D625C3D7368DCC9EB050", + "44AE0AADA74995BE0FD47EC5DA6F862D", + ], + }, +]; + +/// `Camellia with 256-bit key`: `K No.001` .. `K No.010`. +pub static CAMELLIA_256: [KeySet; 10] = [ + // K No.001 + KeySet { + key: "0000000000000000000000000000000000000000000000000000000000000000", + ciphertexts: [ + "B0C6B88AEA518AB09E847248E91B1B9D", + "B8D7684E35FA1DB15BDCEE7A48659858", + "F0CAD59AF92FBB79F36951E697492750", + "117100F6635389560DC4A2DA24EBA70F", + "DBDD62355553019ED84C35886421E532", + "9CB8D04FA506F19848F7B9110518BFC8", + "E4308E253BC3444D293500701BA82C6A", + "EA2FAE53F7F30C0170A20E95A068503E", + "14B14839EA221880B2C64D1FE000B93D", + "A5CFC075B342D5101AACC334E73058BB", + "477EA56B2EBAD0F8AC5E1936866560FF", + "107E8598418404196EC59F63E45B7F6D", + "FF6A891E7C1C074A68FEC291928FDD8D", + "F64C250A13F45D377ADB7545B2B157A9", + "FAD0F252086F11C830C65B63197CBC38", + "9DCB89B209441F02AD0D25C6AB826629", + "E62E4ED4E4F34EDC563710D960E09D4C", + "98A1B926BA06895C3F2E84CCBACBC356", + "29BE0BE4DB7F4D196718AEA38F3B0BFD", + "F670C4EBECBA0B43E71F6D752BFD4854", + "7D7666B4484CDB7E3605468E093A787C", + "562D06B181C091DA6C43642AE99460C6", + "AB0EFB5975E6186B7D76BC9672453488", + "10C0756538E7BFF88D19AE2B1F7B859A", + "AF7FCD5248F8C72F1695AA05DD1CADE0", + "9841E555655609A75D7BE20B8A90EF1E", + "27F9546E6A1B7464780000561783569C", + "8671D935D7A8354EECB7288803D42D7A", + "0DA44F508DEBC6F044394624FCEB8EBE", + "AB137369BE6D93FBB18006BDB236EC09", + "EB90C4E597A7E1779FFA260886E26F75", + "618CF3588D5C128EAF252616230E08F7", + "98DC4DB49D197AB9152D12B9DE2D73CA", + "5BDDE24B15702A35E1F140C57D206443", + "CF755809882BED8BA2F9F1A4ED296A2B", + "F1A8DBB999538AE89D16F92A7F4D1DF1", + "775222FDDAAECB81CF675C4E0B98179E", + "12A648CADCD153C760A965826683119A", + "0503FB10AB241E7CF45D8CDEEE474335", + "3D299C0070CBBD831B802690B8E7CA24", + "33105BD4D11D66753DC34D128BEFE3F4", + "5EFCE2B4B987C0F77D27B44836881682", + "7835449454128035D7F0EA99E327577B", + "27BEDDA0601BE35122FB1D272D73AB3E", + "54C3F99FF48E318CC515EDE75800C4B3", + "C627C329F8E48299F6FDB23B9DBEA0BB", + "1B6578F9E23BD8C1845A02431C5F9AA3", + "6DB2FB8C0B9344D0547C0FF1292020C6", + "4FAD9B2C37C131493FBEF53581FA4F83", + "47502A01E93D2C87BD5584F6AFD3D99D", + "056E1C6F651BFE50271B3B7A18E76D84", + "5632BAF6627B3D96AD4E06FA6A561F55", + "E29807CAACDFA2D41A7D9E91FA7FD8EB", + "81DD44BB5D1822DEE605F9E6FF01D7B3", + "5C3649925E47D7FF96482A8FBD9666FD", + "695415A836E66E737887845EC08A1ADB", + "F5416BCE292D9E2CEA5D1CC70BBAEED1", + "7AEC4F1388FC29C47F7FED74ADDE8485", + "82A9F1A6CE08BC4876E649D8A8EA7EB6", + "B6296C88ADF1A792908B065EEB04BFC2", + "E766A39AECCA40BDBFBE6FF3FA292913", + "C6D081454EA00D83C23B5A62C84359E1", + "85D259A79CCA80484504D1603F7A8F53", + "D8291FA1C6DC250078824B2D0A20883F", + "95387CB74C48FFBD1F8D64A6CC45E074", + "A17F975F538F56CDF629B516011DE837", + "B50B615A1654C6E1CB6AB33716C097FE", + "7BBB2CBB874DF6C8B821DA7FB0F9011B", + "E9EFE074D096A275E47CD2E6206DF6A1", + "88F2F8D5A836406AE8BBB98C65BBDA55", + "F64620D8D87585A3EF038B9AD58F5EA0", + "694438EC141C8ED5F2F898B4554A298F", + "3E6226EC7726A1EE5F5FA9B18CCE8C44", + "8AB6949E79911647800B9E87362AB97A", + "093C5CF24EDAF7F9F1C8A80DE4FF50A9", + "28A36E50061F19E240351ED0E378CBF4", + "B93BB36CB88BF26EA79198652AA51D3C", + "DE4948083D044FAC9BCA6DA8CD67B8A6", + "6E778B5BDA6CA118117E47470D080D3C", + "0A9107324DA32B4281D032A3487EF875", + "18ED5635312D71ABD123CCE779D4D68A", + "2E3C63F95C4BC1F944BAB06DEDC9AA8E", + "ACCC869EF07004C8C3C709083BE7BA2F", + "DF60B34FB1A59147CC1FB049C1578206", + "4228DC636C08E41021054AA0E1E2227A", + "7CE27F66EFD735FFD6B3E1738C50495B", + "F8E74B33A9CDE351DA0BBC06D69093D7", + "AE0D22A5B37B8DC5D81CC641EED334D0", + "C181C6CA5E163743458B9167A0B6A16A", + "5171F4F6095E4B276CFBA1F07223FBE6", + "2732F4D3A8C9D1D8D493840D6E0B864F", + "3EF04E0059A061D973532CA5C1DFBE7B", + "6D9A8F23579E4978EBAA87B5ADEB77E5", + "BBD08873CC44BA4253C0C41FEEB7F124", + "72E4B2437CBD283F3809CE686F6A591E", + "6E5580514B92512B1BF4B1B987B9AA1B", + "5EF5D0C5BCBDCB604D3A083B68CE0FA3", + "9D991FDD723AD2182777A15CA0E0F665", + "24440626EFC8F86BEA7DE78085AB8A22", + "17C3630D62D13C1E826C0FCCBD74A864", + "4CF5AB86A56AB134A7FE46CCE3F9FCE9", + "3E6B9C0388F6D9B8F458F30221907607", + "AD9C926B8A5CD98EEE88200617E59958", + "AFF8AED5E075E02AF720CA4BF0028B3B", + "D90EAFF909202BB209BB3BB8C7F9A954", + "2C709B00E6A22F00F64A7D8EE341853F", + "CCEC598F0D9F0BF201B2F487136D54A4", + "73B2883A0A166AAE1BF14E60A5195FA3", + "E676867BD9AD5EF915143388496779D7", + "CDCB73D1BFCFD4BE7F1DAA9B1C6A4055", + "02A3A5C89DAA24CD2C517F7A73286A89", + "C0FA2AC9E92EE58C2DD12D6D43AB7035", + "EDC2CB1F7291353BDBF2385519E6AE16", + "B4B62D16D197A98CD3B978812B9D9884", + "5CDFC95A529A905101CEA26BC1B891ED", + "CC7150CD3650B98363296C7C4ED368D1", + "CC57706B0C6526B8E25A5DBD32EACBDB", + "30D30456AD98B182D64C649648F6AEC9", + "D7E9DA7F631938EB649A08AF82FBD75F", + "B8DA2AF6600B07895B5D0FFAF4991469", + "0F6F64F930BA6C178943322B98114599", + "8B1F247802E47C91BEE2AA34ECFD7A01", + "7A6985778D3A66E97F23E01F0D0E45E7", + "BA664AC39855518DFDEE10D1B3111FAE", + "7C92854D801A1648F65CA81813DDBF83", + "6A3F25AAB7E92D9CF378E5D9C040F26B", + "3D4B2CDE666761BA5DFB305178E667FB", + "9CDB269B5D293BC5DB9C55B057D9B591", + ], + }, + // K No.002 + KeySet { + key: "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + ciphertexts: [ + "915FFE45872FBE9C737B485F121986EE", + "266B002B53F3D641989ECEE1F050FF8F", + "4F984C2BF268E0701532C3481E21DDC1", + "9E3B0D720BB9A25773125E9821D50F00", + "41A664B63CF1774709558AD0EB8D49F6", + "071F107805E03CAEA2F14268B15B6B16", + "8869F10EE3E6B053AC05A8F8C4B7DCEC", + "84904BF50126247016287EDE88850859", + "74C8B71911F252BA246895DEC299BAAA", + "967AE5A17214EF9005FD752B074EF7B7", + "4A19EE191D582452C873E827E7291A6B", + "3803D230F8788C240E785AA1E8A4035C", + "36808E389D79C1BC094D3E07B3FAC3C6", + "B9365FE8FF98A8DE766B27E8A2E2EF0E", + "88C6C9CD2CFAB47799832D1B7D9E62A5", + "67BEDB721993D03F50C6201F079AEEFF", + "A18F1E13B3910B0D639C2241DD8C6C6C", + "F6E3A6EA07C62722DF3ED8A5FFBDBE15", + "01A9CEC27B476ABBC8CAE1C75EFCFEFE", + "B85F5A0FA60F93981BC7CEFCA585BFD1", + "B4FBBF7ACC0C5FE9D9A6AABEBD5931E2", + "6EAA98394EA345B9E13681F7A9674AEE", + "F87D94697872924594F1E79812C62F8D", + "7F0C689768BB9C80FBFD58A1F83C294A", + "660D1207726043282BBF6848F9301BE2", + "81443AD48632D6613C9547CAB4901299", + "A01EBBA3FC1D27733E0C0B715B50862F", + "1B09F7D68C9EAAB05ACDACB3209256DE", + "F0F81476B7801A35E7258F5F8619DBC5", + "8259E2B63C5B9E254CE63088B216D48B", + "59E85D2845AA379EB3B354B24E70AF48", + "6CEA68B77D6B20530147F2B878B45721", + "534F2AFBCF8DC7F1AF5EF0679E43B419", + "D1407B53682D77EE880F6B4C5B20A59D", + "64910F8994B57741C66476180F636B8C", + "0710C5B82329AF3B6821BDE8F283520C", + "8BE1EBCFC03090652BCB8F977C38BCF5", + "BCCFF2F223FC4F992360BC5876889067", + "CBFE0CA3329E5880638C980FFF723A9A", + "888ABAFB00FABBCDE3CBDF07104910A5", + "A6F4FB56B8C87DE05BCF3534B749E7D1", + "B8686C21C08E5B9A3E200719E27AB869", + "5E7C624460E0CB33AFC3B2CD5D0516C1", + "981717E6FF30D2F902F564CD3413E148", + "D839D7D4B6A156AAF0DE054B0884D1EE", + "E830AE003C1ED4F3170BD69594AB832A", + "1355F645F9E10432FA8298DBA6790968", + "DBB728B54C231A45ACE03252A0C04838", + "42FC300C13DA2D379C8FD28F43DEF93D", + "80AAAE8E6426A1DDE502C1DF69C03BD9", + "86928C745B8B889F7F807BB72EF8B45A", + "4BC5201DCA6831C4F61B6FE9D5FA74E7", + "21194618FD63AB1EC1AE0146E2C57927", + "AA84C737E71564BA8C2562D24A9A9749", + "5B830FDFB6A5C4BB2F2A8FD7706C86C6", + "3B6F6F015312F2CB6B93736121B1B08B", + "62DFC5F92E31CD3FEF9BF85DAE159071", + "C88BCA92DFE74BDC2F22276E1B10DEE7", + "27F586E50EAE85B6CA2DA4E9D1506DD4", + "6A9655A82082949170E39249A76B22D3", + "D92130814AC5646834446C1E8F3FBDF1", + "CAD084DB81AADD23BA773C32B2F41A2E", + "D8A3F5CA2454197DF48CCF4BBBABCE7A", + "FDFA13AE67527E3005DF4DD074E499FA", + "9C92552FE4EDD3EB669E374E544816DD", + "4EBD99D5835240AEFF74608F1F86F00E", + "8AF93C8BE96CF63CA7C8A6CD75C83EB7", + "60CB10893D471D0E78B8C6D2E036333D", + "9163EB29100EB0D37776AD29A442FFA1", + "DEC59AB39213352B9A1777D0B7D1A9C2", + "63E2D7DB51CE7A75FCACDF9F7BAAC7D5", + "8AEFD80991B12C47E754FF3089D33E8D", + "16EB2ABECF4479164E0E56EF592D4D81", + "9E71C0F262A1BA28A13FD653633D5D19", + "8E0001434219642ED5F598E8FE032A05", + "49FE6B913CE0765C6AC2AC81D402A8B0", + "D4E58E68F12D410DD3CF72B6A6D7AEEF", + "EE336C8533A3D8FC84B0DF90ACE2FBD7", + "586C7E803BAEC8F5F8C25B7D7A646BF7", + "5EF0EE5A3EAA048374FE63C8A9DCE183", + "A2ED2202DFB9F21CA4B968F8373B9559", + "04C617B53B12041A0BA9211F6E906753", + "99A641F85FE68982C70FD41BFDBB0E09", + "542E193A1442707EF7E372CF3696F5EC", + "7D37FE7E51ABF48C6423525FDEA727A7", + "2976FD4DF33DDF4BD9FEB0C2E286DB94", + "A5FCFB2E177AE37F5CECA7CE55F80DC2", + "D5575E1E75FF6FFECA8F9AD8268ADA2B", + "6574CE3AB32C761680A0E5C6D3834F08", + "FF521BAC176FB9836BB2962D194021B0", + "78C8BA8F1DF042B0BC5E1D8161EFF090", + "2BC60B11D0D213B95F9DEBF5329DEC29", + "A590CED7D453B736E9FB8AD99D77F133", + "59D08CDFD10BEBF99D1295F8C1C3E972", + "4279007B8673C0D7AD2FCDFAB19CF026", + "01241263D8C80FA05645C9CAC488F2B6", + "2B934BD5E3B3B9705864AA80AE7B8945", + "747A11FA44FCC33FA03D8BCC1FCBEE2B", + "6CA3BB00D9DDDBEF5D6BCAC17217BB73", + "75AEA127396E2E741138E28D59FE620A", + "B11ADECEE3752509368DABD507837A2B", + "EC6E09D1DC127D1E4D4A11B00A6FE255", + "B4BADE02221D0E332CE2AE03D5A7D0F7", + "FEBBA3FFF0D66E09A6DF92CD9FA63BD1", + "774575CB17CC940129EE829266EFBB67", + "037791913CAB855CBE9CF0DE360A7DDC", + "464CD66AC300E23B7511DB31A00C652F", + "B4773D6CF6DF62D2D0E831FD5009C351", + "2631590E00F818DDEBF64B588F51C059", + "3685A5DF3F27D833B54576921C89FF6D", + "43AACB2159ACEC2C58FC9771B2A95B5C", + "36F8B3800070DBCB7CD1720778040502", + "EDCE7CF2BFC54D08E67A90D70DC87CDE", + "6FE36070E82945308A544E5D5B584BB1", + "3D77C18BB8503C9FED0FF118C95E02A1", + "153AAE0FAC91B97163921613F43C4A03", + "0673F49B1B31C73E97D4958F11167758", + "A4CC9F5C9181F2C9D6E3DC24AB337570", + "31170A01E72263C5E93B27B97F091C84", + "E07C9FA5E03B7B636686713BA538FBAC", + "1867E72DB4A9527242BA1E922DE45E51", + "15FDF11E7D2204F8F168299DBE93BB73", + "C9A040918767A666A1511611E1E6CE87", + "DFFCCEFF0AEB8D62B79DEAE025BA203B", + "0B0546D72C94405C043FAB39EE275695", + "1B87A1B276692B5AEA6F71A3663593E6", + "6EA2D02FF72D6EE8961FF9178B56D9D7", + "75F87F5F7EBB9D6F32FF453F2B934BC2", + ], + }, + // K No.003 + KeySet { + key: "0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F", + ciphertexts: [ + "56C9F9A2E00FB4C198C707FDAFE00D9B", + "D82D84CDF8DCC0D42B16265DFB269EC2", + "3BE302551C48ED91CB29CFDC664FA0EE", + "E09F7D1A8DEC902B70CFA3B262DCF413", + "A1AA0EAD2C5666E571A28E2C63B1BC16", + "38A724317E5DBF8901FEB2B50FAA8C97", + "E3ED7AFAD29153C48791CBFCA3777A4A", + "71E532EF96036280B9C53829C98C49D0", + "8B7757341B4794A27FD30995B7D5A9BD", + "DF72EE95DA0DEAC54BE2C380468DA846", + "4C3D60CB210D1465DC729AE728D0B219", + "8B0C6063C8F253131CEC2145CB4D0364", + "FD06CEE5E703517832ADFE545A6B684C", + "C3F3B93FD9F117E95DF96AEB8C8AF127", + "2401F38D8D00A4BE049B02E40DE4B61B", + "AC05FCF0C109FCF35881A7549220A2DE", + "69E1E66314EE577A0D2797802745CAB4", + "F824A2BE99D9D7409A3DCC8CF9100BE9", + "9CEFCC59432596262F50C4558B64A0AD", + "312CDAF059EB7C0AC2C92BE558E25977", + "F9C43DEA36A6A53B400AFFEA29C8C81D", + "DBE0C45EB31BEBE242F755E180AF377F", + "2D382577FE0C9B9CBF86A44518680A43", + "FBD62B02E8177E1A444AAFC8C23F14F2", + "C4B53D13EB45543D217D4075B75A62D1", + "1AAD29D11D4586C3ED1C6C47E1186871", + "58AC1CA5346839C4F0629B980BA7C304", + "D5A02152BE138F0C5AF0E1D3EEA11D9F", + "8DA2953CD847BFFF5ACE84C3C48B4267", + "6D1B41AE8C9622D3AA1B2B5F94B5F80D", + "EB18ABC5F8103820CBAE934BC9A08E82", + "9EC176D60E5850497C10C02C1040743A", + "84ACDAA7AD1D127C3AE06304398853F9", + "00FDD1D7D3CED03929B379BB780911C8", + "7684440548E8D7953F0068F4F9C84D82", + "8C28F45D7AA0C173CD81827C88C903A6", + "03AF26CE75C8C82B33B6C69342B5CDB0", + "B84B62803A66AEE43136ECC0C508555E", + "CA688D6B1F573539351CB3711F7B2C9E", + "C24A99706A38480DCC1CAE0423882CC8", + "3F04807DE268B026B89745BE193C74EA", + "B9B9B756AB49A648D136740758ACAFAD", + "2AB9DC582557970A48323DBC3D19EDE3", + "FBD7DA99AF0BC6468B6574A31643E09C", + "9E1F37EB95410E82B4CE55789935F61A", + "245B1BE2F79DE8EA483785A690EF3B49", + "57A1284771FE6F6C609E39B4DB51C377", + "6B6CC69632181849807D04497F4085A5", + "201AA81F2B034220573F076682752F4E", + "6D14E1CAEE1A6AB83C1BF45D93D8B502", + "DC98426A1AE69D4899C313EAE3FDCBC9", + "E7E0423A662FC74575F597C4D9C561E1", + "58CD473B00B31EF648CB684A82480BC1", + "64EF33DEAFC2F8EF7847C2B640B9A4CE", + "A0656B4DE9BAA3FE5169856B6D2D5850", + "A564E5976E0BB025E39C808A3B854E7D", + "13D05752B967D2FD460891B9D2F54C81", + "453158F0CC2DB5F9ED4DF4ABBBA372CE", + "C0DD9A2B337E932AADFF872E5B11CAFB", + "5C526BA4438981EFDA24E8B3CD95D1A1", + "DB091F1EBD5FACB16C5BE7061EDB1F3F", + "9931AF1B66CD6A0D78642CD2C52D364E", + "69C5DAEDDB050F639475A5BB709B04AE", + "F76D0D2243B9BDF2DF92D93BEB7451EA", + "30B604F1C46B0D3EB85538C5C31DA36D", + "BE9626156981DAEE2A50AC835F457164", + "F7E57B57668BBFA15003F7039F24EB78", + "F5522748DC6A4F31992C11520970ADBA", + "FF01C7BA8B8B73D76FBA065AA1426B69", + "D8EE042775CA92C6FD120771908CA52F", + "DA7F2E9FDAFE7FF505809392645B5686", + "F60304068D20B9596B42C39739676719", + "5220D6412848A1AA2AF1CF076AC8CE86", + "9ECD838ADBFF0C5B669290C9E9971B2A", + "673092206AA8AEBF05C2C68D39BD8059", + "11EF855709F240D798CC13CAAA5FA5D3", + "B22C4E250BA2067AC2C16E79DC4DBDC0", + "253D73BF7F3A6BD8BC19C2CB0B9119D3", + "549B1E0143BED714FB7B928DFBF07163", + "6ACADD12167BD4EA58B7F4D250470B93", + "B7A3EEE66E8D95C888FE92D6A59B66C5", + "961154FF5255CCB57445656C4D0586EF", + "F053A522D98AC21BFE1B9E4984018B95", + "C49A15D20927DE2F1865EA70266D9D44", + "5B4010F5004B9B69E04721EC7480A330", + "766DC99D170CAF823E466A5843E62302", + "7D1394106D296E9D3AA15DD8E270D877", + "E8C070153495AD6FF3D84D01F25B374C", + "22174D3D0123E125F4710B97C8261F64", + "7A6BA0455EE5AA025369E0419C26ACA4", + "031BAC5756E2994250DC8638AE7747A5", + "F63784E732F50398A849451330457FD8", + "3E755DB9276CBB6BD263111A32DE151A", + "E4A38326533CF1197C661F5A76DF82C2", + "90AA703A380ACEB736F074DD0B067967", + "5F471CE18FFA66E0CCAC4EECA92B23BA", + "1BED4592D1C317A9B6C45BB647D88C35", + "B3F6D84A22940CC6D5FF6B42E7AE4C8C", + "B789CE4B975D1E6E68AD43D8378991D2", + "65C897666861259A3802F3A45FE5F10C", + "8FF71F2E814669828A3DDC09B3F1FE01", + "1C6FA3AEB530981DF1B753E57D915E4F", + "77BD9DED1FA1E8B8924EC64730E53EE4", + "A3EF9C8C96359B2040C9A0D7322FBC71", + "72BE9C6C65B83D728095F3AEE6440675", + "E8584EA89402C3A2D1E558ED0BD226C9", + "069C8EFD5534DFBD5D4F271567F232D6", + "A3816231EDD50743C59786A3483DB5C8", + "F0261E6425A9C9D15BA57EFE24B16153", + "73247702A7E27EA4B09B65217A7A6CAB", + "15AEDD79EDCD483BB7CE72320C7342A0", + "37DF28DEEF66D57C3AF23F35D9BEE833", + "FAB6BFDAE5FF5C4EA57850AB88CB0507", + "4E83784BF05C9699A7879E9E8AD41A1D", + "EEDF8CEAD75023DB28A778AC09695BFC", + "95206CF7B7B0F58A734ED43A9038E35B", + "A87EC09A9ECB4DE2AFC0FC15E7608973", + "96C6F71FF9DF5AF6C281801D3BC49509", + "F0E56ECF81E7717847483E7844AAAE41", + "B97B875B0DF2610BB7AF1B0F5612E7A3", + "C28E61735EE8A9E270CCC4E59D44EE9F", + "26465B862B8C8431E7CC17526479AC10", + "81A1F9B8710B22E6B1A62823F524475D", + "B5C622F52E57755DCB3A7A22DDAA889B", + "84E8496745D1BEAFE778DD95962B991E", + "D186D1FA62EF82D9B3228D174CF7A0F9", + "55A6ADFA2D59979653A9939C03F1B2D1", + "AC69DF3894341D2713375EB452F958A1", + ], + }, + // K No.004 + KeySet { + key: "F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0", + ciphertexts: [ + "58B08022488EB3AB659C0EFC392D0594", + "8B9CC534F04FDBE051101ADF2390FDAE", + "D83ADFF0AA4DBB3F00A0A48A45F56836", + "3DBA27842EBD543FE47A808A6FCE2F53", + "4564D869DC2258C626ED8EA6A61D4086", + "234356DCDF2CDFF9147F22F597A269F0", + "FCAC7464DF7AE113DCCE8A8F587EE90C", + "969CB9B7CA5EB66EEC6A787A0CC10465", + "C238AB9ECBA2C95B86C4FF00A488C293", + "4E97A7A930B54887BF55E55539FCE9E9", + "F4386FF1DC440752955F49FEB426FCA2", + "FE4673ECB907EE0E2F27D45D0A82BE5C", + "5D9F10BA8402E13233959B520E2249C2", + "4270C9AE4F594EAC874731CEDACD345C", + "A91B8B7BCDAC11976CE0E369F275AF89", + "22FF6C3206A867141491782248590824", + "26C1198E4F92F954601363AE12D5A4B8", + "4CCD9A7E1B392BAE02665EEDDB442882", + "6F72DFE1C661884693D8CFF759E18B25", + "1EBDEDC8D52A57D4C420F043D6DA8E2D", + "DBDFF5A7CDB8C4C7BD1DE18DEFDE9FC5", + "3824059B1E4EE3BB9CEA64B85ABE55CA", + "3035A2445D4254961AB8047D316042F1", + "15C7E8B541E75022B65726905866E0A8", + "9D0548E96FACF8DA2598D220C3CAE9A0", + "CA9ED54565F0687A49385463D9ACA354", + "0AC4732F5F502EA823717195910E52AC", + "4470A086218E43E182F51F972D83A745", + "AA931838565886D0BD3145DD30E302F9", + "1F6AB4CACC7508EF7E0014D044225894", + "C31137DFAD18DA9842BC3DE24F2B6F0C", + "47AA4C60CEC2483D3BD18C31468596A0", + "20C022F33AC8C41D76765E1246F27114", + "F233059939C73989DAF5266B01B667DA", + "A261BB6128568EB9A21FFE0903880DEE", + "B4BF2079D2E705FFF1D128EC73EB6D32", + "E1786EFB988CD3CE5B57DBFCE23E7784", + "AC0A521E3B275EDA7DB24DE2B6EF745F", + "91BC2550E664D4E6FC1E49E545236A4C", + "DEB0B32DDECEBE21DFD49CF520209E68", + "5BCEDB980FAA87D9CA220CE757DD7AC2", + "B1B42414348F2DED6D41FA9B760D1064", + "C9293CAAC22B7CC5248DB042E66A4C15", + "E72ED6DD01D1E61D0761C487F6037551", + "CE725B705D8ADD57C1DC1DBF3BBED37D", + "142CDFF0FFEE94D77E6EB4CF05698267", + "A5CF8046BC03239A2134C135C4839DB9", + "3DA3563CD0E9F5B1191E9FDC5CEC792A", + "06F9AEAE5B997282A1148B9AC6BF5E39", + "31205A2C222F62029A4B3726A3BAB285", + "69CD85954D1F5BA4AA3C307E6384394A", + "6757BC667A73613703F509682437A1AA", + "F7655C6C74BD20808F652A312802A915", + "F1CB8915DF936C1594432B6F27E9DFE0", + "FF45C37F40B15462187D01DA075FAD85", + "354E4C2E6F3390F57B5A164A05B05CC6", + "AB5E082F9BCA1C367D3C822745CBF12F", + "1B2CE05D5559B3C8A52776DD8663ED2A", + "33E06DFFF34021CF769A0A03C04388E1", + "55782151A1CBFD02B81FC4F5227A59E5", + "6C640D42C279EAD6E415490A88B3B037", + "9D473A02A6525590ADE4AE211A965E8E", + "CB9623F69B96610E1963F1C18529DB32", + "03AA5330783B71A2122B4B55C84EE46D", + "6BA6EED9122F3C56FEF359D42F1E4504", + "45C676EEAFCD61EDF62C430FC1221D10", + "E3E72801E0F884B1AF42D624A3E54E54", + "A02EC9DF898B5CD30A83983ECE5B3E00", + "C50E1DBE08CD3315B8AC435DD32BF165", + "873343DE3725DB77FB4B4499867B7440", + "0808880A01D91D9B0E4A85E1716B9ACC", + "2C57438B59CA1FBBF9FF353EA5405DFD", + "39DC85D9AD7069DC108346E62EEBDB19", + "00B4B704F556BF3B105CFC0D901A32D7", + "A1864F8097C60125875A275A3EBF2AD2", + "9607758C722DE056128DE37B81EFFCF4", + "B988CE7A1F6AE0EFFFD6F8C8FC643034", + "74C2CD06685E12FAA50C48D2D9A2318C", + "A6E9E38DE0414C365F1EC32F66FEFC9E", + "DF2526DC24951347A19AC4D6F22C23E9", + "209F8A34B04EA56EE7BFB42B257EFABC", + "29F947F808CF0845F6D4094A3C9C9469", + "43FB25C3317C10D5A919F2BB3D5600F7", + "F5E1A9859BE0511942624AC8DE6725D3", + "B5AF5BF7705B8BE0C71907F798B33913", + "15842697A9EE8D99DA1DB78892E695CF", + "9E71172760C8949939C364E12F8A975B", + "B5F62DDB0ACEDF94CB43FFF9BFA3C9C9", + "52EA69D3BA97AF219B86D1B846BFCA34", + "20BC39F6F9D8523D4F66471F4FF9C540", + "7C7EDE0443F3DA7B0F670D2A2E7548DA", + "11D715CF362C83425878A139C73C557C", + "509892755060DAB3A3C5E710885A57B6", + "73BBF8EE2C530461D9120D16F42A0C65", + "49E0E134D44B3EF1558C8A913A86FAA5", + "6BAD2249B49C254F4971843BF8E90565", + "EB049CF7DFC82DE840F181606FB5C4FA", + "A4637760207765741BCFF2369AB193BD", + "D54598A364C66C91C10AE7AD3B3B8B10", + "FF69A91E66E24ADFA5685BD70D6EA1EE", + "00FC0DE40E3383A6A4BEF42C2451EDC4", + "99954775FC42301291976DFB3388954C", + "465575AB8C635CD66BF03A2BA3F50F25", + "C3AAF31BF735781924E4653DB9569677", + "95B03DC0D9F64F66FFF8FF7A51DFCC5D", + "E03C8034D5AB9A9B92C50F9DF4B5DDEF", + "B586550D912748153E9FBA8884853905", + "CFEA5D4F990824C1D41085CEE03DEC0D", + "BED31C97FE64A93F7CA2833827C87274", + "B8D852CF7C4578535E53174E7F7ADB71", + "C353D7A1DDB363FA101BBED1FE640FEC", + "407B696D87EAFB14CA58ACBCF53AED9F", + "7869FA37A9E24CF8A91CC9648C5A34F1", + "90FA7D13B2363248520C3996C06CAE49", + "F684CA206B5D7F283A84FF2D62D00D20", + "085E97D0F78828A627C38B29B60E3C21", + "0AA69F647878EDDE2EC2176B6917F68A", + "626BEC6A305A952CD9E91B79F20282AE", + "48CDF8339D6AC65A631E7720D4F9A4DF", + "40BA8190C50C04ADAEE784A41BF85019", + "6DB2F656BED4058E1845F27CE5B7B821", + "14955D8786250EF30D1BF008E78472F7", + "7DB6338F186A95FAD0349910A8C8E7DF", + "E6331F513B5AA5146E1FB67825815187", + "38F641061EE7E857D8F9ADBAC691187A", + "492B77021193B22F0BA4E6DC0E615E90", + "58F963931DD4CEC6BE5B7CD255F17438", + "480B08C64C70F94C9CEFD62CE1EE9092", + ], + }, + // K No.005 + KeySet { + key: "00112233445566778899AABBCCDDEEFFFFEEDDCCBBAA99887766554433221100", + ciphertexts: [ + "95F4E00F2C5668490975341B3792C950", + "522C1040AF6F7D2234BB38BF3616449E", + "D5C4B8925E83DC54DEB0E0F7C27FD364", + "3F145954AAE73C97FCA927A59D4CF7E2", + "86ECA015CD63FC5DE66ACE57317503CA", + "32E5F6D0D8D27207BADD687991B82F29", + "A7C3A6C7E02A45A25D41F2179E68745F", + "58E54E8268048826D81C839CFE48C626", + "C6F249579FDB288BFA2BA5D1495C6D66", + "8ABCA447285305F4EE0FD7460FD08DFB", + "32432FA2D858D74EB74F82BF76DC341F", + "FD779592F166E3070F7AF5D544BEE7AF", + "6114AEA782401472F5838677FD093AD4", + "7011CA8A052342EFCEC65B8A47879B08", + "F93D66041C9C446D9FB05B383AF9F5CF", + "FE3685A1F61F06BCDD605D21315F58F0", + "82FA91B253080886C39C735D1B1F3634", + "FF238050BF23776E264398CBEBC11A25", + "89EA15CC59F76409572E7271DD8DCF7B", + "EFD1326D96B972BE089BCA766F1FD810", + "EE2DE7474F6A0A291C43CEF03304967D", + "9C4CA17CA32147690523B7388A6C6416", + "286D34D6BBEE705D0F7218273B2F27F1", + "5565A2E136A5368C189AE8F1E6E89E8B", + "1CF4CC0A53472459C9F6A926C991426D", + "805834A474173AA19C95B2558BBCA558", + "A4AD71576BE7EBC28E20CE9C07423757", + "C1C43142EE0912019624E249FF828960", + "5D4C26EE84FDB9DB863B8D4A1C7A3DA4", + "611B7B1AD2EF5B058D67C22C3CAC12F8", + "3316EF3BDCDC9F243EFF49A7AC31F9EB", + "6EF267963693998494B58BD6DBB11403", + "BB7557001C6C95743D5F6ED3933FE8AB", + "7904F87305D01EF98EA04C10F4F632BC", + "06CA707A43398B7DBD6BBD49D696865D", + "B3D752F3F96AE881C0C5519FF80B4801", + "0D73FBC49DA9F1EAE6FF2DD69ADFD582", + "A8642770F49571C4F29947D2819964B8", + "A4D11B1A38675AD6205098D8E637C6AF", + "FBA13DB16A85F3970FD66D8C813807E2", + "C723E5C5053D16CFDBB7364BF50F809C", + "2F2D610D5D0A1B89166C987AC42AC991", + "F33203C7BFD88704C216F2EF2FF88F6A", + "3CD0D830029DA105F72523D63B64BBA6", + "589D08258348096C78B7FAEA27889AAD", + "8DF0B1E58940C7DBE22DC694C7438BCA", + "4109500F852482A00394631D5AC54AE4", + "EEB4CB59E9CBCD7A9294E1265A34385A", + "C27B0576657FE8F152D9801E9FFC5EE4", + "892957B4F8368FCE3ABE711DA300BCAC", + "29889787E0694319DA103972EF0EF471", + "ECF62B8F9E4518D27D43BBAB321EE545", + "C180134125E85D6F5E8C0925627DC57B", + "F79408ED515AF747E4E2B10FAE6AC933", + "2FF14EDB8B4736D666984B90A336034F", + "3E7B4B8A7FE80A0674D60EF123271DC8", + "DAC569761972D03CE2AE9AA513EEE0F7", + "14CD819F1914A2E6E8D6A995FE60FE4B", + "3B1DE37DEC61BA51E83E99251B59E492", + "88AED07BCEFF1D5B590EA091DCEAC389", + "AE1E4F8E04BE5C15DCB5B0216E988A25", + "64099D8F56772E8DC41FA0C72EBD2AD0", + "57136258B2A4E520FADD71A796B445F2", + "BA256ED26F4CDF05B85A514799E7565E", + "908D71E2CFE352E2D9D27F578D378115", + "C383AB97F39A1815B2A9ED66C0229048", + "8D1F78A8181B26B4800AAFEE8DD497E9", + "2D3A0FE4EED5ECFA7713C5EA045DAF18", + "E55EEA93C28C8450FA97311D42926148", + "F3D6AC462E902FA5099B721509C39DE5", + "CEB6FC27D4D2112F900C7018B9C92276", + "E316D439360735E95DE78D678B513593", + "742011DD18E286CC272BF9250BE48830", + "CE9C4F68B4E7ADBEC5162F93258B9B64", + "4961FC867F21B03C58677BB33911D396", + "EFA20BE0A26EBAF73F078EFD298BEC54", + "E1B92B426F1DE4187B6E3CC86D88197D", + "BA3E6E3D6A5CF1E3FBA6C6EE734F0FCC", + "BAD9AEC2FDBFB923FA1A4A5D6B19E51F", + "D23CE795427EA0876835FF6BEA10E391", + "44BC6B048859ACDF6E3C5D793BF3C996", + "9E42F561D3047F881F3092AEB6A32E71", + "9623539CEBA74FCC5C8C10491BB2262A", + "BC9B3521A14717B681D0B043A39329B9", + "62D32A23F04DDC7C2EEA3D5019F631E9", + "A724F52A6CD5D4D70A7B0D4EE65DA29D", + "6F6A72E70E3A1C7581EE40B201B43389", + "F097952A9047A2DD74A4FA527520A280", + "8D44736B36BDF298284A62F02D0BEFA5", + "EF39A06870EBF91D23B67775093E0DBF", + "1B6200E893C3231C71B7993AB1DC1126", + "34C892E2EB777A31BF651F4AE231A77C", + "2ED7F65E99C9E6A7CAFFB0958A3058B7", + "AE06B794AF4C68ADE38673A621F70E2C", + "188DC1053AD6A6BF78375434DD50C4E4", + "4E8040242CA0C30C009B7FBCFD461A77", + "78686ED61B63E5761A290C0ADD2C68E7", + "CC61304A5BD0A670029315CEA9244A9F", + "C5B69B1C8B957C5FCBDC0FFB755207DE", + "66930A18C0CA89FA2740D5AC1FC14507", + "3DEAD6340D9625311D3060F880DF3747", + "26A2FB5C1E537849908383752D03338D", + "6B094027008A5051C1D62A5F1CD12C55", + "FA8834CCA2CB1405676326E07F6B5E11", + "6907168544A305FED6755A92A7CD1D06", + "9D197F23A9F244FF537779F49D7BBAB6", + "C3A11E762514432F695C798801D00A51", + "3E39BB22CC8262AB294E30086944170D", + "53408D57DD6B5DCF7FA3260D5B5C912E", + "2E3480C6048526FF9CBF1DCD9DC6897F", + "9C791858677C1801C34C061D704FFA48", + "7A1F69ECAA631C5A28A3EE5351D926B9", + "5EC3521BECE185C7C82AFCEA69E187FE", + "28EFEA36360D5FADC45C43DDCA844838", + "53F7AE2C2203F3AA90AAF0B6945D11BB", + "4A4274F25766384844CBBC88C0F939CC", + "C7AE24EA047B9C4DF2AC3357943059AB", + "054133E97623DD9C303257D8F3ED984A", + "CC5F0025A1E7E0738E357CF39F781599", + "58F4645F6AFDFB83396D73BF6F723E38", + "EBF21BF33D6418E7BD81BF911A0CABE9", + "A0852EB23B8888D547063919383C62BA", + "43FFF4F8F1A3AB730E823B87F695CE6E", + "8BA74A3A3D05FA497DFD1AC1B58C6204", + "554999F11083E6136A5D8DEFBF76D658", + "C9FE7B1C986CE19600FB22A984E3977B", + "EE003F8CFDAE51A33A921DFFC79A25A8", + "CC39FFEE1856D3EB61025E93219B6523", + ], + }, + // K No.006 + KeySet { + key: "FFEEDDCCBBAA9988776655443322110000112233445566778899AABBCCDDEEFF", + ciphertexts: [ + "2E13E093E0AA9BEC31764AF20C2A15AB", + "13F0FE575D8ACFA38591803012F3BF9F", + "3D5392399F18E4F4105B7ED10A835296", + "C705E39C4EACE697551486C98A606164", + "5959F85E1E16F6B7C680C1F18F4D2015", + "96B948E49A105682B113EB69060ACB8B", + "E93468526C5601586DB016E70A85F38D", + "AAE1DFEE0763A54515A79265BE9D88D6", + "A06D0A27E0290F44BF3BF8611054DF90", + "55FB2D12EBB3624902678E107D61D4B0", + "B12A34FFDDD35E75B153A9B034E5690C", + "C7AD1D22750556E050B35671BF4FBDE9", + "0719C5426CED780AAE88CAB95C1BB766", + "E92B5DC93A4E21153C884D550292C5D7", + "B1675EE9B96512844E8C5F2EE0AC3888", + "EC2F1330447B59AA62E195B0DAA15A30", + "6B7C5517A64C657483B3D52B193D4FA2", + "FBE59AB45195C0AA58C4A5BEAFB5081E", + "51C39C3D437B5AA4372FE9315F7D6BB0", + "5E0F616CB2E785FC56070EF618FD5E89", + "10D95E5FB91AD2E94C94F57DB03CEC70", + "75F01AB6E7D6D60AE63A3B9750866FF4", + "6DFED60E06DDA311E45333E494E24BFE", + "9FBC027E256B26DA5C67DC6F6E26F019", + "4A73F977AD12DD260102C30048808C55", + "B5DA0B29B18C0E68023E9434E1B4CB62", + "116CF16E9C809AC35AFCB827E78FF3B8", + "0392431A37F34BA39040739BFCD18C6A", + "57683F0C8D20429330E6386AFF776C7C", + "D899EA872CFAD6B6A8C30FE6AAD66367", + "F10A0843D6EA708FB497BF534CB91B51", + "D732E6C1728826346423BCE09270D2A3", + "E6E78F0DBC57C71E6831714A39060346", + "5C7A92794A9D4D1D64F15DF983C71846", + "CE5179989BCBA795CE2634764517EC55", + "C0FA8723B50410BDD50C670D45CC0934", + "F627B974275F1EDEED77C58CD6B18D45", + "F9613F5986B577F4D86E4C9012E1A54A", + "A91D03EDB88C9AD3A348D0D31D73E247", + "2296C995704D1BABDDA30ADDB48EF89E", + "7545072B37DE3938CCB8559644683793", + "70BB4CF607477DEC2182DB596CB32380", + "53F4DB83448EE4F08E84A06CF964711D", + "B49988019EDF45DDFD9C5DB7AAAE6309", + "1B7203CF8B90239971BF57BA5C6B496E", + "03C48840AAB7323FA242F3782B4E4810", + "4AE50144BBB6BF8FC3E903BDBD4D1D1C", + "B8B19C8807CAD243FBD79E20E90B6432", + "7D5C8AC851AFDD1938EBDFCB8D5305B8", + "3882B09448DDDF4359685B870D8CBDB9", + "E7371E9700661F5865F1BBE131936C18", + "9AF8FE9E414E1D0D4A2EA63644F117CA", + "6AEB90F119C50EAA987B8143BB56469E", + "292415AFEFC903EA41AB8C5E405A5BD3", + "A2E71CD404CEDD8B359A4920D0B25362", + "F060977571248DE71852E70AF034D6B6", + "AC2EE1C7B11AE02D711AE5CA0E8CE3E5", + "02419BBF7127FE32E8301E442277BD01", + "52D470CF5012716E607D90BC38357DF4", + "387FAB21FB2FD88CCED34F13CF599A92", + "33D4EB08932F17E44117BDFE832C3C51", + "4A73BADA3D44ACABA2FA5F907EEB6C15", + "1E3CF34CC91FD8420DD6D660AF8CD2FC", + "218D511EE83DF04ED3E8F2675DE4B815", + "5E0ABF1F854A8075DF5EB2CCA3258017", + "C6FEF57480D6E15B57F0AEE51D1B8BE7", + "E75206F37C9E3B9C62AF315179DD1F90", + "0FF1252680563AFCE641C377B98DE13E", + "44CF5CC6812DEC6419292A61FD016264", + "9455AA8D5C0BE3015B5EDE981571E6F2", + "4FD378D1A2C5144A7794E21DF6CA7E9C", + "05E60837A343CF0B3679ED7FBA95737C", + "6A4D51928256B2053D5BCA539C2CCF6B", + "34AC6DDC78C85D2F04D4827C939520CD", + "259EE7CFF910A84390581AA63ACB35C8", + "700BDE15825EDA23B405644E5607E12D", + "799B4FC9BD60645F8EA50FF6DA4F725B", + "1A6B21F0E4A63E89F74D64ED278ED08F", + "5EE0D338DA685ACFC693CAEAC37D9672", + "BE7D21A1F8F93B710F493362E11DA949", + "57E691D2EC43A11BE5C8A269E6427822", + "07EE76B20F0231D8C10784CB98CC4F51", + "0E96EF04CA756CE41879C872726114E4", + "8456BE741F17437BFFCA8E4EE6208A9D", + "E84D742D10881CCE02C96D500820F369", + "4F61CE0DCE5ABED9185A41FA6DD4652C", + "AFBA047ED117D25B0A171F29807A4B37", + "8549198BE79CA8F212EFFD2F6DD4A365", + "6EC34BFF5DBF617B5D9E53357E7DF344", + "28B221DDC349DAE8F87631EFF599EA38", + "6A9BED6D040B919BD3072DCD31841EF3", + "937D169279AFB3793069C93376225AC1", + "F6C5B3B68052E8CEE31A2AEE0C6DD08D", + "2E3831FADA02FD33E95B1D940B916747", + "6FEC9F0C63F8F931EDDF772A808BAF6C", + "46D39F7F8AFD6268192A0A80CD7E667C", + "17F67B8B9B0831FB46160665A17B57CF", + "A6CD05C0365B06B65835376F69D09132", + "0A0A4D902C6B37FFBE212A0853B342EB", + "428A2618F050A7D577DC9271F4583179", + "9D472ECE76CAC0E0AD85C3369005EDBB", + "C95C38A655389C91B271DC48FD247474", + "A8C888FBDFCB421EC78AC3CD7239E947", + "BBE509EB348815DFAF37E98BA9952219", + "33AA23D9C8DEA88D1F4E2E79C838E835", + "3C3E41E206B2532F8511FA68B60A8BE9", + "830FECFB9195739AD276A5C087E07EB7", + "C9974C303845503D8EE8C32781D7A6C5", + "001036041BBC3C0DAD4095B3AD6FF2F2", + "AFC2B64B2F96E140A8A757D6F9E4F59C", + "7B0AC71AA6AFD7DA8EC196DE78DEF2D4", + "403FD8B7AB3A35FD666C26E71E757B7E", + "01375CF34FC07E4744D6AB105C3C83DF", + "922E2D610420D1E657260E6B99A04352", + "76D5A21289EB9A0823D33D168FCCF95F", + "7AD8DF7558043BE377064471AD2B961F", + "6572B3A5E81BE57792B17A8C8495E402", + "22763AEB43D6918BD75754EFC9F9D404", + "4785E3D73F3D6B68CFC039D6D2803A86", + "12426E062B1D8BBD6D555CF8BCAC74C4", + "B1B1FFBFF8E27782236C812B724B941D", + "249980E6E7623CCA003B6F9BE15B69C4", + "585AADE1C312E797106724F7C538F2F8", + "66DA9937C1B54CFABA701943159331F4", + "FBD975B0F2A2043FAB5ABCA0AE778F27", + "0ABA4525B3E3131117D8C7E63306D765", + "72A5F812A8534246C05A273ABF1CA210", + "4342246D33ED5428E7EFC229BA752CFC", + ], + }, + // K No.007 + KeySet { + key: "0123456789ABCDEFFEDCBA9876543210FEDCBA98765432100123456789ABCDEF", + ciphertexts: [ + "85BA4EDEFCEA6533E2033B33223EDFFF", + "1E04D42E959531CF59F6CDC0BBE0E3EF", + "FFAF72CFDB6C5BAF878DBF56F9E55299", + "BD1E3922A89B5BA1C13A40DEEC3CB41E", + "82A9A6CA76DA3DF4583E002B79250A93", + "0C32D3AFC3E2C27D997CCAD8F0352B8C", + "9102E73550B2829475F2DE4FE14A66B0", + "4A8F7AB4B02C9ECF1C67CECC0A6ED50F", + "157579A70B4A1ABC61546ECA28A4B937", + "0B551D0548B81A0F3F5819AD4691AC02", + "6F1E2E8EAD692E4051CC7970FB311A17", + "156E9323606B9A4267BE1CDB4993EB59", + "221F874CCE15DD8BC0DA9BB252268465", + "09D85B24969CE6675D0832D20656D722", + "691F6AD95B62860059F9B49DEE64796E", + "A151851EC4D0849CC4FA9E10EB139BF9", + "7B4F1E925A435C18614DDE6A4DBB00C1", + "3415EE0C03881568D99F91B2B2CCCD40", + "D17212186527DBD9BEDF54CBA1198407", + "3D0BAE28A32DF82AA308D0A3020055B8", + "5B140283572606A24119C9DE55B161C4", + "85A508D3EE72940DBB1ADFFD7053DCEF", + "C55C1C0D2071629D098025826718FA0E", + "37A16B737A6049AEAC0CFD280D95E6F0", + "03AEA298E06631C074F0F90529CE2C33", + "4BF6255CA8A59E989ED6D21322BEB1AE", + "4D29DC41A802A4A05FB1E92547805935", + "10B0A180E46366928A2B7E4D7D4A5A70", + "C4FE1B0125AFF368E120A41F138E6892", + "86BD657EB9A46CC68AF70319674BC232", + "4966EB70232A7E3EA41EAEE389A9F309", + "8D16C5626CA9368B193FD9FCB8EBAC2A", + "6FB60EEE3B28EFE2A7CFF3ABBF527398", + "06077A53C20B5D27B8598DEACAE4D4B2", + "7A6905F2F404677C904F32CA28F813E4", + "4990E395D4085327129EAEC11AF960DE", + "B09D2A95660E97D539593570493AD6B2", + "BF52D957FB0AF2BC1EEC02C961AD728B", + "EEF57F1CD0784E6DBAA526FC5D5B846A", + "BBBBCF5968CCB22CAE829AC3A5BEA6EC", + "A41472091947D939547DEF0F3E3FB71F", + "B3952E6DDCA8EE058204A8A51E375EBD", + "48AE393ACED0A7198F7C8C268C2D9940", + "13A35E0659DA4616C8D4C8CC95F4B1A3", + "9386A960BFABFE067C3F9D7CBF223C17", + "8037EF34B73AAD173C4E56F703511468", + "F7E6D4707CDF342FE3E7309EA0BD8CDC", + "307D7124CBE4723786BD7C7129FC79BC", + "5C639D420F7375C956B5C4754AC1FBA3", + "A619DBEFFFA3E2B8DF4EE3B43F95496C", + "B890A9FF856EA08B470A1C48B6830509", + "1F8143A722C70A32B61BC45B8A301986", + "78147861E8C4015656BF2DE0846A4F77", + "6ED4B94B1D4CDB3821A46AB30A6B2045", + "7D4C8E1A5A15C4FE0903E9F404196A73", + "EEC387EEFE55F7821594FECFF3021D94", + "A5C09054C97A7B005997D1E10AE90F6D", + "3A80ED019B866A4477583D207FC9ABE4", + "749CDC4BDB0E1987C55DE0BA4D74E5AE", + "3F58D75725A21F758067C951D8609214", + "F37E5E91134ED08854527EE94C8101B3", + "A9654E9E3DB13FB49DB2609D58F4B007", + "6E4E063207931723CE3FE6711B11F1F9", + "88DB81AE9507FC0C730021711F687CBC", + "590953266AB2D88729677D656BDB3D0A", + "FFEAB91631FE278A187FA3CB06654055", + "3C250045CDDFEC3B80DB1C9560536E1D", + "715C08A18F06137BF5ABA7A25A4B0EE8", + "0927ABC1D9517BA15D53988B1709F4E1", + "13E50FB47EB686382ABD2DEEC3CB73CD", + "45DB1E14B602CB0C9E660424D10D4639", + "E3BCC7BF084ACEED00AEB701B8EBF822", + "2B512B42C280FACE600C707C327883F2", + "83300D516874FF0A7205DBA39C319748", + "CD668788601939EF82CC9885F1D0A2F9", + "F8216774113646C751C25A71F65DE4EE", + "3F5DE26359DEF147660138117CF35651", + "B7986453F7B672795C9FF78A17806B03", + "258930CE3F3D84F7C974B642BC9C44DF", + "C33D570FC30A2275BA018D9618DCECFF", + "92BC879CE58ED1ACC2E1668F07410F01", + "28409DE6C90BA4048C7552EF10ECCE8A", + "0AB091E1280C12C86E5212F2E599A0C3", + "70103F022D0597F0D65F81E285EFDA37", + "E6FF384C0ADECF059EDCECD6622FFEEA", + "778167100E89838BF83C937CF1DD2F01", + "12BE0749021A7F5040CE50EFD983FC48", + "2C01E072F55083F90FC24098AFD706BD", + "AF6AFA5FC8C3CC50D7D2ABF0D0164296", + "023124FC257BE8B8DECF5A49565D4E8B", + "319B8B151AEB35F133DF9798A85B21FF", + "FAF27843EBD52B83892DE416321952CE", + "F7D2D7452330FDCCE07394C88412F2D7", + "A2790ABECCE3C1EA6976BFEF61C15EBD", + "5CCF9E78675017E239CF4067B730A002", + "B5E2AA8674C2B3B77E8517F59619F39A", + "21B59BF8C4B128CB2ADE782F86F8A359", + "A05941006641C4F4393164F086A64FE7", + "9126D92047CBB566D1B064CFD6CEA575", + "0F749FD0852D0C83DC73A9B073CF3ECF", + "61692E76FB0AD7AB9751DE62BBA42CDD", + "C82DF5F7E7E95C2669C4E8905AE30767", + "65291FE744F489D91F97B4A2D1E3466A", + "4103F3A1BFDB6D505CD535BC7808CE35", + "885AF6850B68D5B71D1B574FF9B1A552", + "F815265F6BB093DCCA9EF5F9DB6B5EB0", + "5545CFF83DAA487BAEA157AAC28348B6", + "187541AE84DE9F552279E5F6E8919FBB", + "341FDF46D32B0995D183D6F1066688B8", + "A26F9517DC6025C0C16A9394580D6A72", + "755E93FA3A976B92FC7315A01D976860", + "808DDBE73C6864DBC6738A11786B159D", + "5A6516A4E15666601BFADBFBCEB88B70", + "B914DE2C8F8C38481546900A0261086B", + "0C27852F4EC261E77E908BDE2F289931", + "24EBED4560D68E963DF0CD152E15911F", + "097D7F08010621F4DD08F93ACE2BAB24", + "F6BAB9F170CD7D17B705BFD18B8EFCD9", + "85FDE817C7867939EA8003A71AD3E6A8", + "2AC62C307A15DD1D30EA03DBC08D2A3D", + "FE0E7E0CB678E1D54DFD163E43C5D609", + "1BB1835478C2E335FED37FCDCED796CA", + "B0F3A7D26F2FA3BAB3DA8B6070AC5440", + "3A1B7A14118459C50181AFDB2971DE6C", + "478B2E0E0A3586ACC56D103F99D66145", + "0777C93906293DA5E3FF7512E340567D", + "DF56DBEDCF9C00908FD8C8583B961D84", + "F1CE65E2BA02B055AB22C04940B4FAE7", + ], + }, + // K No.008 + KeySet { + key: "FEDCBA98765432100123456789ABCDEF0123456789ABCDEFFEDCBA9876543210", + ciphertexts: [ + "74C7821DCD05FDE6A33DB007353A0E65", + "E15BD31603710F1B4B10B92E5E1EDCB7", + "2610970C3DA190C96171D86E54E59423", + "2EAE865996A69BA64326B474B4830379", + "1778A5D91CF9525F7E93680220372386", + "D873EA7BD9A2CC5185C2AFC0C5B56B0E", + "E858ACF9962E03E28C9794B6DCC4F20D", + "AE3DB542B68CCFDA780C372EA3212EFD", + "0FBF80572A86AE6D61F26763668BFFD3", + "608AD0A63870FECAE42E31E62ED221A1", + "E2342ADAA0D5A860CFD0DE7809DEC485", + "BE56E9D8101E43F2EB92CA9DD29CD631", + "85DAB3007A6FE086D2DAEA6F10D2DC31", + "FF2749C177EE49BC8128FFEB7654E1E8", + "5D8671418E26499B486AA53D63659B0D", + "BF7C313DE21170940A6DCC9D79DD215F", + "9481B1D99237962D82506F26B5074172", + "475CFF2EACB3E284DAF38A9E96C71360", + "F158E5F3A7863A7D5128BFBB1229FCDB", + "62439E2376E35D23A946AACC9154F205", + "190BD5DA48DB829B36903587A54C4D27", + "55DB467C1A22511BC4C5D362396D0BF6", + "B425F0D580956A4B11F9DD4E813E9122", + "DB1CBC3586D0FA27637EB9198636D7B2", + "400EAB1AC6DB3C18F64DE03E12B2A44D", + "1EADC90365008C940A4998AA6A188012", + "43746CEB98472D6051F801CCA595EBD9", + "F71EE137E8D4A85064D1BE754C436356", + "CA523AEAE59596CACD66AE4545E9C91B", + "65A328D7FD0F411039CAE5B6E087DDB4", + "EC2C9C5A82F3C9C416E69E8E9770D68D", + "3EE80B5650454834B670E46A1759E4E6", + "68B0D7460259F7D0063ED4CD2E1B221D", + "C8BC48C1FA5F08A87F160BCAF377B036", + "8D651EA8F0E7E06AF3DC816D99291E5A", + "768BAEB36AC434CCF7B28161CF53059C", + "EED6249DF760486060AD573B7B68617D", + "1E93074314D2AE39B07B86459CF80D5B", + "200E2347D492289842209C696E93FB9F", + "AA2D44C480086594A8BB61FF20EFBE2E", + "FF4FEF40D99E5C4F0F7E7DF0F948C4A3", + "7F4393F7A2BB14AD82AC9C3BF97F6D6C", + "2DEDE4BC917E041E0C860D7F818EF0EA", + "1EC3E5BDE0B216A8076D1DB2BB726892", + "BAAE1ED315FF5C6B3EC8F847C696A851", + "8B36FE2309D7EC239E76DE2772B96AA1", + "07319AECDBE8F1F76345B014406CB0E5", + "F64451FBA30DC5F87884A34C5695EE8D", + "4D5D6953522A03F3D93C36F609D91C52", + "C6687D7505377F6DB61A2ECF483431EA", + "8D090731B1D80A81A94A0F42CB768F69", + "2CF7FB820EA4A91F65256C325E182744", + "A34C20224708A06465603A465EF07F4D", + "36B7D90CADB46AE622FAE75C07B072B7", + "8832A2414A65D8BC050CB4EEFD164A2C", + "98DD0D657DFE8A9B96BBC2B7E751A477", + "B60F23B9D42138CC153E002291B1D7F4", + "C8854382AE5A0E24AEEEC09BFAD88AE2", + "70DD3940E54612ABB11ED2B950AB5BBC", + "106DD53219AE0250560C388A2EBF1281", + "89BC7D709054C6C83ACE007863C6B714", + "A7C1063578FC87308A5984F55D37B2B7", + "3870B145F49F98BF6555073758FD18B8", + "9A01644563F84B1F941DEDA9C6D1B11E", + "BD00A1025DE0BCE9C5773F3296E91447", + "06E7431DA76DB6617DC1CD905D26B8A3", + "BEE7834E3ED658FFA53BCA26D6E90C56", + "EF9F5215722D6A7342FF49970281BD61", + "8B6F2921171B36A10A959B9675FA6CE4", + "FC2C7EAFED94B7AB4567311F4C382CFE", + "D54E275E9D3478076D9DCFAB27D04D2D", + "13F4D7EE9864301249B9E81569EA92CC", + "F16535A71665030B4B6D0CEA43193F2C", + "0595083E54727696543DFF817FC4FAB6", + "4637DEC296CA0DBAF12E768059F7DAF4", + "51BB6C7A91C313E4D86B82ED576721E2", + "340E2C09C496C741A53196634B196A66", + "EBAD604CB673C4EE80B2E6418154664A", + "D3F22A6A7A4B403BCFC77A115BC21149", + "62D581EE1E101694256929894116F536", + "4894FE0C8FF92928BD5784CDF4336301", + "8C270006AC786F0E6C36B0ACA1AE3F96", + "4221D4C855970030DEDC5B1D83955148", + "B9A426ACB42A4A1CE77C883D1DB6B7B9", + "E1CA07ABB12779705DF65AAAC6E14960", + "25DDBB8E5057EB692CA31368F635C866", + "951CA678CD9EC4AC5EED964F24B7392A", + "65E902DA59D18F6734497B92D01087CE", + "C32FCD143CC7C42D79236AA6F4EFB734", + "FC34836CA626AF8B84733E5EC7BA752B", + "6CE02ADB64E87DB26981050E7BAF6BBC", + "5F560EA04C66BCC54387AC75C01E0006", + "C2365838B538CB1C19E6B12FA571A4EB", + "AE18340C1E3D74ABE61FDFD5B8999D56", + "B38E9AE503E6A203CACC7452A2D1541B", + "163BA06716C4FF7219ED66ABC030D2F5", + "08A83A2C75ADE1F7F2EFCB71B1DCE52C", + "514A530FBDD6C097B8E418C5DA7BE41C", + "93D3C2A4EA6C50C83172DD47D1B966C5", + "050E7DF64E9B1DBE3FA8CF43D4B3E807", + "110DCF3B3E6CA76ADA1D0DDF4FE7A4FE", + "477D1A8C98DF1127CBA58523246C5B79", + "A32CB6EC4ABE01D33501788132F36AED", + "6418A3FF584BCCA654655D88CFCE4355", + "6BF7CE75D798DEED004DEBEF04766B9B", + "570AD02B1B15D79EE15EF0125C2CF87C", + "72F81C7151EABC7653964D387DB4BEAE", + "BBE297ADE2585A6DBBE48C2DC8B1A8E8", + "5DF2C0CDB44210F7ABFBCFC2151F2CAD", + "1B501C8429416FA3F4C95B1B16A19538", + "683E0A0ED2458ED8D72F6F200DEAF73F", + "BD96EE98A9371E8FF5A6BC7D44C8DB9A", + "23BB4D08D3A0013D9F2B74B41EDFAB8C", + "51B3808B2ED74211A54B720F909C0705", + "E3694055B626734EA522F73AFDA87731", + "32D3ECD84B9E71CAA1B777E7690D2323", + "997643B2C4CEE981F32D0C9F4AE8290A", + "EEBB94FB64FBB29EBB9CDA39C261CEE6", + "4CC9EB85F000B243DE38B51E884C4ED7", + "54E3F4DCA8D8E320CF431CAF0E39E4D8", + "92F0F4574951B37E7CCA4B25A6B0CAE9", + "68D8E6AA34295370C86100217C5845F4", + "E3310A0AB7BDE72FC0EC1DC21CA3CD0D", + "618BD29E8F0EDAE58DD38C66A93A484F", + "999ECD3A39452CBEDC8A66A90FA0C340", + "CCDD106B009FC5354EE3D22323E9C920", + "3468AC3AF2A4A30E8859073082198297", + "02A9E0A13A64514B3E341490F2F39FE6", + ], + }, + // K No.009 + KeySet { + key: "1032547698BADCFEEFCDAB8967452301EFCDAB89674523011032547698BADCFE", + ciphertexts: [ + "2D3284BDEFC1FFE021B9D5A54C1603E2", + "0BB0EC7C00548CD17A6E63806891644B", + "470D25A5D3FE0723CDB2DD6BB86C6F21", + "9F8C1299325ECF242348123706C3BD0C", + "65F058E530BEBAEAAD91D16F50FE58D4", + "E5ACFB46BA214BEEDCE9CB1F4AA96424", + "3A8DA9C08B31461F34A96C7A5F80131D", + "9D4C392FBD48C48E3E2CF0CB118E3051", + "879F3EC2F247BF4FEAE1F03744ADE200", + "3FBAC2AC754C1E8A1DAD08FB07EAF689", + "D092B19DD7F3E8A98DA682FB97A5B7B0", + "603B077CEC818D28664D2E87AF822AA8", + "2652B9BDEF6E6216B50D8430761D9418", + "9E590A4BFBDEF70CF9022DB11BC28165", + "B520C41DA545DF16E3D3547DF477D01B", + "A7C854DC42AC14E9B5F3EA9A155A58F3", + "DF62311DB9C223272322BACCF20D63BD", + "A79F8710C75AF7DB0048C539BB88E262", + "6E53EB5FAE9909F1317DE009689616BD", + "38C7E55C91D137C35D7C67D630D0CB6E", + "03C76EF3DFA83AB5E3DDB85470019EBD", + "0B3275B1C106A5DCE09C29408A1F3CF3", + "D9425A30359E21D1FD89F697C0FECD4B", + "3025F8683C3ACD36247062810435BA06", + "A622F179484BB51BC070C898AD254EF6", + "81E2C96E631E72D1DA4D92C1C8750D5A", + "B64CF737A6E4A1569B26F4D4FB875C12", + "C2CF7D54DCFF74C2EF6B7092B0FD82F1", + "E1BC7833C30BC32544919B1BC0BE48C7", + "B55DB74B0856A43CD37120013C8F7035", + "53571A8770D7A44DC2494072559A839E", + "CFD47EB1CE3D3833388EA4D5588FBE58", + "7D9FCD68CE2F9530FBEDEB282587085C", + "2001EE8937066AD0A7F0D42D428DA29F", + "ADA0464D533C791265528F7F0C79FBFE", + "C19C14D6875FC712C8E53F3D8F442628", + "D136CF1D85A5C45C067FF4EC6C72B30C", + "157B693832B656B2E31DAB9620A36229", + "0DF4CB2DB8F650966A4BC0B267954FEE", + "D82B3012C9B9E387A7DFA681048DCB7F", + "D71E7841D6D036B6653BFE799E96B066", + "5F92ECE781D3D4285AA6A08CD9AA0B02", + "036642FFE3DA8516A39170B08BDE94A1", + "78E0284D53E3DD4EAAE4F3734F13CAC4", + "4C800DFAA75905B9A84F7DB8CC884AC8", + "FEAC6E454D828AC1BED6167CCAE60AAF", + "FD54380701E4676231A246119668B558", + "07AD7F37D65D2A74B959EB4758345AF9", + "558092EE6CE885DED0B7472A7317B198", + "2E182D73C4BFFBA7FF8789D4DD66CBE3", + "6D53E3738C01A596050079FE6281C67F", + "F796B7D4AA1440D69F047CBB092EC090", + "4FC8865731F4479A0077426F7DE446A2", + "135BE9FFAC3B32E669A4A8C42974A851", + "E8F9D2A164F2D7A49600DCAC89BBFCFF", + "9A20423A7BF658F9E14CA9BAC79F3270", + "B5B49B561E5209818FD7821E1195FC3B", + "202BC0320F2F9E0406B121B4C3CD43FB", + "5050198B61797C9B01B9EBE3E35B66DB", + "1F1E2337F1488D04CA388E0E68CA348D", + "E8042CE4990F3EF748818F092B14C426", + "AA61C375436D26EDEB2A9E2F6605E9A3", + "B20FD0194ED84C0C216196DE61A55C20", + "D9E634DC3BA54FCBAAB837D1353D3599", + "D3B8011D64C6EBB78214CDE8D5740119", + "DCF053840A542C5B6749B4EC44BF25F5", + "EA179A76CFF3A831AD9299CF1CB3C317", + "006F1460EE9D96A4CBED0E7CCE6D3F1E", + "EED2E052A6ADCB790D2E954AAFFF07BB", + "87B4415B77F235883E347218A08FEEF3", + "163577392574A20ED9C5159C7D2C3FA2", + "CD8227A61603EE3000E425B93BA070E2", + "AAE16DB0130CC9DE5ADE163E996B7A76", + "330B2EC37C189D7BF66D00968AFD5FE4", + "FA6666E139B6487630933447A541FB24", + "CCD84B2739E3E3D3476BFACB0113C42F", + "091581DC957060F414EE0628C1352D40", + "1BA6DA5397A234E15F0152DF5FF4727C", + "4A5FF51C1BB02B93556D2126DBB0F67A", + "9A1178ECDEC01CE420B7D7BD9E63D7C1", + "70B6AB39A48760C72EF2EE2BB2033AA3", + "B434F1FA38F2DA9ED06B8A9C06E1AD14", + "9965EDD17603747CCB741C665E2F044C", + "FB333E7108E4437F61BB3468A6F41FA8", + "6AAC29B4DE8ED8D4A397FF917C15CF2F", + "F0AAA9673F05E416479CF9A5C219DA22", + "CB9F7AEECD8FF13B23E1DB2D9901A9AD", + "F11E7B4D5C3D4E2549478E31CE4941B9", + "AA80E0473EEDD52939127DF966DD89A0", + "0248E8DC47C29553AFD0DE8AFD123964", + "41F6D8EA76267ACCECD1CFD031FDF484", + "45214F9BB65BB16C723E3C30708ED1DD", + "FB99403CC307BC1BF6BE43ED0328DE79", + "8E76DC2BB2584115572FA999553F7D76", + "536FBBA25EF18BB9873DB2C3CDC0CC09", + "55AEC95558758CAB9AF6AB073E8B1AE5", + "A5E3D745DBC5F493BA5B990FDC65874B", + "47B74CDDA3ADD925E9456C55B564D5BE", + "00EBB4C4E7F691EA070EF7464A296D57", + "02A847DE8D682D315ED59FE1D77926A9", + "50EFF1D1A97A0BE01C338B9904F86173", + "78C67E6B2970CD1FFD2C2595ADC87E78", + "9A993345F87CCEAF2232CE0AE595FF49", + "529F094C9D244F7CDCF131712A056E34", + "463D4C1E393ABD921A966906CE335E26", + "8558B42A44DD78B40F31C75E21B8F42B", + "32F9AB148E2A9591983D2A9FD414C508", + "EECC3DFB070AFEECCE6E4BBEAEA0D127", + "78BD2E3C953DF0064746085BCFFDB51E", + "F7514DD2E1E5BE39E20184CC72C81B84", + "CC31EC8B3F7A95FB52D28B2BB9A23071", + "94CFDDB232C72652512BAB0CE296BA95", + "09C27194F0DC3271A324E16BC65C984F", + "9A3D28182D195C433435A7BE5B76B335", + "DF425D426F1797E73B364414470AAB04", + "C6A744261501AECBCF8F406B474B5D3A", + "E11DF05FC7CA156ED97568CC44083A62", + "C3EC2463E511D7C0852F82980174603E", + "098F34E21D86A518E6CDA9450194E894", + "1ADD3409176913D1DBB10CE7E03E19C3", + "95EE10EED5D6A0863E8B21C945A9C7D7", + "46D01C301942D58388CEC3E7298B0A12", + "CF6CEA3EB42AB3F0F53336E55E5BE15F", + "A002092044D5919438E9BAD38A24D1DE", + "424117784815F4E0E17A00790A485EB8", + "97EC0AC78CA02073BDEB8E45E9F82F91", + "DE41C3145BBF5074EF3A0C3F110B4E40", + "AE42C843C3FE3BAAB8037506E7823A09", + ], + }, + // K No.010 + KeySet { + key: "EFCDAB89674523011032547698BADCFE1032547698BADCFEEFCDAB8967452301", + ciphertexts: [ + "1B6D3D823EECC0C29ECF09448670F6F5", + "C8BF0EE51F4CC101B8F7A1102DF737D8", + "9039554E55B169438BC50ECEDF1376F0", + "46E0A24B40E9CEEEF189425B59E968FF", + "76C0C93B17E93358BECB8618897BC3A4", + "8015321DA57D4912EDC31B8AC94DC96E", + "125EA3BAD64BE4D108E67B60AC34274B", + "775C0A0900AA828C06A8AE794260DF31", + "02650D837531E8694EABDCC01328343D", + "3C23CFD7E87C1FA4EC632B0B00563BCE", + "58E52A5D1B1E81CD0CBD1610EA40D845", + "9C55A8236EE2BF4F55528D7E4627033D", + "F7704328346B43FF19811B72BB8A477F", + "79B1B5874AEDB3AEB2E39F972F5E009E", + "CE745DBBB90A9E8C52733836004FC302", + "EECB8EADE237E02B456A38600CB3DA72", + "38F5254D336A1F3D8DC9BA83B2B580AE", + "6A69C7E188F5D4788CE8D0236386BF4D", + "3893482FE5FAE8246BB67923F00B12C1", + "06B8E6746B4388B70DC3A0337E8AC00A", + "5F8F45979BEA38B8AFC6191B6CFF5B4E", + "3149759C73E8ECDEEC8DABA90117F421", + "7ADB7115E417E3EEFBEABAB01B0B54D0", + "90DD8631F791B6F7FEAC8A5880034B24", + "1D6017954E356A11F3BAA55BB98E7A52", + "3CB7B6363B59E6D1A5F56F0A0F085433", + "A40EE9D914978475964E28405ED749CF", + "DA66984DE313D46950755E1CFAE3A12B", + "F8F25834467F02E309BF780E809BC47F", + "46590CB9D724BE0D2A19B72D07111BDF", + "4FDD2F76D9A8975B410CF1A3A8AFFCA1", + "30E316CAAD8A054EB36C173384DB4224", + "4AAA9A53203243067446D4765A0EC1A7", + "B815095F92A8AC1978D8DC623922167F", + "E45E5D3B39B0EA8A603294204B350AF9", + "739287C6346EB9E60E3CFA0853A6850F", + "9F6FBAFAAD1C8B4C333C33D16F769F2A", + "30F6B284A92B5C65553FEDE135326126", + "6F04D157CF3F82A440AA9A96FD560588", + "E5A4E2330921A1EB8FFE21AB1C2C2513", + "06F9A947C43567B0B3B901C1C9FC2D55", + "73977E6FDE76A75A2DA3A1FE0B37B63E", + "BC973003938B963C5A97CFDC69716099", + "E8A3AA5771829D159A893A8F338B1554", + "4919FFEB8D764993F8FB03736221283E", + "A34D89B23856E0A729B2CF70CDADD278", + "E879B4A674178EA57AEC198F77FED9B2", + "82B4B93E6F83CA49EEA2512F122D2690", + "D930DCD7F97A2460E6E5368A876E75DA", + "325C840F283828DDF25607C2F884D364", + "9D001F8DE8E6EF4683CE8F6AE6EA476F", + "3315D69CDABBD0E3ED35B5953B1C67F3", + "F65A0ABDBCA794C8FDE7B0AA4520708C", + "ACE5ADB7982EB3D90FF6FF44CBCC2ACD", + "459A28405872B2CF7DBBC355E137F2C7", + "72B4805C14C75F662070B9498FC3F3BA", + "4939302040DCE30127245F1D9FD4B28D", + "E159FDB1C1E2FA1770A01F073AE1FA31", + "203E33DCD203DEB93BC1B7D605FC8EA0", + "036F4544F020064CDAC7E2C208AA08D2", + "59B01C9E9BAE566A997BD513C661BB73", + "8DBE7E21FC8BF9CB9D37DEFDFFF46951", + "4A4F443EEC4007C23BE31C6622656700", + "D4CF7365C75AB184592C57F24A6F1D93", + "08B03581099F2038D8D7DFF1A67D7751", + "203A9E8E1BA0D6FFDB81F6B9951A3C0B", + "36EEE62244AC098DA5A7450EC1E20406", + "C0B2D3173EB145335E91FFF625AF006A", + "9CF6E4DA01D35B951915F11311263E88", + "9EB4515527011778434ACD923F154BF5", + "E40B3F28A77E40FABE919DCD7533179C", + "722FF579EAEF7C1A89B50A1331215EC7", + "A79BBBE0AC571A196DFA7EC0A63A729D", + "DE288AED2C41CC9EEA5E92802ED002F6", + "1F8160E72CF2A1F99B370EA29C95626C", + "85E4368DC20B150D78A1A6200F76C5E5", + "791A3522E39CEB6CB8E9A78BDEA9E7DA", + "B4E7F7CBA215368D2664083F437780DF", + "FE2FA429928839DA3AE054D63C2DD93C", + "61CFEA8BB96BB0CE4BEADB71EB0F410C", + "0772AC6A93888A0C27294B4373243A65", + "D9574580E7E1052A6470A91664346E34", + "850C49C2997E3EC2A8E1B3CB87FE9E3D", + "4C652A1C978587E8F845493AE9F42C74", + "9003710DA743077BC0AB9048CC9572E9", + "CAB7BA7B65AD3B73BD20AA1541721922", + "1BEC38DBDCCF9013F97206ECA77408DF", + "BF9C1CFB49359ADCC43615671E22DB7F", + "4DE33DEFD5212935434DB6E54A0EC3E7", + "52D6B71A26ACB1DD10203CFD0C647531", + "76BC1861E7CB8622B4FB9E18C78F96D6", + "4AC779FADC4AF49B174DAE26503F9DEB", + "13276CC603C166C1DD9707B6473262A0", + "72FD62445B14E685389AF0474167FF12", + "A0754BD75F111945C7AA408A814C02F6", + "31E8D69833F484900904CE1D7F0D005C", + "0A116418847FED0742C3B84D632A16A1", + "DE0133FFDD29F0102AF7CC4C140B7DB0", + "C6F84D09020126CBB548FA1D95A33EF2", + "6939AE05C9BCA4CFBD5628A5FD00900A", + "5D900C179D571844B854C9E6651951F3", + "F4C7827D5E02D7FD766B97B93BC3C7E1", + "C203B1842886BE151D86A4C77C7D069E", + "E8503D12D308FD89821BE0BDF21075A8", + "F730396F9F11ABD32D38409B8431494C", + "9347713D9B0004C401D8661AF7D9C799", + "5D4B3E6C5F1F96702802167408918879", + "8658D6B7296A294A1A171FD9936E3061", + "9D4DF675D4EB51DBD43260FADBF44511", + "47A897FE82E2EDC1FF99A0B55716E033", + "C342B3C25EA3C6F501BA6A561E36967D", + "9D9CDF48439F2A0CC432243CD9D8667F", + "95D58EDA851AA9F233AAEA7A45869D7E", + "D846B65806E17D1875D14484DA45C28B", + "03625B4CA28E883F0522F22AAF0D2AFB", + "F881991E16BD9BB6E7D66EAD80E97B58", + "A78ADC2908149DAF7B0A061698D25856", + "119D096BE52A527C4097EED7F47292E4", + "8FC76E1DEC0CB98D8921A85E37D0617B", + "6B9B0AD177FA86866F08FCA2290F75C8", + "588E7EAA6B12A57CC85AAF14645A0AED", + "9CC942FF0F0C15EAB3FFBFF260D08335", + "9C7D95074BE9A394D8E948D23DA54418", + "5CC760D3FB3C017B9066E75B1A14CD66", + "15FBA8DD215A0A4BA99D84550094BFC1", + "4406C013DE347A8797FA267D58951AD1", + "1C5FA60B9718D625C3D7368DCC9EB050", + "44AE0AADA74995BE0FD47EC5DA6F862D", + ], + }, +]; diff --git a/crypto/camellia/tests/ntt_cryptrec_tests.rs b/crypto/camellia/tests/ntt_cryptrec_tests.rs new file mode 100644 index 000000000..0450cd3b3 --- /dev/null +++ b/crypto/camellia/tests/ntt_cryptrec_tests.rs @@ -0,0 +1,120 @@ +//! All 3840 known-answer vectors of NTT's CRYPTREC test-vector file `t_camellia.txt`, for all three +//! key lengths, in both directions, through the four-block and single-block paths. +//! +//! The data module `ntt_cryptrec_data.rs` describes the file and its provenance. Each key set is +//! the 128 single-bit plaintexts under one key, so the 128 ciphertexts go through +//! `encrypt_4blocks` as thirty-two batches of four (one four-lane pass each) and back through +//! `decrypt_4blocks`; the first +//! plaintext of every set is also run through the single-block methods. Between them the 30 keys +//! cover all-zero, all-one and patterned keys of every length, and the plaintexts cover every bit +//! position of the block, which is a good test of the byte-lane masks and the bit-plane layout. + +mod common; +mod ntt_cryptrec_data; + +use bouncycastle_camellia::BLOCK_LEN; +use bouncycastle_camellia::hazmat::{ + Camellia128Internal, Camellia192Internal, Camellia256Internal, +}; +use bouncycastle_core::hazmat::ElectronicCodeBook; +use bouncycastle_core::hazmat::do_hazardous_operations; +use bouncycastle_core::key_material::{KeyMaterial, KeyMaterialTrait, KeyType}; +use bouncycastle_core::security_strength::SecurityStrength; +use common::bytes; +use ntt_cryptrec_data::{CAMELLIA_128, CAMELLIA_192, CAMELLIA_256, KeySet}; + +/// `P No.i`: the block with only bit `128 - i` set (bit 0 least significant), `i` in `1..=128`. +fn plaintext(i: usize) -> [u8; BLOCK_LEN] { + (1u128 << (128 - i)).to_be_bytes() +} + +fn engine>(key: &str) -> P { + let key_bytes: [u8; KEY_LEN] = bytes(key); + let mut km = + KeyMaterial::::from_bytes_as_type(&key_bytes, KeyType::SymmetricCipherKey) + .expect("a key"); + // `K No.001` is all zero, which `from_bytes_as_type` tags `Zeroized`; retag it as the CLI does. + do_hazardous_operations(&mut km, |k| { + k.set_key_type(KeyType::SymmetricCipherKey)?; + k.set_security_strength(SecurityStrength::from_bytes(KEY_LEN)) + }) + .expect("retagging the key"); + P::new(&km).expect("a valid key") +} + +fn check_key_set>( + bits: usize, + kno: usize, + set: &KeySet, +) -> usize { + let perm: P = engine::(set.key); + let expected: Vec<[u8; BLOCK_LEN]> = set.ciphertexts.iter().map(|c| bytes(c)).collect(); + let plaintexts: Vec<[u8; BLOCK_LEN]> = (1..=128).map(plaintext).collect(); + + // Thirty-two batches of four, both directions. + for (batch, (pts, cts)) in plaintexts.chunks(4).zip(expected.chunks(4)).enumerate() { + let mut blocks: [[u8; BLOCK_LEN]; 4] = pts.try_into().unwrap(); + perm.encrypt_4blocks(&mut blocks); + for (lane, (got, want)) in blocks.iter().zip(cts.iter()).enumerate() { + assert_eq!( + got, + want, + "{bits}-bit K No.{kno:03}, P No.{:03} (batch {batch}, slot {lane}): encrypt", + batch * 4 + lane + 1 + ); + } + perm.decrypt_4blocks(&mut blocks); + assert_eq!(&blocks[..], pts, "{bits}-bit K No.{kno:03}, batch {batch}: decrypt_4blocks"); + } + + // The first vector of the set through the single-block methods too. + let mut b = plaintexts[0]; + perm.encrypt_block(&mut b); + assert_eq!(b, expected[0], "{bits}-bit K No.{kno:03}, P No.001: encrypt_block"); + perm.decrypt_block(&mut b); + assert_eq!(b, plaintexts[0], "{bits}-bit K No.{kno:03}, C No.001: decrypt_block"); + + expected.len() +} + +#[test] +fn plaintexts_are_single_bits() { + assert_eq!(plaintext(1), bytes("80000000000000000000000000000000")); + assert_eq!(plaintext(2), bytes("40000000000000000000000000000000")); + assert_eq!(plaintext(128), bytes("00000000000000000000000000000001")); +} + +#[test] +fn camellia_128_all_ten_keys() { + let mut n = 0; + for (i, set) in CAMELLIA_128.iter().enumerate() { + n += check_key_set::<16, Camellia128Internal>(128, i + 1, set); + } + assert_eq!(n, 1280); +} + +#[test] +fn camellia_192_all_ten_keys() { + let mut n = 0; + for (i, set) in CAMELLIA_192.iter().enumerate() { + n += check_key_set::<24, Camellia192Internal>(192, i + 1, set); + } + assert_eq!(n, 1280); +} + +#[test] +fn camellia_256_all_ten_keys() { + let mut n = 0; + for (i, set) in CAMELLIA_256.iter().enumerate() { + n += check_key_set::<32, Camellia256Internal>(256, i + 1, set); + } + assert_eq!(n, 1280); +} + +/// The file's first vector is also BC Java's `CamelliaTest` vector 0 and NESSIE's; pin it by hand +/// so a regenerated data module cannot silently shift. +#[test] +fn first_vector_is_the_nessie_one() { + assert_eq!(CAMELLIA_128[0].key, "00000000000000000000000000000000"); + assert_eq!(CAMELLIA_128[0].ciphertexts[0], "07923A39EB0A817D1C4D87BDB82D1F1C"); +} diff --git a/crypto/camellia/tests/openssl_cbc_tests.rs b/crypto/camellia/tests/openssl_cbc_tests.rs new file mode 100644 index 000000000..652174a44 --- /dev/null +++ b/crypto/camellia/tests/openssl_cbc_tests.rs @@ -0,0 +1,147 @@ +//! Camellia-CBC known-answer tests, through `Camellia128Key>` and its siblings -- the +//! block-aligned keys the padded `Camellia_CBC_*` aliases wrap. +//! +//! RFC 3713 has no CBC vectors (it only assigns the `id-camellia*-cbc` identifiers, Sec 3), so +//! these are the `CAMELLIA-*-CBC` entries of OpenSSL's +//! `test/recipes/30-test_evp_data/evpciph_camellia.txt` (OpenSSL 3.6.2), transcribed from the file. +//! For each key length the first three entries chain -- each `IV` is the previous `Ciphertext` -- +//! so they form one three-block CBC message under the IV `000102..0f`; that is what is checked +//! here, in one call and block by block, both directions. (The fourth 128-bit entry has an IV +//! unrelated to the third's ciphertext and is checked on its own.) The plaintext blocks and the +//! 128/192/256-bit keys are those of NIST SP 800-38A Appendix F, so a CBC vector here is also a +//! cross-check of the single-block cipher under fresh keys. +//! +//! There is no API for supplying an IV, so encryption is driven through the key's +//! `create_encryptor` with a [`FixedSeedRNG`] whose stream is the vector's IV, and the test asserts +//! the returned init data really is that IV before comparing any ciphertext. Decryption takes the +//! IV directly. + +mod common; + +use bouncycastle_camellia::{BLOCK_LEN, Camellia128Key, Camellia192Key, Camellia256Key}; +use bouncycastle_cipher::modes::{Blocks, CBC}; +use bouncycastle_core::key_material::{KeyMaterial, KeyType}; +use bouncycastle_core::symmetric_key::{BlockDecryptionKey, BlockEncryptionKey, FromKeyMaterial}; +use bouncycastle_core::traits::{BlockCipherDecryptor, BlockCipherEncryptor}; +use bouncycastle_rng::FixedSeedRNG; +use common::bytes; + +/// The IV of the first entry of every chain. +const IV: &str = "000102030405060708090A0B0C0D0E0F"; + +/// The plaintext blocks, in order (SP 800-38A F.2's four blocks; the first three chain here). +const PT: [&str; 4] = [ + "6BC1BEE22E409F96E93D7E117393172A", + "AE2D8A571E03AC9C9EB76FAC45AF8E51", + "30C81C46A35CE411E5FBC1191A0A52EF", + "F69F2445DF4F9B17AD2B417BE66C3710", +]; + +const KEY_128: &str = "2B7E151628AED2A6ABF7158809CF4F3C"; +const CT_128: [&str; 3] = [ + "1607CF494B36BBF00DAEB0B503C831AB", + "A2F2CF671629EF7840C5A5DFB5074887", + "0F06165008CF8B8B5A63586362543E54", +]; +/// The fourth 128-bit entry: its own IV. +const IV_128_4: &str = "36A84CDAFD5F9A85ADA0F0A993D6D577"; +const CT_128_4: &str = "74C64268CDB8B8FAF5B34E8AF3732980"; + +const KEY_192: &str = "8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B"; +const CT_192: [&str; 4] = [ + "2A4830AB5AC4A1A2405955FD2195CF93", + "5D5A869BD14CE54264F892A6DD2EC3D5", + "37D359C3349836D884E310ADDF68C449", + "01FAAA930B4AB9916E9668E1428C6B08", +]; + +const KEY_256: &str = "603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4"; +const CT_256: [&str; 4] = [ + "E6CFA35FC02B134A4D2C0B6737AC3EDA", + "36CBEB73BD504B4070B1B7DE2B21EB50", + "E31A6055297D96CA3330CDF1B1860A83", + "5D563F6D1CCCF236051C0C5C1C58F28F", +]; + +fn key(hex_str: &str) -> KeyMaterial { + KeyMaterial::::from_bytes_as_type(&bytes::(hex_str), KeyType::SymmetricCipherKey) + .expect("a valid symmetric cipher key") +} + +fn concat(blocks: &[&str]) -> [u8; N] { + let joined: String = blocks.iter().copied().collect(); + bytes(&joined) +} + +/// A chained CBC message of `N` bytes under `IV`, through a `CBC` key: one call, block by +/// block, both directions. +fn check_chain( + name: &str, + key: &K, + pt: &[u8; N], + ct: &[u8; N], +) where + K: BlockEncryptionKey + + BlockDecryptionKey, +{ + let iv: [u8; 16] = bytes(IV); + + // Encrypt, all blocks in one call, under the vector's IV. + let (mut enc, got_iv) = key.create_encryptor(&mut FixedSeedRNG::new(iv)).unwrap(); + assert_eq!(got_iv, iv, "{name}: the pinned RNG should produce the vector's IV"); + let mut data = *pt; + enc.do_encrypt_blocks_inplace(data.as_chunks_mut::().0).unwrap(); + assert_eq!(data, *ct, "{name}: encrypt, all blocks in one call"); + + // Encrypt one block at a time. + let (mut enc, _) = key.create_encryptor(&mut FixedSeedRNG::new(iv)).unwrap(); + let mut data = *pt; + for block in data.as_chunks_mut::().0.iter_mut() { + enc.do_encrypt_blocks_inplace(core::slice::from_mut(block)).unwrap(); + } + assert_eq!(data, *ct, "{name}: encrypt, one block at a time"); + + // Decrypt with the IV as init data: one shot, and streaming. + let mut data = *ct; + key.decrypt_inplace(&iv, &mut data).unwrap(); + assert_eq!(data, *pt, "{name}: decrypt, one shot"); + + let mut dec = key.create_decryptor(&iv); + let mut data = *ct; + for block in data.as_chunks_mut::().0.iter_mut() { + dec.do_decrypt_blocks_inplace(core::slice::from_mut(block)).unwrap(); + } + assert_eq!(data, *pt, "{name}: decrypt, one block at a time"); +} + +#[test] +fn camellia_128_cbc_chain() { + let key = Camellia128Key::>::from_key_material(&key::<16>(KEY_128)).unwrap(); + check_chain::<16, _, 48>( + "CAMELLIA-128-CBC", + &key, + &concat::<48>(&PT[..3]), + &concat::<48>(&CT_128), + ); + // The fourth entry stands alone: one block under its own IV. + let iv: [u8; 16] = bytes(IV_128_4); + let mut data: [u8; 16] = bytes(PT[3]); + let (mut enc, got_iv) = key.create_encryptor(&mut FixedSeedRNG::new(iv)).unwrap(); + assert_eq!(got_iv, iv); + enc.do_encrypt_blocks_inplace(core::slice::from_mut(&mut data)).unwrap(); + assert_eq!(data, bytes::<16>(CT_128_4), "CAMELLIA-128-CBC entry 4"); + key.decrypt_inplace(&iv, &mut data).unwrap(); + assert_eq!(data, bytes::<16>(PT[3])); +} + +#[test] +fn camellia_192_cbc_chain() { + let key = Camellia192Key::>::from_key_material(&key::<24>(KEY_192)).unwrap(); + check_chain::<24, _, 64>("CAMELLIA-192-CBC", &key, &concat::<64>(&PT), &concat::<64>(&CT_192)); +} + +#[test] +fn camellia_256_cbc_chain() { + let key = Camellia256Key::>::from_key_material(&key::<32>(KEY_256)).unwrap(); + check_chain::<32, _, 64>("CAMELLIA-256-CBC", &key, &concat::<64>(&PT), &concat::<64>(&CT_256)); +} diff --git a/crypto/camellia/tests/padded_alias_tests.rs b/crypto/camellia/tests/padded_alias_tests.rs new file mode 100644 index 000000000..a51d0f9a2 --- /dev/null +++ b/crypto/camellia/tests/padded_alias_tests.rs @@ -0,0 +1,110 @@ +//! The padded CBC mode through the three Camellia keys. +//! +//! The aliases are only type aliases, so what is worth testing is that both parameters actually +//! select: the direction picks the encryptor or the decryptor, and the padding scheme changes the +//! behaviour rather than being decorative. The mode and the padding layer are tested in +//! `bouncycastle-cipher`; this checks the wiring between them and the key that hands the aliases +//! out. Which type each alias resolves to is pinned in `alg_name_tests.rs`. + +use bouncycastle_camellia::{BLOCK_LEN, Camellia128Key, Camellia192Key, Camellia256Key}; +use bouncycastle_cipher::modes::CBC; +use bouncycastle_cipher::padding::{NoPadding, PKCS7}; +use bouncycastle_core::key_material::{KeyMaterial, KeyType}; +use bouncycastle_core::symmetric_key::{ + FromKeyMaterial, SymmetricDecryptionKey, SymmetricEncryptionKey, +}; +use bouncycastle_rng::HashDRBG_SHA512; + +fn material() -> KeyMaterial { + let bytes: [u8; N] = core::array::from_fn(|i| (i as u8).wrapping_mul(7).wrapping_add(1)); + KeyMaterial::::from_bytes_as_type(&bytes, KeyType::SymmetricCipherKey).expect("a valid key") +} + +fn rng() -> HashDRBG_SHA512 { + HashDRBG_SHA512::new_from_os() +} + +/// Round trips at lengths that need padding and lengths that do not, at every key length. +fn round_trips(name: &str, key: &K) +where + K: SymmetricEncryptionKey + + SymmetricDecryptionKey, +{ + for len in [0usize, 1, 15, 16, 17, 31, 32, 33, 127, 128] { + let plaintext: Vec = (0..len).map(|i| (i * 11 + 3) as u8).collect(); + let (iv, ciphertext) = key.encrypt(&mut rng(), &plaintext).expect("encryption"); + assert_eq!(iv.len(), BLOCK_LEN); + assert_eq!( + ciphertext.len(), + (len / BLOCK_LEN + 1) * BLOCK_LEN, + "{name}, len {len}: PKCS7 pads up to the next whole block" + ); + let recovered = key.decrypt(&iv, &ciphertext).expect("decryption"); + assert_eq!(recovered, plaintext, "{name}, len {len}: round trip"); + } +} + +#[test] +fn every_key_length_round_trips() { + round_trips::<16, _>( + "Camellia-128", + &Camellia128Key::>::from_key_material(&material()).unwrap(), + ); + round_trips::<24, _>( + "Camellia-192", + &Camellia192Key::>::from_key_material(&material()).unwrap(), + ); + round_trips::<32, _>( + "Camellia-256", + &Camellia256Key::>::from_key_material(&material()).unwrap(), + ); +} + +/// The padding parameter must actually select the scheme, not merely be carried around. +#[test] +fn the_padding_parameter_selects_the_scheme() { + let pkcs7_key = Camellia128Key::>::from_key_material(&material()).unwrap(); + let nopad_key = Camellia128Key::>::from_key_material(&material()).unwrap(); + + // A whole block: both schemes accept it, and they disagree about the length. + let aligned = [0x5Au8; BLOCK_LEN]; + let (_, pkcs7) = pkcs7_key.encrypt(&mut rng(), &aligned).expect("PKCS7 accepts it"); + let (_, nopad) = nopad_key.encrypt(&mut rng(), &aligned).expect("NoPadding accepts it"); + assert_eq!(pkcs7.len(), 32, "PKCS7 adds a whole block of padding to aligned data"); + assert_eq!(nopad.len(), 16, "NoPadding adds nothing"); + + // Five bytes: PKCS7 pads it, NoPadding refuses rather than silently padding. + assert!(pkcs7_key.encrypt(&mut rng(), b"hello").is_ok(), "PKCS7 pads a partial block"); + assert!(nopad_key.encrypt(&mut rng(), b"hello").is_err(), "NoPadding must refuse it"); +} + +/// A ciphertext made under one scheme must not decrypt cleanly under the other. +#[test] +fn the_two_schemes_are_not_interchangeable() { + let pkcs7_key = Camellia128Key::>::from_key_material(&material()).unwrap(); + let nopad_key = Camellia128Key::>::from_key_material(&material()).unwrap(); + let aligned = [0x5Au8; BLOCK_LEN]; + let (iv, pkcs7) = pkcs7_key.encrypt(&mut rng(), &aligned).expect("encryption"); + + // NoPadding hands back the padding block as if it were data: the silent mismatch the type + // parameter is there to prevent. + let as_nopad = nopad_key.decrypt(&iv, &pkcs7).expect("NoPadding cannot tell"); + assert_ne!(as_nopad, aligned); + assert_eq!(as_nopad.len(), 32, "it keeps the padding block as data"); + + assert_eq!(pkcs7_key.decrypt(&iv, &pkcs7).expect("decryption"), aligned); +} + +/// The IV is drawn per encryption, so the same plaintext gives different ciphertext. +#[test] +fn each_encryption_gets_a_fresh_iv() { + let key = Camellia128Key::>::from_key_material(&material()).unwrap(); + let mut rng = rng(); + let plaintext = [0x77u8; 32]; + let mut seen = std::collections::BTreeSet::new(); + for _ in 0..16 { + let (iv, ct) = key.encrypt(&mut rng, &plaintext).unwrap(); + assert!(seen.insert(iv), "IV repeated across encryptions"); + assert_eq!(key.decrypt(&iv, &ct).unwrap(), plaintext); + } +} diff --git a/crypto/camellia/tests/reference_tests.rs b/crypto/camellia/tests/reference_tests.rs new file mode 100644 index 000000000..719ce6434 --- /dev/null +++ b/crypto/camellia/tests/reference_tests.rs @@ -0,0 +1,166 @@ +//! Cross-check of the constant-time engine against a transcription of BC Java's +//! `CamelliaLightEngine` (`tests/common/mod.rs`), on many keys and blocks of every length, in +//! every lane, in both directions. +//! +//! The known-answer files pin published values. This file pins *agreement with the source +//! implementation* over thousands of inputs, which is what catches a circuit, mask or schedule +//! error that happens not to be exercised by the published examples -- and the reference is +//! organised quite differently (32-bit quarters, direction-dependent subkey layout, table +//! S-boxes), so agreement is not tautological. + +mod common; + +use bouncycastle_camellia::hazmat::{ + Camellia128Internal, Camellia192Internal, Camellia256Internal, +}; +use bouncycastle_camellia::{BLOCK_LEN, LANES}; +use bouncycastle_core::hazmat::ElectronicCodeBook; +use bouncycastle_core::key_material::{KeyMaterial, KeyType}; + +fn engine>(key: &[u8; KEY_LEN]) -> P { +

>::new( + &KeyMaterial::::from_bytes_as_type(key, KeyType::SymmetricCipherKey) + .expect("a valid symmetric cipher key"), + ) + .expect("a valid key") +} + +/// The reference itself reproduces RFC 3713 Appendix A, so it can be trusted to judge. +#[test] +fn reference_sanity() { + let pt: [u8; BLOCK_LEN] = common::bytes("0123456789abcdeffedcba9876543210"); + for (key, ct) in [ + ( + &common::bytes::<32>( + "0123456789abcdeffedcba987654321000112233445566778899aabbccddeeff", + )[..16], + "67673138549669730857065648eabe43", + ), + ( + &common::bytes::<32>( + "0123456789abcdeffedcba987654321000112233445566778899aabbccddeeff", + )[..24], + "b4993401b3e996f84ee5cee7d79b09b9", + ), + ( + &common::bytes::<32>( + "0123456789abcdeffedcba987654321000112233445566778899aabbccddeeff", + )[..], + "9acc237dff16d76c20ef7c919e3a7509", + ), + ] { + let mut block = pt; + common::encrypt_block(key, &mut block); + assert_eq!(block, common::bytes::<16>(ct), "{}-byte key", key.len()); + common::decrypt_block(key, &mut block); + assert_eq!(block, pt); + } +} + +fn single_block_agrees>(seed: u32) { + let mut seed = seed; + for _ in 0..256 { + let key: [u8; KEY_LEN] = common::pseudo_random(&mut seed); + let perm: P = engine(&key); + for _ in 0..8 { + let block: [u8; BLOCK_LEN] = common::pseudo_random(&mut seed); + + let mut ours = block; + let mut theirs = block; + perm.encrypt_block(&mut ours); + common::encrypt_block(&key, &mut theirs); + assert_eq!(ours, theirs, "encrypt, key {key:02x?}, block {block:02x?}"); + + let mut ours = block; + let mut theirs = block; + perm.decrypt_block(&mut ours); + common::decrypt_block(&key, &mut theirs); + assert_eq!(ours, theirs, "decrypt, key {key:02x?}, block {block:02x?}"); + } + } +} + +fn two_block_override_matches>(seed: u32) { + let mut seed = seed; + for _ in 0..64 { + let key: [u8; KEY_LEN] = common::pseudo_random(&mut seed); + let perm: P = engine(&key); + let a: [u8; BLOCK_LEN] = common::pseudo_random(&mut seed); + let b: [u8; BLOCK_LEN] = common::pseudo_random(&mut seed); + + let mut singly = [a, b]; + perm.encrypt_block(&mut singly[0]); + perm.encrypt_block(&mut singly[1]); + let mut paired = [a, b]; + perm.encrypt_2blocks(&mut paired); + assert_eq!(paired, singly); + let mut theirs = [a, b]; + common::encrypt_block(&key, &mut theirs[0]); + common::encrypt_block(&key, &mut theirs[1]); + assert_eq!(paired, theirs); + + perm.decrypt_2blocks(&mut paired); + assert_eq!(paired, [a, b]); + } +} + +/// Single-block API against the reference: 256 keys of each length, 8 blocks each, both directions. +#[test] +fn single_block_agrees_with_the_reference() { + single_block_agrees::<16, Camellia128Internal>(0x5EED_0001); + single_block_agrees::<24, Camellia192Internal>(0x5EED_0002); + single_block_agrees::<32, Camellia256Internal>(0x5EED_0003); +} + +/// The four-lane API -- the natural unit -- against the reference, every lane, both directions. +#[test] +fn four_lanes_agree_with_the_reference() { + fn run( + mut seed: u32, + new: impl Fn(&[u8; KEY_LEN]) -> bouncycastle_camellia::hazmat::CamelliaInternal

, + ) where + bouncycastle_camellia::hazmat::CamelliaInternal

: ElectronicCodeBook, + { + for _ in 0..128 { + let key: [u8; KEY_LEN] = common::pseudo_random(&mut seed); + let perm = new(&key); + let blocks: [[u8; BLOCK_LEN]; LANES] = + core::array::from_fn(|_| common::pseudo_random(&mut seed)); + + let mut ours = blocks; + perm.encrypt_4blocks(&mut ours); + for (lane, (o, b)) in ours.iter().zip(blocks.iter()).enumerate() { + let mut theirs = *b; + common::encrypt_block(&key, &mut theirs); + assert_eq!(*o, theirs, "encrypt lane {lane}"); + } + perm.decrypt_4blocks(&mut ours); + assert_eq!(ours, blocks, "decrypt_4blocks must invert encrypt_4blocks"); + + let mut ours = blocks; + perm.decrypt_4blocks(&mut ours); + for (lane, (o, b)) in ours.iter().zip(blocks.iter()).enumerate() { + let mut theirs = *b; + common::decrypt_block(&key, &mut theirs); + assert_eq!(*o, theirs, "decrypt lane {lane}"); + } + } + } + let km = + |k: &[u8]| KeyMaterial::<16>::from_bytes_as_type(k, KeyType::SymmetricCipherKey).unwrap(); + run::<16, _>(0x5EED_0031, |k| Camellia128Internal::new(&km(k)).unwrap()); + let km = + |k: &[u8]| KeyMaterial::<24>::from_bytes_as_type(k, KeyType::SymmetricCipherKey).unwrap(); + run::<24, _>(0x5EED_0032, |k| Camellia192Internal::new(&km(k)).unwrap()); + let km = + |k: &[u8]| KeyMaterial::<32>::from_bytes_as_type(k, KeyType::SymmetricCipherKey).unwrap(); + run::<32, _>(0x5EED_0033, |k| Camellia256Internal::new(&km(k)).unwrap()); +} + +/// The two-block override against two single-block calls and the reference, in both slots. +#[test] +fn two_block_override_matches_two_single_calls() { + two_block_override_matches::<16, Camellia128Internal>(0x5EED_0021); + two_block_override_matches::<24, Camellia192Internal>(0x5EED_0022); + two_block_override_matches::<32, Camellia256Internal>(0x5EED_0023); +} diff --git a/crypto/camellia/tests/rfc3713_tests.rs b/crypto/camellia/tests/rfc3713_tests.rs new file mode 100644 index 000000000..676cd683b --- /dev/null +++ b/crypto/camellia/tests/rfc3713_tests.rs @@ -0,0 +1,134 @@ +//! Known-answer tests from RFC 3713 Appendix A, "Example Data of Camellia": one vector per key +//! length, checked in both directions, through every lane of the four-block path (which is also +//! the trait's batch) and through the pair path. +//! +//! All values are transcribed from the downloaded text of the RFC. + +mod common; + +use bouncycastle_camellia::hazmat::{ + Camellia128Internal, Camellia192Internal, Camellia256Internal, CamelliaInternal, +}; +use bouncycastle_camellia::{BLOCK_LEN, LANES}; +use bouncycastle_core::hazmat::{BlockPermutation, ElectronicCodeBook}; +use bouncycastle_core::key_material::{KeyMaterial, KeyType}; +use common::bytes; + +/// The plaintext shared by all three examples. +const PLAINTEXT: &str = "0123456789abcdeffedcba9876543210"; + +/// "128-bit key". +const KEY_128: &str = "0123456789abcdeffedcba9876543210"; +const CT_128: &str = "67673138549669730857065648eabe43"; + +/// "192-bit key". +const KEY_192: &str = "0123456789abcdeffedcba98765432100011223344556677"; +const CT_192: &str = "b4993401b3e996f84ee5cee7d79b09b9"; + +/// "256-bit key". +const KEY_256: &str = "0123456789abcdeffedcba987654321000112233445566778899aabbccddeeff"; +const CT_256: &str = "9acc237dff16d76c20ef7c919e3a7509"; + +fn key(hex_str: &str) -> KeyMaterial { + KeyMaterial::::from_bytes_as_type(&bytes::(hex_str), KeyType::SymmetricCipherKey) + .expect("a valid symmetric cipher key") +} + +/// Every entry point, both directions, for one vector. +fn check( + name: &str, + perm: &CamelliaInternal

, + plaintext: &[u8; BLOCK_LEN], + ciphertext: &[u8; BLOCK_LEN], +) where + CamelliaInternal

: ElectronicCodeBook, +{ + // Single block. + let mut b = *plaintext; + perm.encrypt_block(&mut b); + assert_eq!(&b, ciphertext, "{name}: encrypt_block"); + perm.decrypt_block(&mut b); + assert_eq!(&b, plaintext, "{name}: decrypt_block"); + + // Four lanes: the vector in each lane in turn, with unrelated blocks in the others, which + // must come out as they do on their own. + let others: [[u8; BLOCK_LEN]; LANES] = core::array::from_fn(|i| [i as u8 * 17 + 1; 16]); + let mut alone = others; + for b in alone.iter_mut() { + perm.encrypt_block(b); + } + for lane in 0..LANES { + let mut mixed = others; + mixed[lane] = *plaintext; + perm.encrypt_4blocks(&mut mixed); + assert_eq!(&mixed[lane], ciphertext, "{name}: encrypt_4blocks lane {lane}"); + for other in (0..LANES).filter(|&o| o != lane) { + assert_eq!(mixed[other], alone[other], "{name}: lane {lane} disturbed lane {other}"); + } + perm.decrypt_4blocks(&mut mixed); + assert_eq!(&mixed[lane], plaintext, "{name}: decrypt_4blocks lane {lane}"); + assert_eq!(&mixed[..lane], &others[..lane]); + assert_eq!(&mixed[lane + 1..], &others[lane + 1..]); + } + + // The pair path, in both slots. + let mut pair = [*plaintext, others[3]]; + perm.encrypt_2blocks(&mut pair); + assert_eq!(&pair[0], ciphertext, "{name}: encrypt_2blocks slot 0"); + assert_eq!(pair[1], alone[3]); + perm.decrypt_2blocks(&mut pair); + assert_eq!(pair, [*plaintext, others[3]], "{name}: decrypt_2blocks"); + let mut pair = [others[2], *plaintext]; + perm.encrypt_2blocks(&mut pair); + assert_eq!(&pair[1], ciphertext, "{name}: encrypt_2blocks slot 1"); +} + +#[test] +fn appendix_a_128_bit_key() { + let perm = Camellia128Internal::new(&key::<16>(KEY_128)).unwrap(); + check::<16, _>("Appendix A, 128-bit key", &perm, &bytes(PLAINTEXT), &bytes(CT_128)); +} + +#[test] +fn appendix_a_192_bit_key() { + let perm = Camellia192Internal::new(&key::<24>(KEY_192)).unwrap(); + check::<24, _>("Appendix A, 192-bit key", &perm, &bytes(PLAINTEXT), &bytes(CT_192)); +} + +#[test] +fn appendix_a_256_bit_key() { + let perm = Camellia256Internal::new(&key::<32>(KEY_256)).unwrap(); + check::<32, _>("Appendix A, 256-bit key", &perm, &bytes(PLAINTEXT), &bytes(CT_256)); +} + +/// The three key lengths are different ciphers: the same 16 key bytes extended to 24 or 32 must +/// not produce the 128-bit answer (a schedule that ignored `KR` would). +#[test] +fn key_lengths_are_distinct_ciphers() { + let mut a = bytes::<16>(PLAINTEXT); + let mut b = a; + let mut c = a; + Camellia128Internal::new(&key::<16>(KEY_128)).unwrap().encrypt_block(&mut a); + Camellia192Internal::new(&key::<24>(KEY_192)).unwrap().encrypt_block(&mut b); + Camellia256Internal::new(&key::<32>(KEY_256)).unwrap().encrypt_block(&mut c); + assert_ne!(a, b); + assert_ne!(b, c); + assert_ne!(a, c); +} + +/// `Debug` prints the algorithm name only, never the subkeys. +#[test] +fn debug_prints_only_the_name() { + assert_eq!( + format!("{:?}", Camellia128Internal::new(&key::<16>(KEY_128)).unwrap()), + "Camellia-128" + ); + assert_eq!( + format!("{:?}", Camellia192Internal::new(&key::<24>(KEY_192)).unwrap()), + "Camellia-192" + ); + assert_eq!( + format!("{:?}", Camellia256Internal::new(&key::<32>(KEY_256)).unwrap()), + "Camellia-256" + ); +} diff --git a/crypto/camellia/tests/stream_mode_alias_tests.rs b/crypto/camellia/tests/stream_mode_alias_tests.rs new file mode 100644 index 000000000..e11ed5029 --- /dev/null +++ b/crypto/camellia/tests/stream_mode_alias_tests.rs @@ -0,0 +1,195 @@ +//! Tests for the stream-mode keys `Camellia_CFB_*`, `Camellia_CFB8_*` and `Camellia_CTR_*`. +//! +//! The aliases are only type aliases, so what is worth testing is that they name the right types +//! and behave as the mode they claim to be: the direction selects the encryptor or the decryptor, +//! the init data is the length the mode defines, and the three modes are distinct from each other. +//! The known-answer coverage is in `stream_mode_tests.rs`, and the modes themselves are tested in +//! their own right in `bouncycastle_cipher::modes`; this checks the wiring between them. + +use bouncycastle_camellia::hazmat::{ + Camellia128Internal, Camellia192Internal, Camellia256Internal, +}; +use bouncycastle_camellia::{ + BLOCK_LEN, CTR_NONCE_LEN, Camellia128Key, Camellia192Key, Camellia256Key, +}; +use bouncycastle_cipher::modes::{CFB, CFB8, CTR}; +use bouncycastle_core::hazmat::Mode; +use bouncycastle_core::key_material::{KeyMaterial, KeyType}; +use bouncycastle_core::symmetric_key::{ + FromKeyMaterial, SymmetricDecryptionKey, SymmetricEncryptionKey, +}; +use bouncycastle_core::traits::{StreamCipherDecryptor, StreamCipherEncryptor}; +use bouncycastle_rng::FixedSeedRNG; +use bouncycastle_rng::HashDRBG_SHA512; + +fn material() -> KeyMaterial { + let bytes: [u8; N] = core::array::from_fn(|i| (i as u8).wrapping_mul(7).wrapping_add(1)); + KeyMaterial::::from_bytes_as_type(&bytes, KeyType::SymmetricCipherKey).expect("a valid key") +} + +fn key128>() -> Camellia128Key { + Camellia128Key::from_key_material(&material::<16>()).expect("a valid key") +} +fn key192>() -> Camellia192Key { + Camellia192Key::from_key_material(&material::<24>()).expect("a valid key") +} +fn key256>() -> Camellia256Key { + Camellia256Key::from_key_material(&material::<32>()).expect("a valid key") +} + +fn rng() -> HashDRBG_SHA512 { + HashDRBG_SHA512::new_from_os() +} + +/// Deterministic pseudo-random bytes, so the tests do not depend on an RNG. +fn filler(len: usize, seed: u32) -> Vec { + let mut state = seed.wrapping_mul(2_654_435_761).wrapping_add(1); + (0..len) + .map(|_| { + state ^= state << 13; + state ^= state >> 17; + state ^= state << 5; + (state >> 24) as u8 + }) + .collect() +} + +/// Every stream-mode key round-trips at any length, with the ciphertext exactly as long as the +/// plaintext -- the property that separates these nine from the CBC keys, which pad. +#[test] +fn every_stream_key_round_trips_at_any_length() { + fn check<'k, const KEY_LEN: usize, const INIT_DATA_LEN: usize, K>(name: &str, key: &'k K) + where + K: SymmetricEncryptionKey + + SymmetricDecryptionKey, + K::Encryptor<'k>: StreamCipherEncryptor, + K::Decryptor<'k>: StreamCipherDecryptor, + { + for len in [0usize, 1, 15, 16, 17, 64, 257] { + let plaintext = filler(len, len as u32); + let mut data = plaintext.clone(); + + let (_, init) = key.encrypt_inplace(&mut rng(), &mut data).expect("encryption"); + assert_eq!(data.len(), len, "{name}, len {len}: no padding is added"); + assert_eq!(init.len(), INIT_DATA_LEN, "{name}: init data length"); + + key.decrypt_inplace(&init, &mut data).expect("decryption"); + assert_eq!(data, plaintext, "{name}, len {len}: round trip"); + } + } + + check::<16, 16, _>("Camellia_CFB_128", &key128::()); + check::<24, 16, _>("Camellia_CFB_192", &key192::()); + check::<32, 16, _>("Camellia_CFB_256", &key256::()); + check::<16, 16, _>("Camellia_CFB8_128", &key128::()); + check::<24, 16, _>("Camellia_CFB8_192", &key192::()); + check::<32, 16, _>("Camellia_CFB8_256", &key256::()); + check::<16, 12, _>("Camellia_CTR_128", &key128::()); + check::<24, 12, _>("Camellia_CTR_192", &key192::()); + check::<32, 12, _>("Camellia_CTR_256", &key256::()); +} + +/// Streaming in arbitrary pieces gives the same answer as one call: a sequence of calls must be +/// equivalent to one over the concatenation, whatever the chunking. +#[test] +fn chunking_does_not_change_the_ciphertext() { + fn check<'k, const KEY_LEN: usize, const INIT_DATA_LEN: usize, K>(name: &str, key: &'k K) + where + K: SymmetricEncryptionKey + + SymmetricDecryptionKey, + K::Encryptor<'k>: StreamCipherEncryptor, + K::Decryptor<'k>: StreamCipherDecryptor, + { + let plaintext = filler(100, 99); + let mut whole = plaintext.clone(); + let (_, init) = key.encrypt_inplace(&mut rng(), &mut whole).expect("encryption"); + + for chunk in [1usize, 3, 7, 16, 33] { + let mut dec = key.create_decryptor(&init); + let mut data = whole.clone(); + for piece in data.chunks_mut(chunk) { + dec.do_decrypt_inplace(piece).expect("decryption"); + } + assert_eq!(data, plaintext, "{name}: {chunk}-byte pieces should decrypt the same"); + } + } + + check::<16, 16, _>("Camellia_CFB_128", &key128::()); + check::<24, 16, _>("Camellia_CFB8_192", &key192::()); + check::<32, 12, _>("Camellia_CTR_256", &key256::()); +} + +/// A fresh IV or nonce per encryption, so the same plaintext gives different ciphertext. For CTR +/// this is the whole security argument: a repeated nonce leaks the XOR of the two messages. +#[test] +fn each_encryption_gets_fresh_init_data() { + fn check<'k, const INIT_DATA_LEN: usize, K>(name: &str, key: &'k K) + where + K: SymmetricEncryptionKey<16, INIT_DATA_LEN, 0> + + SymmetricDecryptionKey<16, INIT_DATA_LEN, 0>, + K::Encryptor<'k>: StreamCipherEncryptor, + K::Decryptor<'k>: StreamCipherDecryptor, + { + let plaintext = [0x77u8; 32]; + let mut rng = rng(); + let mut seen = std::collections::BTreeSet::new(); + for _ in 0..16 { + let mut data = plaintext; + let (_, init) = key.encrypt_inplace(&mut rng, &mut data).expect("encryption"); + assert!(seen.insert(init.to_vec()), "{name}: init data repeated across encryptions"); + key.decrypt_inplace(&init, &mut data).expect("decryption"); + assert_eq!(data, plaintext, "{name}: round trip"); + } + } + + check::<16, _>("Camellia_CFB_128", &key128::()); + check::<16, _>("Camellia_CFB8_128", &key128::()); + check::<12, _>("Camellia_CTR_128", &key128::()); +} + +/// CFB128 and CFB8 are different, non-interoperable modes. Under the same key and IV their first +/// bytes agree -- both are `P_1 XOR MSB_8(O_1)` of the same first output block -- and everything +/// after that diverges, because CFB8 re-enciphers after every byte while CFB128 waits for a block. +#[test] +fn cfb128_and_cfb8_are_not_interchangeable() { + let iv = [0x0Au8; BLOCK_LEN]; + let plaintext = filler(32, 12_345); + + let cfb_key = key128::(); + let mut as_cfb = plaintext.clone(); + let (mut enc, got) = cfb_key.create_encryptor(&mut FixedSeedRNG::new(iv)).expect("CFB128 init"); + assert_eq!(got, iv, "the pinned RNG should produce the chosen IV"); + enc.do_encrypt_inplace(&mut as_cfb).expect("CFB128"); + + let cfb8_key = key128::(); + let mut as_cfb8 = plaintext.clone(); + let (mut enc8, got8) = + cfb8_key.create_encryptor(&mut FixedSeedRNG::new(iv)).expect("CFB8 init"); + assert_eq!(got8, iv); + enc8.do_encrypt_inplace(&mut as_cfb8).expect("CFB8"); + + assert_eq!(as_cfb[0], as_cfb8[0], "both take MSB_8 of the same first output block"); + assert_ne!(as_cfb[1..], as_cfb8[1..], "and diverge from the second byte on"); +} + +/// CTR is not CFB either, and its init data is shorter: 12 bytes against 16. +#[test] +fn ctr_is_not_cfb() { + let plaintext = filler(32, 999); + + let mut as_ctr = plaintext.clone(); + let (_, nonce) = key128::().encrypt_inplace(&mut rng(), &mut as_ctr).unwrap(); + assert_eq!(nonce.len(), CTR_NONCE_LEN); + + let cfb_key = key128::(); + let mut as_cfb = plaintext.clone(); + let (_, iv) = cfb_key.encrypt_inplace(&mut rng(), &mut as_cfb).unwrap(); + assert_eq!(iv.len(), BLOCK_LEN); + + // A CFB decryptor handed a CTR ciphertext cannot recover the plaintext. + let mut misread = as_ctr.clone(); + let mut iv_from_nonce = [0u8; BLOCK_LEN]; + iv_from_nonce[..CTR_NONCE_LEN].copy_from_slice(&nonce); + cfb_key.decrypt_inplace(&iv_from_nonce, &mut misread).expect("decryption runs"); + assert_ne!(misread, plaintext, "CFB must not decrypt a CTR ciphertext"); +} diff --git a/crypto/camellia/tests/stream_mode_tests.rs b/crypto/camellia/tests/stream_mode_tests.rs new file mode 100644 index 000000000..4f4c7137f --- /dev/null +++ b/crypto/camellia/tests/stream_mode_tests.rs @@ -0,0 +1,462 @@ +//! Known-answer tests for the stream modes of operation over Camellia: CFB128 from OpenSSL's +//! vector file, CTR from RFC 5528, and CFB8 from the SP 800-38A equations for want of anything +//! published. +//! +//! RFC 3713 has no mode vectors at all (Sec 3 only assigns the `id-camellia*-cbc` identifiers), so +//! each mode is pinned against the best published source there is, and each source needs a +//! different amount of work to line up with these aliases: +//! +//! * **CFB128.** The `CAMELLIA-*-CFB` entries of OpenSSL's +//! `test/recipes/30-test_evp_data/evpciph_camellia.txt` (OpenSSL 3.6.2), transcribed from the +//! file. For each key length the four entries chain -- each `IV` is the previous `Ciphertext` -- +//! so they form one four-block CFB128 message under the IV `000102..0f`, which is what is checked +//! here through `Camellia128Key` and its siblings. The plaintext blocks and the keys are +//! NIST SP 800-38A Appendix F's. +//! * **CTR.** RFC 5528's nine Camellia-CTR test vectors (Sec 4.1). Its counter block is a 4-octet +//! nonce, an 8-octet IV and a 4-octet block counter **starting at one**, where `Ctr` here takes a +//! 12-byte nonce and a counter starting at zero, so the published counter blocks are one step +//! past the first block the `CTR` keys generate and cannot be reached through them. The vectors +//! therefore pin [`reference_ctr`], written from the SP 800-38A Sec 6.5 equations over the +//! permutation, and the keys are then required to agree with that same reference on the counter +//! blocks they do produce. +//! * **CFB8.** There is no published vector: the OpenSSL file says in as many words that it does +//! not carry `CFB{1,8}-CAMELLIAxxx`. [`reference_cfb8`] evaluates the Sec 6.3 equations at +//! `s = 8` over the permutation, and the `CFB8` keys are held to it. +//! +//! Everything internal to the modes -- the counter increment, the short final block, the shift +//! register, the chunking -- is covered by the SP 800-38A and ACVP vectors in +//! `bouncycastle_cipher::modes`. + +mod common; + +use bouncycastle_camellia::hazmat::{ + Camellia128Internal, Camellia192Internal, Camellia256Internal, +}; +use bouncycastle_camellia::{ + BLOCK_LEN, CTR_NONCE_LEN, Camellia128Key, Camellia192Key, Camellia256Key, +}; +use bouncycastle_cipher::modes::{CFB, CFB8, CTR}; +use bouncycastle_core::errors::SymmetricCipherError; +use bouncycastle_core::hazmat::ElectronicCodeBook; +use bouncycastle_core::key_material::{KeyMaterial, KeyType}; +use bouncycastle_core::symmetric_key::{ + FromKeyMaterial, SymmetricDecryptionKey, SymmetricEncryptionKey, +}; +use bouncycastle_core::traits::{StreamCipherDecryptor, StreamCipherEncryptor}; +use bouncycastle_rng::FixedSeedRNG; +use common::bytes; + +const KEY_128: &str = "2B7E151628AED2A6ABF7158809CF4F3C"; +const KEY_192: &str = "8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B"; +const KEY_256: &str = "603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4"; + +fn key_material(hex_str: &str) -> KeyMaterial { + KeyMaterial::::from_bytes_as_type(&bytes::(hex_str), KeyType::SymmetricCipherKey) + .expect("a valid symmetric cipher key") +} + +// ---- CFB128: the OpenSSL vectors, through the aliases ------------------------------------------ + +/// The IV of the first entry of every CFB chain. +const CFB_IV: &str = "000102030405060708090A0B0C0D0E0F"; + +/// SP 800-38A Appendix F's four plaintext blocks, concatenated. +const CFB_PT: &str = concat!( + "6BC1BEE22E409F96E93D7E117393172A", + "AE2D8A571E03AC9C9EB76FAC45AF8E51", + "30C81C46A35CE411E5FBC1191A0A52EF", + "F69F2445DF4F9B17AD2B417BE66C3710", +); + +/// `CFB128-CAMELLIA128.Encrypt`, the four chained entries concatenated. +const CFB_CT_128: &str = concat!( + "14F7646187817EB586599146B82BD719", + "A53D28BB82DF741103EA4F921A44880B", + "9C2157A664626D1DEF9EA420FDE69B96", + "742A25F0542340C7BAEF24CA8482BB09", +); +/// `CFB128-CAMELLIA192.Encrypt`. +const CFB_CT_192: &str = concat!( + "C832BB9780677DAA82D9B6860DCD565E", + "86F8491627906D780C7A6D46EA331F98", + "69511CCE594CF710CB98BB63D7221F01", + "D5B5378A3ABED55803F25565D8907B84", +); +/// `CFB128-CAMELLIA256.Encrypt`. +const CFB_CT_256: &str = concat!( + "CF6107BB0CEA7D7FB1BD31F5E7B06C93", + "89BEDB4CCDD864EA11BA4CBE849B5E2B", + "555FC3F34BDD2D54C62D9E3BF338C1C4", + "5953ADCE14DB8C7F39F1BD39F359BFFA", +); + +/// One key length's CFB128 vector, through its `CFB` key: encrypted under the vector's own IV, in +/// one call and then block by block, and decrypted back both ways. +fn check_cfb<'k, const KEY_LEN: usize, K>(name: &str, key: &'k K, expected: &str) +where + K: SymmetricEncryptionKey + + SymmetricDecryptionKey, + K::Encryptor<'k>: StreamCipherEncryptor, + K::Decryptor<'k>: StreamCipherDecryptor, +{ + let iv = bytes::(CFB_IV); + let pt = bytes::<64>(CFB_PT); + let ct = bytes::<64>(expected); + + // There is no API for supplying an IV, so pin the RNG to the vector's and check what came back. + let (mut enc, got_iv) = key.create_encryptor(&mut FixedSeedRNG::new(iv)).expect("enc init"); + assert_eq!(got_iv, iv, "{name}: the pinned RNG should produce the vector's IV"); + let mut data = pt; + enc.do_encrypt_inplace(&mut data).expect("encryption"); + assert_eq!(data, ct, "{name} encrypt, one call"); + + let (mut enc, _) = key.create_encryptor(&mut FixedSeedRNG::new(iv)).expect("enc init"); + let mut data = pt; + for block in data.chunks_mut(BLOCK_LEN) { + enc.do_encrypt_inplace(block).expect("encryption"); + } + assert_eq!(data, ct, "{name} encrypt, one block at a time"); + + let mut data = ct; + key.decrypt_inplace(&iv, &mut data).expect("decryption"); + assert_eq!(data, pt, "{name} decrypt, one shot"); + + // Seven bytes at a time: a stream cipher must not care where the call boundaries fall. + let mut dec = key.create_decryptor(&iv); + let mut data = ct; + for piece in data.chunks_mut(7) { + dec.do_decrypt_inplace(piece).expect("decryption"); + } + assert_eq!(data, pt, "{name} decrypt, seven bytes at a time"); +} + +#[test] +fn cfb128_camellia128_openssl_vectors() { + let key = Camellia128Key::::from_key_material(&key_material::<16>(KEY_128)).unwrap(); + check_cfb::<16, _>("CFB128-CAMELLIA128", &key, CFB_CT_128); +} + +#[test] +fn cfb128_camellia192_openssl_vectors() { + let key = Camellia192Key::::from_key_material(&key_material::<24>(KEY_192)).unwrap(); + check_cfb::<24, _>("CFB128-CAMELLIA192", &key, CFB_CT_192); +} + +#[test] +fn cfb128_camellia256_openssl_vectors() { + let key = Camellia256Key::::from_key_material(&key_material::<32>(KEY_256)).unwrap(); + check_cfb::<32, _>("CFB128-CAMELLIA256", &key, CFB_CT_256); +} + +// ---- CTR: RFC 5528's vectors, through a reference built from the equations ---------------------- + +/// CTR straight from SP 800-38A Sec 6.5, over an explicit initial counter block. +/// +/// ```text +/// O_j = CIPH_K(T_j) +/// C_j = P_j XOR O_j (j < n) +/// C*_n = P*_n XOR MSB_u(O_n) +/// ``` +/// +/// `t1` is `T_1` and each `T_{j+1}` is `T_j` incremented as a 128-bit big-endian integer, which is +/// what RFC 5528's "Counter Block (1) ... (2) ... (3)" listings show. Encryption and decryption are +/// the same operation, so one function serves both. `P` is the permutation, so the same body serves +/// all three key lengths. +fn reference_ctr( + key: &KeyMaterial, + t1: [u8; BLOCK_LEN], + data: &mut [u8], +) where + P: ElectronicCodeBook, +{ + let cipher = P::new(key).expect("a valid key"); + let mut t = t1; + for chunk in data.chunks_mut(BLOCK_LEN) { + // O_j = CIPH_K(T_j); a short final chunk takes MSB_u(O_n) by simply stopping early. + let mut o = t; + cipher.encrypt_block(&mut o); + for (d, k) in chunk.iter_mut().zip(o.iter()) { + *d ^= k; + } + // T_{j+1}: increment the whole block, carrying from the least significant byte. + for b in t.iter_mut().rev() { + *b = b.wrapping_add(1); + if *b != 0 { + break; + } + } + } +} + +/// RFC 5528 Sec 4.1 TV #1..#9: `(key, initial counter block, plaintext, ciphertext)`, with the +/// counter block written out as `nonce || IV || 00000001` exactly as the RFC lists it. +type CtrVector = (&'static str, &'static str, &'static str, &'static str); + +/// TV #1 to #3, 128-bit key. +const CTR_VECTORS_128: [CtrVector; 3] = [ + ( + "AE6852F8121067CC4BF7A5765577F39E", + "00000030000000000000000000000001", + "53696E676C6520626C6F636B206D7367", + "D09DC29A8214619A20877C76DB1F0B3F", + ), + ( + "7E24067817FAE0D743D6CE1F32539163", + "006CB6DBC0543B59DA48D90B00000001", + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", + "DBF3C78DC08396D4DA7C907765BBCB442B8E8E0F31F0DCA72C7417E35360E048", + ), + ( + "7691BE035E5020A8AC6E618529F9A0DC", + "00E0017B27777F3F4A1786F000000001", + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20212223", + "B19D1FCDCB75EB882F849CE24D85CF739CE64B2B5C9D73F14F2D5D9DCE9889CDDF508696", + ), +]; + +/// TV #4 to #6, 192-bit key. +const CTR_VECTORS_192: [CtrVector; 3] = [ + ( + "16AF5B145FC9F579C175F93E3BFB0EED863D06CCFDB78515", + "0000004836733C147D6D93CB00000001", + "53696E676C6520626C6F636B206D7367", + "2379399E8A8D2B2B16702FC78B9E9696", + ), + ( + "7C5CB2401B3DC33C19E7340819E0F69C678C3DB8E6F6A91A", + "0096B03B020C6EADC2CB500D00000001", + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", + "7DEF34F7A5D0E415674B7FFCAE67C75DD018B86FF23051E056392A99F35A4CED", + ), + ( + "02BF391EE8ECB159B959617B0965279BF59B60A786D3E0FE", + "0007BDFD5CBD60278DCC091200000001", + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20212223", + "5710E556E1487A20B5AC0E73F19E4E7876F37FDC91B1EF4D4DADE8E666A64D0ED557AB57", + ), +]; + +/// TV #7 to #9, 256-bit key. +const CTR_VECTORS_256: [CtrVector; 3] = [ + ( + "776BEFF2851DB06F4C8A0542C8696F6C6A81AF1EEC96B4D37FC1D689E6C1C104", + "00000060DB5672C97AA8F0B200000001", + "53696E676C6520626C6F636B206D7367", + "3401F9C8247EFFCEBD6994714C1BBB11", + ), + ( + "F6D66D6BD52D59BB0796365879EFF886C66DD51A5B6A99744B50590C87A23884", + "00FAAC24C1585EF15A43D87500000001", + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", + "D6C30392246F7808A83C2B22A8839E45E51CD48A1CDF406EBC9CC2D3AB834108", + ), + ( + "FF7A617CE69148E4F1726E2F43581DE2AA62D9F805532EDFF1EED687FB54153D", + "001CC5B751A51D70A1C1114800000001", + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20212223", + "A4DA23FCE6A5FFAA6D64AE9A0652A42CD161A34B65F9679F75C01F101F71276F15EF0D8D", + ), +]; + +/// The reference reproduces every RFC 5528 ciphertext, and is its own inverse. This is what pins +/// the reference; the aliases are then checked against it below. +fn check_ctr_vectors(name: &str, vectors: &[CtrVector]) +where + P: ElectronicCodeBook, +{ + for (i, (key_hex, t1_hex, pt_hex, ct_hex)) in vectors.iter().enumerate() { + let key = key_material::(key_hex); + let t1 = bytes::(t1_hex); + + let mut data = hex_vec(pt_hex); + reference_ctr::(&key, t1, &mut data); + assert_eq!(data, hex_vec(ct_hex), "{name} TV #{}: ciphertext", i + 1); + + reference_ctr::(&key, t1, &mut data); + assert_eq!(data, hex_vec(pt_hex), "{name} TV #{}: and back", i + 1); + } +} + +/// The RFC's values are 16, 32 and 36 bytes long, so they are decoded to a `Vec` rather than to the +/// fixed-size arrays `common::bytes` returns. +fn hex_vec(hex_str: &str) -> Vec { + assert!(hex_str.len().is_multiple_of(2), "hex string must have even length"); + (0..hex_str.len()) + .step_by(2) + .map(|i| u8::from_str_radix(&hex_str[i..i + 2], 16).expect("valid hex")) + .collect() +} + +#[test] +fn rfc5528_ctr_vectors_pin_the_reference() { + check_ctr_vectors::("RFC 5528 Camellia-128-CTR", &CTR_VECTORS_128); + check_ctr_vectors::("RFC 5528 Camellia-192-CTR", &CTR_VECTORS_192); + check_ctr_vectors::("RFC 5528 Camellia-256-CTR", &CTR_VECTORS_256); +} + +/// Each `CTR` key agrees with the pinned reference on the counter blocks it does produce: the +/// 12-byte nonce followed by a four-byte counter starting at zero. Lengths cross the block boundary +/// and end on a short final block, which is where `MSB_u(O_n)` applies. +fn check_ctr_key<'k, P, const KEY_LEN: usize, K>(name: &str, key_hex: &str, key: &'k K) +where + P: ElectronicCodeBook, + K: SymmetricEncryptionKey + + SymmetricDecryptionKey, + K::Encryptor<'k>: StreamCipherEncryptor, + K::Decryptor<'k>: StreamCipherDecryptor, +{ + let material = key_material::(key_hex); + let nonce = bytes::("000102030405060708090A0B"); + + // The counter block the key starts from: the nonce, then four zero bytes. + let mut t1 = [0u8; BLOCK_LEN]; + t1[..CTR_NONCE_LEN].copy_from_slice(&nonce); + + let mut seed = 0xC0FFEEu32; + for len in [0usize, 1, 15, 16, 17, 31, 32, 33, 64, 129] { + let plaintext: Vec = + (0..len).map(|_| common::pseudo_random::<1>(&mut seed)[0]).collect(); + + let mut expected = plaintext.clone(); + reference_ctr::(&material, t1, &mut expected); + + let mut data = plaintext.clone(); + let (mut enc, got) = key.create_encryptor(&mut FixedSeedRNG::new(nonce)).expect("enc init"); + assert_eq!(got, nonce, "{name}: the pinned RNG should produce the chosen nonce"); + enc.do_encrypt_inplace(&mut data).expect("encryption"); + assert_eq!(data, expected, "{name}, len {len}: should match the reference"); + + key.decrypt_inplace(&nonce, &mut data).expect("decryption"); + assert_eq!(data, plaintext, "{name}, len {len}: round trip"); + } +} + +#[test] +fn the_ctr_keys_agree_with_the_reference() { + check_ctr_key::( + "Camellia_CTR_128", + KEY_128, + &Camellia128Key::::from_key_material(&key_material::<16>(KEY_128)).unwrap(), + ); + check_ctr_key::( + "Camellia_CTR_192", + KEY_192, + &Camellia192Key::::from_key_material(&key_material::<24>(KEY_192)).unwrap(), + ); + check_ctr_key::( + "Camellia_CTR_256", + KEY_256, + &Camellia256Key::::from_key_material(&key_material::<32>(KEY_256)).unwrap(), + ); +} + +// ---- CFB8: the Sec 6.3 equations at s = 8 ------------------------------------------------------- + +/// CFB straight from SP 800-38A Sec 6.3 with `s = 8`, one byte per forward cipher call. +/// +/// ```text +/// I_1 = IV +/// I_j = LSB_{b-s}(I_{j-1}) | C#_{j-1} +/// O_j = CIPH_K(I_j) +/// C#_j = P#_j XOR MSB_s(O_j) +/// ``` +/// +/// `encrypting` selects which of the two byte streams feeds the shift register: the ciphertext +/// segment, which is the output when encrypting and the input when decrypting. +fn reference_cfb8( + key: &KeyMaterial, + iv: [u8; BLOCK_LEN], + data: &mut [u8], + encrypting: bool, +) where + P: ElectronicCodeBook, +{ + let cipher = P::new(key).expect("a valid key"); + let mut i = iv; + for byte in data.iter_mut() { + let mut o = i; + cipher.encrypt_block(&mut o); + let input = *byte; + // C#_j = P#_j XOR MSB_8(O_j), one byte of the output block. + *byte ^= o[0]; + let feedback = if encrypting { *byte } else { input }; + // I_{j+1} = LSB_{b-8}(I_j) | C#_j: drop the top byte, append the ciphertext byte. + i.rotate_left(1); + i[BLOCK_LEN - 1] = feedback; + } +} + +/// Each `CFB8` key agrees with the equations, both directions, at lengths either side of a block. +fn check_cfb8<'k, P, const KEY_LEN: usize, K>(name: &str, key_hex: &str, key: &'k K) +where + P: ElectronicCodeBook, + K: SymmetricEncryptionKey + + SymmetricDecryptionKey, + K::Encryptor<'k>: StreamCipherEncryptor, + K::Decryptor<'k>: StreamCipherDecryptor, +{ + let material = key_material::(key_hex); + let iv = bytes::(CFB_IV); + + let mut seed = 0x5EEDu32; + for len in [0usize, 1, 2, 15, 16, 17, 33, 64] { + let plaintext: Vec = + (0..len).map(|_| common::pseudo_random::<1>(&mut seed)[0]).collect(); + + let mut expected = plaintext.clone(); + reference_cfb8::(&material, iv, &mut expected, true); + + let mut data = plaintext.clone(); + let (mut enc, got_iv) = key.create_encryptor(&mut FixedSeedRNG::new(iv)).expect("enc init"); + assert_eq!(got_iv, iv); + enc.do_encrypt_inplace(&mut data).expect("encryption"); + assert_eq!(data, expected, "{name}, len {len}: encrypt should match the equations"); + + let mut back = data.clone(); + reference_cfb8::(&material, iv, &mut back, false); + assert_eq!(back, plaintext, "{name}, len {len}: the reference decrypts its own output"); + + key.decrypt_inplace(&iv, &mut data).expect("decryption"); + assert_eq!(data, plaintext, "{name}, len {len}: decrypt should match"); + } +} + +#[test] +fn the_cfb8_keys_agree_with_the_equations() { + check_cfb8::( + "Camellia_CFB8_128", + KEY_128, + &Camellia128Key::::from_key_material(&key_material::<16>(KEY_128)).unwrap(), + ); + check_cfb8::( + "Camellia_CFB8_192", + KEY_192, + &Camellia192Key::::from_key_material(&key_material::<24>(KEY_192)).unwrap(), + ); + check_cfb8::( + "Camellia_CFB8_256", + KEY_256, + &Camellia256Key::::from_key_material(&key_material::<32>(KEY_256)).unwrap(), + ); +} + +/// The counter limit, through a key: under `CTR<15>` the counter is one byte, so the 256th block +/// is the last the mode will produce, and the byte after it is refused rather than repeating the +/// keystream (`bouncycastle_cipher::modes::Ctr`'s rule, pinned here on a Camellia key so that the +/// key-object path reaches it). +#[test] +fn a_ctr_key_refuses_the_byte_after_the_counter_wraps() { + let key = Camellia128Key::>::from_key_material(&key_material::<16>(KEY_128)).unwrap(); + let nonce = [0x5au8; 15]; + let (mut enc, got) = key.create_encryptor(&mut FixedSeedRNG::new(nonce)).unwrap(); + assert_eq!(got, nonce); + + let mut data = vec![0u8; 256 * BLOCK_LEN]; + enc.do_encrypt_inplace(&mut data).expect("256 blocks fill a one-byte counter exactly"); + + let mut one = [0u8; 1]; + assert!( + matches!(enc.do_encrypt_inplace(&mut one), Err(SymmetricCipherError::DataLimitExceeded)), + "the 4097th byte must be refused, not encrypted under a repeated counter block" + ); +} diff --git a/mem_usage_benches/Cargo.toml b/mem_usage_benches/Cargo.toml index f104fe9e1..24bae8260 100644 --- a/mem_usage_benches/Cargo.toml +++ b/mem_usage_benches/Cargo.toml @@ -35,6 +35,10 @@ path = "src/bench_ccm_mem_usage.rs" name = "bench_ascon_mem_usage" path = "src/bench_ascon_mem_usage.rs" +[[bin]] +name = "bench_camellia_mem_usage" +path = "src/bench_camellia_mem_usage.rs" + [[bin]] name = "bench_sm3_mem_usage" path = "src/bench_sm3_mem_usage.rs" diff --git a/mem_usage_benches/src/bench_camellia_mem_usage.rs b/mem_usage_benches/src/bench_camellia_mem_usage.rs new file mode 100644 index 000000000..e8fe0d57d --- /dev/null +++ b/mem_usage_benches/src/bench_camellia_mem_usage.rs @@ -0,0 +1,367 @@ +//! The purpose of this binary is to perform a single run of the primitive under test so that +//! its peak memory usage can be measured with: +//! +//! ```text +//! valgrind --tool=massif --heap=no --stacks=yes -- target/release/bench_camellia_mem_usage > /dev/null +//! +//! ms_print massif.out.* +//! ``` +//! +//! or, shoved all into one line: +//! +//! ```text +//! clear; clear; valgrind --tool=massif --heap=no --stacks=yes -- target/release/bench_camellia_mem_usage > /dev/null; ms_print massif.out.*; rm massif.out.* +//! ``` +//! +//! Make sure you build in release mode! +//! +//! Note: print!() is used to force the compiler not to optimize away the actual code. +//! The important stuff for benchmarking goes to stderr so the junk can be piped to /dev/null. +//! +//! Main is at the bottom, and controls which of these actually runs -- measure one at a time, +//! because massif reports the peak across the whole process. +//! +//! # What to expect, and why massif cannot see it +//! +//! Like AES, Camellia has no interesting stack profile: a call needs a few hundred bytes -- the +//! four-block working state (64 bytes), the eight `u32` S-box planes (32 bytes) plus their copy +//! during the byte rotations, and the circuit's spills -- which is below what massif resolves, +//! since the process's own start-up reaches about 7.7 kB of stack before `main` runs. So the +//! massif number is the floor, not a measurement. +//! +//! The numbers that do mean something come from the compiler's frame-layout remarks, as for +//! `bench_aes_mem_usage`: build this binary with +//! `RUSTFLAGS="-C remark=prologepilog -C remark=stack-frame-layout"`, with `main` calling every +//! bench so none is dead-stripped, and sum the deepest chain of frames below each `measure` +//! closure. The closure is not the whole cost: `encrypt_4blocks` (or the schedule's `expand`), +//! `f` and `ortho` keep their own frames under it (`objdump -d` shows the calls), each with its +//! 8-byte return address. The engine is built in an `#[inline(never)]` helper so its frame is a +//! sibling of the operation's, and the operation runs in a non-inlined, non-returning closure so +//! nothing crosses back across the boundary. The persistent cost, the subkeys, is what +//! `print_struct_sizes` prints. There are no lookup tables; a table-driven engine adds anywhere +//! from 256 bytes to 4 KiB of them on top. +//! +//! With rustc 1.97 nightly on x86-64 the frames are: closures 456 B for Camellia-128's `new`, +//! 584 B for the other two, 88 B for the one- and four-block entry points and 104 B for the +//! two-block ones; `expand` 248 B for Camellia-128 and 328 B for the other two; `encrypt_4blocks` +//! and `decrypt_4blocks` 200 B, or 232 B and 216 B for the copies the four-block closures call; +//! `f` 152 B; `ortho` 24 B. The crate docs tabulate the chains: `new` 720 B for Camellia-128 and +//! 1120 B for the other two, 496 B for the one-block calls, 512 B for the two-block calls and +//! `decrypt_4blocks`, 528 B for `encrypt_4blocks`. + +#![allow(dead_code)] +#![allow(unused_imports)] + +use bouncycastle::camellia::LANES; +use bouncycastle::camellia::hazmat::{ + Camellia128Internal, Camellia192Internal, Camellia256Internal, +}; +use bouncycastle::core::hazmat::{BlockPermutation, ElectronicCodeBook}; +use bouncycastle::core::key_material::{KeyMaterial, KeyType}; + +/// This exists so /usr/bin/time can measure the base memory footprint of the harness itself. +fn bench_do_nothing() { + eprintln!("DoNothing"); + + print!("{}", 1 + 1); +} + +/// Prints the in-memory size of each engine, i.e. the persistent cost of holding the subkeys. +fn print_struct_sizes() { + use core::mem::size_of; + + // RFC 3713 Sec 2.2: kw1..kw4, k1..k18 and ke1..ke4 for 128-bit keys (26 x 8 bytes); + // kw1..kw4, k1..k24 and ke1..ke6 otherwise (34 x 8 bytes). + println!("size_of: {}", size_of::()); + println!("size_of: {}", size_of::()); + println!("size_of: {}", size_of::()); +} + +/// Runs the operation in its own frame. Returns nothing, so no result crosses the boundary and +/// the closure's frame is exactly the operation's. +#[inline(never)] +fn measure(f: impl FnOnce()) { + f() +} + +/// The RFC 3713 Appendix A keys, so the engines under measurement are known ones. +const KEY_128: [u8; 16] = [ + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, +]; +const KEY_192: [u8; 24] = [ + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, +]; +const KEY_256: [u8; 32] = [ + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, +]; + +/// Wraps a hard-coded key. `#[inline(never)]` so the wrapping is a sibling frame of whatever +/// uses the key, not part of it. +#[inline(never)] +fn key(bytes: &[u8; N]) -> KeyMaterial { + KeyMaterial::::from_bytes_as_type(bytes, KeyType::SymmetricCipherKey).unwrap() +} + +/// Expands the key into an engine, in its own frame, so the expansion's temporaries are popped +/// before an operation on the engine runs. +#[inline(never)] +fn load_camellia128() -> Camellia128Internal { + Camellia128Internal::new(&key(&KEY_128)).unwrap() +} +#[inline(never)] +fn load_camellia192() -> Camellia192Internal { + Camellia192Internal::new(&key(&KEY_192)).unwrap() +} +#[inline(never)] +fn load_camellia256() -> Camellia256Internal { + Camellia256Internal::new(&key(&KEY_256)).unwrap() +} + +// ---- key expansion: the expansion is the operation, so it runs inside `measure` ------------ + +fn bench_camellia128_key_expansion() { + eprintln!("Camellia128Internal::new (key expansion)"); + let key = key(&KEY_128); + measure(|| { + let camellia = Camellia128Internal::new(&key).unwrap(); + print!("{camellia:?}"); + }); +} + +fn bench_camellia192_key_expansion() { + eprintln!("Camellia192Internal::new (key expansion)"); + let key = key(&KEY_192); + measure(|| { + let camellia = Camellia192Internal::new(&key).unwrap(); + print!("{camellia:?}"); + }); +} + +fn bench_camellia256_key_expansion() { + eprintln!("Camellia256Internal::new (key expansion)"); + let key = key(&KEY_256); + measure(|| { + let camellia = Camellia256Internal::new(&key).unwrap(); + print!("{camellia:?}"); + }); +} + +// ---- the six entry points, per key length ------------------------------------------------- +// +// Every entry point runs the same four-lane circuit: a single block fills all four lanes with +// copies, two blocks fill two, so the working state is the same size throughout. The blocks are +// stack arrays in the closure, never a heap buffer, so massif's --heap=no does not hide them. + +fn bench_camellia128_encrypt_block() { + eprintln!("Camellia128Internal::encrypt_block"); + let camellia = load_camellia128(); + measure(|| { + let mut block = [0x11u8; 16]; + camellia.encrypt_block(&mut block); + print!("{block:x?}"); + }); +} + +fn bench_camellia128_decrypt_block() { + eprintln!("Camellia128Internal::decrypt_block"); + let camellia = load_camellia128(); + measure(|| { + let mut block = [0x11u8; 16]; + camellia.decrypt_block(&mut block); + print!("{block:x?}"); + }); +} + +fn bench_camellia128_encrypt_2blocks() { + eprintln!("Camellia128Internal::encrypt_2blocks"); + let camellia = load_camellia128(); + measure(|| { + let mut blocks = [[0x11u8; 16], [0x22u8; 16]]; + camellia.encrypt_2blocks(&mut blocks); + print!("{blocks:x?}"); + }); +} + +fn bench_camellia128_decrypt_2blocks() { + eprintln!("Camellia128Internal::decrypt_2blocks"); + let camellia = load_camellia128(); + measure(|| { + let mut blocks = [[0x11u8; 16], [0x22u8; 16]]; + camellia.decrypt_2blocks(&mut blocks); + print!("{blocks:x?}"); + }); +} + +fn bench_camellia128_encrypt_4blocks() { + eprintln!("Camellia128Internal::encrypt_4blocks"); + let camellia = load_camellia128(); + measure(|| { + let mut blocks: [[u8; 16]; LANES] = + [[0x11u8; 16], [0x22u8; 16], [0x33u8; 16], [0x44u8; 16]]; + camellia.encrypt_4blocks(&mut blocks); + print!("{blocks:x?}"); + }); +} + +fn bench_camellia128_decrypt_4blocks() { + eprintln!("Camellia128Internal::decrypt_4blocks"); + let camellia = load_camellia128(); + measure(|| { + let mut blocks: [[u8; 16]; LANES] = + [[0x11u8; 16], [0x22u8; 16], [0x33u8; 16], [0x44u8; 16]]; + camellia.decrypt_4blocks(&mut blocks); + print!("{blocks:x?}"); + }); +} + +fn bench_camellia192_encrypt_block() { + eprintln!("Camellia192Internal::encrypt_block"); + let camellia = load_camellia192(); + measure(|| { + let mut block = [0x11u8; 16]; + camellia.encrypt_block(&mut block); + print!("{block:x?}"); + }); +} + +fn bench_camellia192_decrypt_block() { + eprintln!("Camellia192Internal::decrypt_block"); + let camellia = load_camellia192(); + measure(|| { + let mut block = [0x11u8; 16]; + camellia.decrypt_block(&mut block); + print!("{block:x?}"); + }); +} + +fn bench_camellia192_encrypt_2blocks() { + eprintln!("Camellia192Internal::encrypt_2blocks"); + let camellia = load_camellia192(); + measure(|| { + let mut blocks = [[0x11u8; 16], [0x22u8; 16]]; + camellia.encrypt_2blocks(&mut blocks); + print!("{blocks:x?}"); + }); +} + +fn bench_camellia192_decrypt_2blocks() { + eprintln!("Camellia192Internal::decrypt_2blocks"); + let camellia = load_camellia192(); + measure(|| { + let mut blocks = [[0x11u8; 16], [0x22u8; 16]]; + camellia.decrypt_2blocks(&mut blocks); + print!("{blocks:x?}"); + }); +} + +fn bench_camellia192_encrypt_4blocks() { + eprintln!("Camellia192Internal::encrypt_4blocks"); + let camellia = load_camellia192(); + measure(|| { + let mut blocks: [[u8; 16]; LANES] = + [[0x11u8; 16], [0x22u8; 16], [0x33u8; 16], [0x44u8; 16]]; + camellia.encrypt_4blocks(&mut blocks); + print!("{blocks:x?}"); + }); +} + +fn bench_camellia192_decrypt_4blocks() { + eprintln!("Camellia192Internal::decrypt_4blocks"); + let camellia = load_camellia192(); + measure(|| { + let mut blocks: [[u8; 16]; LANES] = + [[0x11u8; 16], [0x22u8; 16], [0x33u8; 16], [0x44u8; 16]]; + camellia.decrypt_4blocks(&mut blocks); + print!("{blocks:x?}"); + }); +} + +fn bench_camellia256_encrypt_block() { + eprintln!("Camellia256Internal::encrypt_block"); + let camellia = load_camellia256(); + measure(|| { + let mut block = [0x11u8; 16]; + camellia.encrypt_block(&mut block); + print!("{block:x?}"); + }); +} + +fn bench_camellia256_decrypt_block() { + eprintln!("Camellia256Internal::decrypt_block"); + let camellia = load_camellia256(); + measure(|| { + let mut block = [0x11u8; 16]; + camellia.decrypt_block(&mut block); + print!("{block:x?}"); + }); +} + +fn bench_camellia256_encrypt_2blocks() { + eprintln!("Camellia256Internal::encrypt_2blocks"); + let camellia = load_camellia256(); + measure(|| { + let mut blocks = [[0x11u8; 16], [0x22u8; 16]]; + camellia.encrypt_2blocks(&mut blocks); + print!("{blocks:x?}"); + }); +} + +fn bench_camellia256_decrypt_2blocks() { + eprintln!("Camellia256Internal::decrypt_2blocks"); + let camellia = load_camellia256(); + measure(|| { + let mut blocks = [[0x11u8; 16], [0x22u8; 16]]; + camellia.decrypt_2blocks(&mut blocks); + print!("{blocks:x?}"); + }); +} + +fn bench_camellia256_encrypt_4blocks() { + eprintln!("Camellia256Internal::encrypt_4blocks"); + let camellia = load_camellia256(); + measure(|| { + let mut blocks: [[u8; 16]; LANES] = + [[0x11u8; 16], [0x22u8; 16], [0x33u8; 16], [0x44u8; 16]]; + camellia.encrypt_4blocks(&mut blocks); + print!("{blocks:x?}"); + }); +} + +fn bench_camellia256_decrypt_4blocks() { + eprintln!("Camellia256Internal::decrypt_4blocks"); + let camellia = load_camellia256(); + measure(|| { + let mut blocks: [[u8; 16]; LANES] = + [[0x11u8; 16], [0x22u8; 16], [0x33u8; 16], [0x44u8; 16]]; + camellia.decrypt_4blocks(&mut blocks); + print!("{blocks:x?}"); + }); +} + +fn main() { + print_struct_sizes() + // bench_do_nothing() + // bench_camellia128_key_expansion() + // bench_camellia192_key_expansion() + // bench_camellia256_key_expansion() + // bench_camellia128_encrypt_block() + // bench_camellia128_decrypt_block() + // bench_camellia128_encrypt_2blocks() + // bench_camellia128_decrypt_2blocks() + // bench_camellia128_encrypt_4blocks() + // bench_camellia128_decrypt_4blocks() + // bench_camellia192_encrypt_block() + // bench_camellia192_decrypt_block() + // bench_camellia192_encrypt_2blocks() + // bench_camellia192_decrypt_2blocks() + // bench_camellia192_encrypt_4blocks() + // bench_camellia192_decrypt_4blocks() + // bench_camellia256_encrypt_block() + // bench_camellia256_decrypt_block() + // bench_camellia256_encrypt_2blocks() + // bench_camellia256_decrypt_2blocks() + // bench_camellia256_encrypt_4blocks() + // bench_camellia256_decrypt_4blocks() +} diff --git a/mem_usage_benches/src/lib.rs b/mem_usage_benches/src/lib.rs index a19644665..f14d2463c 100644 --- a/mem_usage_benches/src/lib.rs +++ b/mem_usage_benches/src/lib.rs @@ -1,5 +1,6 @@ mod bench_aes_mem_usage; mod bench_ascon_mem_usage; +mod bench_camellia_mem_usage; mod bench_ccm_mem_usage; mod bench_chacha20_mem_usage; mod bench_chacha20_poly1305_mem_usage; diff --git a/src/lib.rs b/src/lib.rs index 068807c3e..42dffcb05 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ pub use bouncycastle_aes as aes; pub use bouncycastle_ascon as ascon; pub use bouncycastle_base64 as base64; +pub use bouncycastle_camellia as camellia; pub use bouncycastle_chacha20 as chacha20; pub use bouncycastle_chacha20_poly1305_aead as chacha20_poly1305_aead; pub use bouncycastle_cipher as cipher;