diff --git a/Cargo.toml b/Cargo.toml index 7e284ef..2fae5b0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ authors = [ "Richard Haehne <richard.haehne@goto.com>", ] -description = "pure rust implementation of SFrame draft-ietf-sframe-enc-01" +description = "pure rust implementation of SFrame draft-ietf-sframe-enc-03" repository = "https://github.com/goto-opensource/sframe-rs" documentation = "https://docs.rs/sframe/" readme = "README.md" @@ -45,6 +45,7 @@ rand = "0.8" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" strum_macros = "0.25" +test-case = "3.1.0" [features] default = ["ring"] diff --git a/README.md b/README.md index 16dcf74..5e08875 100644 --- a/README.md +++ b/README.md @@ -8,18 +8,18 @@ Secure Frame (SFrame)  -This library is an implementation of [draft-ietf-sframe-enc-latest](https://sframe-wg.github.io/sframe/draft-ietf-sframe-enc.html) and provides and end-to-end encryption mechanism for media frames that is suited for WebRTC conferences. +This library is an implementation of [draft-ietf-sframe-enc-03](https://datatracker.ietf.org/doc/html/draft-ietf-sframe-enc-03) and provides and end-to-end encryption mechanism for media frames that is suited for WebRTC conferences. It is in it's current form a subset of the specification. There is an alternative implementation under [goto-opensource/secure-frame-ts](https://github.com/goto-opensource/secure-frame-ts) ## Differences from the sframe draft * ratcheting is not implemented * keyIds are used as senderIds -* no metadata authentication +* no metadata authentication ## Supported crypto libraries Currently two crypto libraries are supported: -- [ring](https://crates.io/crates/ring) +- [ring](https://crates.io/crates/ring) - is enabled per default with the feature `ring` - supports compilation to Wasm32 - Aes-CTR mode ciphers are not supported @@ -27,10 +27,10 @@ Currently two crypto libraries are supported: - is enabled with the feature `openssl` - To build e.g. use `cargo build --features openssl --no-default-features` - uses rust bindings to OpenSSL. - - Per default the OpenSSL library is locally compiled and then statically linked. The build process requires a C compiler, `perl` (and `perl-core`), and `make`. For further options see the [openssl crate documentation](https://docs.rs/openssl/0.10.55/openssl/). + - Per default the OpenSSL library is locally compiled and then statically linked. The build process requires a C compiler, `perl` (and `perl-core`), and `make`. For further options see the [openssl crate documentation](https://docs.rs/openssl/0.10.55/openssl/). - Compilation to Wasm32 is [not yet supported](https://github.com/sfackler/rust-openssl/issues/1016) -Both cannot be enabled at the same time, thus on conflict `sframe` issues a compiler error. +Both cannot be enabled at the same time, thus on conflict `sframe` issues a compiler error. ## License Licensed under either of Apache License, Version 2.0 or MIT license at your option. @@ -39,4 +39,4 @@ Unless you explicitly state otherwise, any contribution intentionally submitted ## Contribution Any help in form of descriptive and friendly issues or comprehensive pull requests are welcome! -The Changelog of this library is generated from its commit log, there any commit message must conform with https://www.conventionalcommits.org/en/v1.0.0/. For simplicity you could make your commits with convco. \ No newline at end of file +The Changelog of this library is generated from its commit log, there any commit message must conform with https://www.conventionalcommits.org/en/v1.0.0/. For simplicity you could make your commits with convco. diff --git a/benches/crypto.rs b/benches/crypto.rs index 05e65f9..803c5cd 100644 --- a/benches/crypto.rs +++ b/benches/crypto.rs @@ -108,6 +108,12 @@ fn crypto_benches(c: &mut Criterion) { for variant in [ CipherSuiteVariant::AesGcm128Sha256, CipherSuiteVariant::AesGcm256Sha512, + #[cfg(feature = "openssl")] + CipherSuiteVariant::AesCtr128HmacSha256_80, + #[cfg(feature = "openssl")] + CipherSuiteVariant::AesCtr128HmacSha256_64, + #[cfg(feature = "openssl")] + CipherSuiteVariant::AesCtr128HmacSha256_32, ] { let mut ctx = CryptoBenches::from(variant); ctx.run_benches(c); diff --git a/src/crypto/aead.rs b/src/crypto/aead.rs index fbdf9c6..6eec782 100644 --- a/src/crypto/aead.rs +++ b/src/crypto/aead.rs @@ -34,167 +34,117 @@ pub trait AeadDecrypt { #[cfg(test)] mod test { - mod aes_gcm { - use crate::{ - crypto::{ - aead::AeadEncrypt, - cipher_suite::{CipherSuite, CipherSuiteVariant}, - key_expansion::KeyExpansion, - secret::Secret, - }, - header::{Header, HeaderFields}, - }; - use rand::{thread_rng, Rng}; - const KEY_MATERIAL: &str = "THIS_IS_RANDOM"; - - #[test] - fn encrypt_random_frame() { - let mut data = vec![0u8; 1024]; - thread_rng().fill(data.as_mut_slice()); - let header = Header::default(); - let cipher_suite = CipherSuite::from(CipherSuiteVariant::AesGcm256Sha512); - let secret = Secret::expand_from(&cipher_suite, KEY_MATERIAL.as_bytes()).unwrap(); - - let _tag = cipher_suite - .encrypt( - &mut data, - &secret, - &Vec::from(&header), - header.frame_count(), - ) - .unwrap(); - } + use crate::crypto::key_derivation::KeyDerivation; + use crate::header::{FrameCount, KeyId}; + use crate::test_vectors::{get_sframe_test_vector, SframeTest}; + use crate::util::test::assert_bytes_eq; + use crate::{ + crypto::{ + aead::AeadDecrypt, + aead::AeadEncrypt, + cipher_suite::{CipherSuite, CipherSuiteVariant}, + secret::Secret, + }, + header::{Header, HeaderFields}, + }; + + use test_case::test_case; + + use rand::{thread_rng, Rng}; + + const KEY_MATERIAL: &str = "THIS_IS_RANDOM"; + + #[test] + fn encrypt_random_frame() { + let mut data = vec![0u8; 1024]; + thread_rng().fill(data.as_mut_slice()); + let header = Header::default(); + let cipher_suite = CipherSuite::from(CipherSuiteVariant::AesGcm256Sha512); + let secret = + Secret::expand_from(&cipher_suite, KEY_MATERIAL.as_bytes(), KeyId::default()).unwrap(); + + let _tag = cipher_suite + .encrypt( + &mut data, + &secret, + &Vec::from(&header), + header.frame_count(), + ) + .unwrap(); + } - mod test_vectors { - - use crate::crypto::key_expansion::KeyExpansion; - use crate::test_vectors::{get_test_vector, TestVector}; - - use crate::{ - crypto::{ - aead::{AeadDecrypt, AeadEncrypt}, - cipher_suite::{CipherSuite, CipherSuiteVariant}, - secret::Secret, - }, - header::{FrameCount, Header, HeaderFields, KeyId}, - util::test::assert_bytes_eq, - }; - - fn encrypt_test_vector(variant: CipherSuiteVariant) { - let test_vector = get_test_vector(&variant.to_string()); - let cipher_suite = CipherSuite::from(variant); - - let secret = prepare_secret(&cipher_suite, test_vector); - - for enc in &test_vector.encryptions { - let mut data = test_vector.plain_text.clone(); - let header = Header::with_frame_count( - KeyId::from(enc.key_id), - FrameCount::from(enc.frame_count), - ); - let header_buffer = Vec::from(&header); - let tag = cipher_suite - .encrypt(&mut data, &secret, &header_buffer, header.frame_count()) - .unwrap(); - let full_frame: Vec<u8> = header_buffer - .into_iter() - .chain(data.into_iter()) - .chain(tag.as_ref().iter().cloned()) - .collect(); - - assert_bytes_eq(&full_frame, &enc.cipher_text); - } - } + #[test_case(CipherSuiteVariant::AesGcm128Sha256; "AesGcm128Sha256")] + #[test_case(CipherSuiteVariant::AesGcm256Sha512; "AesGcm256Sha512")] + #[cfg_attr(feature = "openssl", test_case(CipherSuiteVariant::AesCtr128HmacSha256_80; "AesCtr128HmacSha256_80"))] + #[cfg_attr(feature = "openssl", test_case(CipherSuiteVariant::AesCtr128HmacSha256_64; "AesCtr128HmacSha256_64"))] + #[cfg_attr(feature = "openssl", test_case(CipherSuiteVariant::AesCtr128HmacSha256_32; "AesCtr128HmacSha256_32"))] + fn encrypt_test_vector(variant: CipherSuiteVariant) { + let test_vec = get_sframe_test_vector(&variant.to_string()); + let cipher_suite = CipherSuite::from(variant); - fn decrypt_test_vector(variant: CipherSuiteVariant) { - let test_vector = get_test_vector(&variant.to_string()); - let cipher_suite = CipherSuite::from(variant); + let secret = prepare_secret(&cipher_suite, test_vec); - let secret = prepare_secret(&cipher_suite, test_vector); + let mut data_buffer = test_vec.plain_text.clone(); - for enc in &test_vector.encryptions { - let header = Header::with_frame_count( - KeyId::from(enc.key_id), - FrameCount::from(enc.frame_count), - ); - let header_buffer = Vec::from(&header); - let mut data = Vec::from(&enc.cipher_text[header.size()..]); + let header = Header::with_frame_count( + KeyId::from(test_vec.key_id), + FrameCount::from(test_vec.frame_count), + ); + let header_buffer = Vec::from(&header); - let decrypted = cipher_suite - .decrypt(&mut data, &secret, &header_buffer, header.frame_count()) - .unwrap(); + let aad_buffer = [header_buffer.as_slice(), test_vec.metadata.as_slice()].concat(); - assert_bytes_eq(decrypted, &test_vector.plain_text); - } - } + let tag = cipher_suite + .encrypt(&mut data_buffer, &secret, &aad_buffer, header.frame_count()) + .unwrap(); - fn prepare_secret(cipher_suite: &CipherSuite, test_vector: &TestVector) -> Secret { - if cipher_suite.is_ctr_mode() { - Secret::expand_from(cipher_suite, &test_vector.key_material).unwrap() - } else { - Secret::from_test_vector(test_vector) - } - } + let full_frame: Vec<u8> = header_buffer + .into_iter() + .chain(data_buffer) + .chain(tag.as_ref().iter().cloned()) + .collect(); - #[test] - fn encrypt_test_vector_aes_gcm_128_sha256() { - encrypt_test_vector(CipherSuiteVariant::AesGcm128Sha256); - } + assert_bytes_eq(&aad_buffer, &test_vec.aad); + assert_bytes_eq(&full_frame, &test_vec.cipher_text); + } - #[test] - fn should_decrypt_test_vector_aes_gcm_128_sha256() { - decrypt_test_vector(CipherSuiteVariant::AesGcm128Sha256); - } + #[test_case(CipherSuiteVariant::AesGcm128Sha256; "AesGcm128Sha256")] + #[test_case(CipherSuiteVariant::AesGcm256Sha512; "AesGcm256Sha512")] + #[cfg_attr(feature = "openssl", test_case(CipherSuiteVariant::AesCtr128HmacSha256_80; "AesCtr128HmacSha256_80"))] + #[cfg_attr(feature = "openssl", test_case(CipherSuiteVariant::AesCtr128HmacSha256_64; "AesCtr128HmacSha256_64"))] + #[cfg_attr(feature = "openssl", test_case(CipherSuiteVariant::AesCtr128HmacSha256_32; "AesCtr128HmacSha256_32"))] + fn decrypt_test_vector(variant: CipherSuiteVariant) { + let test_vec = get_sframe_test_vector(&variant.to_string()); + let cipher_suite = CipherSuite::from(variant); - #[test] - fn encrypt_test_vectors_aes_gcm_256_sha512() { - encrypt_test_vector(CipherSuiteVariant::AesGcm256Sha512); - } + let secret = prepare_secret(&cipher_suite, test_vec); + let header = Header::with_frame_count( + KeyId::from(test_vec.key_id), + FrameCount::from(test_vec.frame_count), + ); + let header_buffer = Vec::from(&header); - #[test] - fn should_decrypt_test_vectors_aes_gcm_256_sha512() { - decrypt_test_vector(CipherSuiteVariant::AesGcm256Sha512); - } + let aad_buffer = [header_buffer.as_slice(), test_vec.metadata.as_slice()].concat(); + assert_bytes_eq(&aad_buffer, &test_vec.aad); + + let mut data = Vec::from(&test_vec.cipher_text[header.size()..]); + + let decrypted = cipher_suite + .decrypt(&mut data, &secret, &aad_buffer, header.frame_count()) + .unwrap(); + + assert_bytes_eq(decrypted, &test_vec.plain_text); + } - #[cfg(feature = "openssl")] - mod aes_ctr { - use crate::CipherSuiteVariant; - - use super::{decrypt_test_vector, encrypt_test_vector}; - - #[test] - fn should_encrypt_test_vectors_aes_ctr_64_hmac_sha256_64() { - encrypt_test_vector(CipherSuiteVariant::AesCtr128HmacSha256_64); - } - - #[test] - fn should_decrypt_test_vectors_aes_ctr_64_hmac_sha256_64() { - decrypt_test_vector(CipherSuiteVariant::AesCtr128HmacSha256_64); - } - - #[test] - fn should_encrypt_test_vectors_aes_ctr_64_hmac_sha256_32() { - encrypt_test_vector(CipherSuiteVariant::AesCtr128HmacSha256_32); - } - - #[test] - fn should_decrypt_test_vectors_aes_ctr_64_hmac_sha256_32() { - decrypt_test_vector(CipherSuiteVariant::AesCtr128HmacSha256_32); - } - - #[test] - // AesCtr128HmacSha256_80 is not available in the test vectors - #[ignore] - fn should_encrypt_test_vectors_aes_ctr_64_hmac_sha256_80() { - encrypt_test_vector(CipherSuiteVariant::AesCtr128HmacSha256_32); - } - - #[test] - // AesCtr128HmacSha256_80 is not available in the test vectors - #[ignore] - fn should_decrypt_test_vectors_aes_ctr_64_hmac_sha256_80() { - decrypt_test_vector(CipherSuiteVariant::AesCtr128HmacSha256_32); - } + fn prepare_secret(cipher_suite: &CipherSuite, test_vec: &SframeTest) -> Secret { + if cipher_suite.is_ctr_mode() { + // the test vectors do not provide the auth key, so we have to expand here + Secret::expand_from(cipher_suite, &test_vec.key_material, test_vec.key_id).unwrap() + } else { + Secret { + key: test_vec.sframe_key.clone(), + salt: test_vec.sframe_salt.clone(), + auth: None, } } } diff --git a/src/crypto/cipher_suite.rs b/src/crypto/cipher_suite.rs index 70cab86..0a373a8 100644 --- a/src/crypto/cipher_suite.rs +++ b/src/crypto/cipher_suite.rs @@ -3,7 +3,7 @@ /// Depicts which AEAD algorithm is used for encryption /// and which hashing function is used for the key expansion, -/// see [sframe draft 00 4.4](https://datatracker.ietf.org/doc/html/draft-ietf-sframe-enc-01#name-ciphersuites) +/// see [sframe draft 03 4.4](https://datatracker.ietf.org/doc/html/draft-ietf-sframe-enc-03#name-cipher-suites) #[derive(Debug, PartialEq, Eq, Clone, Copy)] #[cfg_attr(test, derive(strum_macros::Display))] pub enum CipherSuiteVariant { diff --git a/src/crypto/key_derivation.rs b/src/crypto/key_derivation.rs new file mode 100644 index 0000000..2103e76 --- /dev/null +++ b/src/crypto/key_derivation.rs @@ -0,0 +1,114 @@ +// Copyright (c) 2023 GoTo Group, Inc +// SPDX-License-Identifier: Apache-2.0 AND MIT + +use super::{cipher_suite::CipherSuite, secret::Secret}; +use crate::error::Result; + +pub trait KeyDerivation { + fn expand_from<M, K>(cipher_suite: &CipherSuite, key_material: M, key_id: K) -> Result<Secret> + where + M: AsRef<[u8]>, + K: Into<u64>; +} + +pub fn get_hkdf_key_expand_info(key_id: u64) -> Vec<u8> { + [ + SFRAME_LABEL, + SFRAME_HKDF_KEY_EXPAND_INFO, + &key_id.to_be_bytes(), + ] + .concat() +} + +pub fn get_hkdf_salt_expand_info(key_id: u64) -> Vec<u8> { + [ + SFRAME_LABEL, + SFRAME_HDKF_SALT_EXPAND_INFO, + &key_id.to_be_bytes(), + ] + .concat() +} + +const SFRAME_LABEL: &[u8] = b"SFrame 1.0 "; + +const SFRAME_HKDF_KEY_EXPAND_INFO: &[u8] = b"Secret key "; +const SFRAME_HDKF_SALT_EXPAND_INFO: &[u8] = b"Secret salt "; + +cfg_if::cfg_if! { + if #[cfg(feature = "openssl")] { + pub fn get_hkdf_aead_label(tag_len: usize) -> Vec<u8> { + // for current platforms there is no issue casting from usize to u64 + [SFRAME_HDKF_SUB_AEAD_LABEL, &(tag_len).to_be_bytes()].concat() + } + + pub const SFRAME_HDKF_SUB_AEAD_LABEL: &[u8] = b"SFrame 1.0 AES CTR AEAD "; + pub const SFRAME_HKDF_SUB_ENC_EXPAND_INFO: &[u8] = b"enc"; + pub const SFRAME_HDKF_SUB_AUTH_EXPAND_INFO: &[u8] = b"auth"; + } +} + +#[cfg(test)] +mod test { + use super::KeyDerivation; + use crate::crypto::cipher_suite::CipherSuite; + use crate::crypto::secret::Secret; + use crate::test_vectors::get_sframe_test_vector; + use crate::{crypto::cipher_suite::CipherSuiteVariant, util::test::assert_bytes_eq}; + + mod aes_gcm { + use crate::crypto::key_derivation::{get_hkdf_key_expand_info, get_hkdf_salt_expand_info}; + + use super::*; + + use test_case::test_case; + + #[test_case(CipherSuiteVariant::AesGcm128Sha256; "AesGcm128Sha256")] + #[test_case(CipherSuiteVariant::AesGcm256Sha512; "AesGcm256Sha512")] + + fn derive_correct_base_keys(variant: CipherSuiteVariant) { + let test_vec = get_sframe_test_vector(&variant.to_string()); + + assert_bytes_eq( + &get_hkdf_key_expand_info(test_vec.key_id), + &test_vec.sframe_key_label, + ); + assert_bytes_eq( + &get_hkdf_salt_expand_info(test_vec.key_id), + &test_vec.sframe_salt_label, + ); + + let secret = Secret::expand_from( + &CipherSuite::from(variant), + &test_vec.key_material, + test_vec.key_id, + ) + .unwrap(); + + assert_bytes_eq(&secret.key, &test_vec.sframe_key); + assert_bytes_eq(&secret.salt, &test_vec.sframe_salt); + } + } + + #[cfg(feature = "openssl")] + mod aes_ctr { + use super::*; + use test_case::test_case; + + #[test_case(CipherSuiteVariant::AesCtr128HmacSha256_80; "AesCtr128HmacSha256_80")] + #[test_case(CipherSuiteVariant::AesCtr128HmacSha256_64; "AesCtr128HmacSha256_64")] + #[test_case(CipherSuiteVariant::AesCtr128HmacSha256_32; "AesCtr128HmacSha256_32")] + fn derive_correct_sub_keys(variant: CipherSuiteVariant) { + let test_vec = get_sframe_test_vector(&variant.to_string()); + let cipher_suite = CipherSuite::from(variant); + + let secret = + Secret::expand_from(&cipher_suite, &test_vec.key_material, test_vec.key_id) + .unwrap(); + + assert_bytes_eq(&secret.salt, &test_vec.sframe_salt); + // the subkeys stored in secret.key and secret.auth are not included in the test vectors + assert_eq!(secret.auth.unwrap().len(), cipher_suite.hash_len); + assert_eq!(secret.key.len(), cipher_suite.key_len); + } + } +} diff --git a/src/crypto/key_expansion.rs b/src/crypto/key_expansion.rs deleted file mode 100644 index 0e83d0e..0000000 --- a/src/crypto/key_expansion.rs +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) 2023 GoTo Group, Inc -// SPDX-License-Identifier: Apache-2.0 AND MIT - -use super::{cipher_suite::CipherSuite, secret::Secret}; -use crate::error::Result; - -pub trait KeyExpansion { - fn expand_from<T>(cipher_suite: &CipherSuite, key_material: T) -> Result<Secret> - where - T: AsRef<[u8]>; -} - -pub const SFRAME_HKDF_SALT: &[u8] = b"SFrame10"; -pub const SFRAME_HKDF_KEY_EXPAND_INFO: &[u8] = b"key"; -pub const SFRAME_HDKF_SALT_EXPAND_INFO: &[u8] = b"salt"; - -#[cfg(feature = "openssl")] -pub const SFRAME_HKDF_SUB_SALT: &[u8] = b"SFrame10 AES CTR AEAD"; -#[cfg(feature = "openssl")] -pub const SFRAME_HKDF_SUB_ENC_EXPAND_INFO: &[u8] = b"enc"; -#[cfg(feature = "openssl")] -pub const SFRAME_HDKF_SUB_AUTH_EXPAND_INFO: &[u8] = b"auth"; - -#[cfg(test)] -mod test { - use crate::crypto::cipher_suite::CipherSuite; - use crate::crypto::secret::Secret; - use crate::test_vectors::get_test_vector; - - use crate::{crypto::cipher_suite::CipherSuiteVariant, util::test::assert_bytes_eq}; - - use super::KeyExpansion; - - fn derive_correct_base_keys(variant: CipherSuiteVariant) { - let test_vector = get_test_vector(&variant.to_string()); - let secret = - Secret::expand_from(&CipherSuite::from(variant), &test_vector.key_material).unwrap(); - - assert_bytes_eq(&secret.key, &test_vector.key); - assert_bytes_eq(&secret.salt, &test_vector.salt); - } - - #[test] - fn derive_correct_keys_aes_gcm_128_sha256() { - derive_correct_base_keys(CipherSuiteVariant::AesGcm128Sha256); - } - - #[test] - fn derive_correct_keys_aes_gcm_256_sha512() { - derive_correct_base_keys(CipherSuiteVariant::AesGcm256Sha512); - } - - #[cfg(feature = "openssl")] - mod aes_ctr { - use super::*; - - fn derive_correct_sub_keys(variant: CipherSuiteVariant) { - let test_vector = get_test_vector(&variant.to_string()); - let cipher_suite = CipherSuite::from(variant); - let secret = Secret::expand_from(&cipher_suite, &test_vector.key_material).unwrap(); - - assert_bytes_eq(&secret.salt, &test_vector.salt); - // the subkeys stored in secret.key and secret.auth are not included in the test vectors - assert_eq!(secret.auth.unwrap().len(), cipher_suite.hash_len); - assert_eq!(secret.key.len(), cipher_suite.key_len); - } - - #[test] - fn derive_correct_keys_aes_ctr_128_hmac_sha256_64() { - derive_correct_sub_keys(CipherSuiteVariant::AesCtr128HmacSha256_64); - } - - #[test] - fn derive_correct_keys_aes_ctr_128_hmac_sha256_32() { - derive_correct_sub_keys(CipherSuiteVariant::AesCtr128HmacSha256_32); - } - - #[test] - // AesCtr128HmacSha256_80 is not available in the test vectors - #[ignore] - fn derive_correct_keys_aes_ctr_128_hmac_sha256_80() { - derive_correct_sub_keys(CipherSuiteVariant::AesCtr128HmacSha256_80); - } - } -} diff --git a/src/crypto/mod.rs b/src/crypto/mod.rs index c2f0cdb..a1635fa 100644 --- a/src/crypto/mod.rs +++ b/src/crypto/mod.rs @@ -3,7 +3,7 @@ pub mod aead; pub mod cipher_suite; -pub mod key_expansion; +pub mod key_derivation; pub mod secret; cfg_if::cfg_if! { diff --git a/src/crypto/openssl/aead.rs b/src/crypto/openssl/aead.rs index ad8d9ee..4102711 100644 --- a/src/crypto/openssl/aead.rs +++ b/src/crypto/openssl/aead.rs @@ -190,11 +190,13 @@ impl CipherSuite { let mut signer = openssl::sign::Signer::new(openssl::hash::MessageDigest::sha256(), &key)?; // for current platforms there is no issue casting from usize to u64 - let aad_len = (aad.len() as u64).to_be_bytes(); - let ct_len = (encrypted.len() as u64).to_be_bytes(); - for buf in [&aad_len, &ct_len, nonce, aad, encrypted] { - signer.update(buf)?; - } + signer.update(&(aad.len() as u64).to_be_bytes())?; + signer.update(&(encrypted.len() as u64).to_be_bytes())?; + signer.update(&(self.auth_tag_len as u64).to_be_bytes())?; + signer.update(nonce)?; + signer.update(aad)?; + signer.update(encrypted)?; + let mut tag = signer.sign_to_vec()?; tag.resize(self.auth_tag_len, 0); diff --git a/src/crypto/openssl/key_expansion.rs b/src/crypto/openssl/key_derivation.rs similarity index 60% rename from src/crypto/openssl/key_expansion.rs rename to src/crypto/openssl/key_derivation.rs index 1cf4346..ee68ccd 100644 --- a/src/crypto/openssl/key_expansion.rs +++ b/src/crypto/openssl/key_derivation.rs @@ -4,23 +4,24 @@ use crate::{ crypto::{ cipher_suite::{CipherSuite, CipherSuiteVariant}, - key_expansion::{ - KeyExpansion, SFRAME_HDKF_SALT_EXPAND_INFO, SFRAME_HDKF_SUB_AUTH_EXPAND_INFO, - SFRAME_HKDF_KEY_EXPAND_INFO, SFRAME_HKDF_SALT, SFRAME_HKDF_SUB_ENC_EXPAND_INFO, - SFRAME_HKDF_SUB_SALT, + key_derivation::{ + get_hkdf_aead_label, get_hkdf_key_expand_info, get_hkdf_salt_expand_info, + KeyDerivation, SFRAME_HDKF_SUB_AUTH_EXPAND_INFO, SFRAME_HKDF_SUB_ENC_EXPAND_INFO, }, secret::Secret, }, error::{Result, SframeError}, }; -impl KeyExpansion for Secret { - fn expand_from<T>(cipher_suite: &CipherSuite, key_material: T) -> Result<Secret> +impl KeyDerivation for Secret { + fn expand_from<M, K>(cipher_suite: &CipherSuite, key_material: M, key_id: K) -> Result<Secret> where - T: AsRef<[u8]>, + M: AsRef<[u8]>, + K: Into<u64>, { let try_expand = || { - let (base_key, salt) = expand_secret(cipher_suite, key_material.as_ref())?; + let (base_key, salt) = + expand_secret(cipher_suite, key_material.as_ref(), key_id.into())?; let (key, auth) = if cipher_suite.is_ctr_mode() { let (key, auth) = expand_subsecret(cipher_suite, &base_key)?; (key, Some(auth)) @@ -31,25 +32,27 @@ impl KeyExpansion for Secret { Ok(Secret { key, salt, auth }) }; - try_expand().map_err(|_: openssl::error::ErrorStack| SframeError::KeyExpansion) + try_expand().map_err(|_: openssl::error::ErrorStack| SframeError::KeyDerivation) } } fn expand_secret( cipher_suite: &CipherSuite, key_material: &[u8], + key_id: u64, ) -> std::result::Result<(Vec<u8>, Vec<u8>), openssl::error::ErrorStack> { - let prk = extract_prk(cipher_suite, key_material, SFRAME_HKDF_SALT)?; + // No salt used for the extraction: https://www.ietf.org/archive/id/draft-ietf-sframe-enc-03.html#name-key-derivation + let prk = extract_pseudo_random_key(cipher_suite, key_material, b"")?; let key = expand_key( cipher_suite, &prk, - SFRAME_HKDF_KEY_EXPAND_INFO, + &get_hkdf_key_expand_info(key_id), cipher_suite.key_len, )?; let salt = expand_key( cipher_suite, &prk, - SFRAME_HDKF_SALT_EXPAND_INFO, + &get_hkdf_salt_expand_info(key_id), cipher_suite.nonce_len, )?; @@ -60,7 +63,8 @@ fn expand_subsecret( cipher_suite: &CipherSuite, key: &[u8], ) -> std::result::Result<(Vec<u8>, Vec<u8>), openssl::error::ErrorStack> { - let prk = extract_prk(cipher_suite, key, SFRAME_HKDF_SUB_SALT)?; + let salt = get_hkdf_aead_label(cipher_suite.auth_tag_len); + let prk = extract_pseudo_random_key(cipher_suite, key, &salt)?; let key = expand_key( cipher_suite, &prk, @@ -77,7 +81,7 @@ fn expand_subsecret( Ok((key, auth)) } -fn extract_prk( +fn extract_pseudo_random_key( cipher_suite: &CipherSuite, key_material: &[u8], salt: &[u8], @@ -135,3 +139,29 @@ impl From<CipherSuiteVariant> for &'static openssl::md::MdRef { } } } +#[cfg(test)] +mod test { + + use super::*; + use crate::{test_vectors::get_aes_ctr_test_vector, util::test::assert_bytes_eq}; + + use test_case::test_case; + + #[test_case(CipherSuiteVariant::AesCtr128HmacSha256_80; "AesCtr128HmacSha256_80")] + #[test_case(CipherSuiteVariant::AesCtr128HmacSha256_64; "AesCtr128HmacSha256_64")] + #[test_case(CipherSuiteVariant::AesCtr128HmacSha256_32; "AesCtr128HmacSha256_32")] + fn derive_correct_sub_keys(variant: CipherSuiteVariant) { + let test_vec = get_aes_ctr_test_vector(&variant.to_string()); + let cipher_suite = CipherSuite::from(variant); + + let aead_salt = get_hkdf_aead_label(cipher_suite.auth_tag_len); + assert_bytes_eq(&aead_salt, &test_vec.aead_label); + + let prk = extract_pseudo_random_key(&cipher_suite, &test_vec.base_key, &aead_salt).unwrap(); + assert_bytes_eq(&prk, &test_vec.aead_secret); + + let (key, auth) = expand_subsecret(&cipher_suite, &test_vec.base_key).unwrap(); + assert_bytes_eq(&key, &test_vec.enc_key); + assert_bytes_eq(&auth, &test_vec.auth_key); + } +} diff --git a/src/crypto/openssl/mod.rs b/src/crypto/openssl/mod.rs index b0a2ee6..1dba826 100644 --- a/src/crypto/openssl/mod.rs +++ b/src/crypto/openssl/mod.rs @@ -2,5 +2,5 @@ // SPDX-License-Identifier: Apache-2.0 AND MIT pub mod aead; -pub mod key_expansion; +pub mod key_derivation; pub mod tag; diff --git a/src/crypto/ring/aead.rs b/src/crypto/ring/aead.rs index 4a54e93..2b5eb25 100644 --- a/src/crypto/ring/aead.rs +++ b/src/crypto/ring/aead.rs @@ -47,7 +47,7 @@ impl From<CipherSuiteVariant> for &'static ring::aead::Algorithm { impl CipherSuite { fn unbound_encryption_key(&self, secret: &Secret) -> Result<ring::aead::UnboundKey> { ring::aead::UnboundKey::new(self.variant.into(), secret.key.as_slice()) - .map_err(|_| SframeError::KeyExpansion) + .map_err(|_| SframeError::KeyDerivation) } } diff --git a/src/crypto/ring/key_expansion.rs b/src/crypto/ring/key_derivation.rs similarity index 54% rename from src/crypto/ring/key_expansion.rs rename to src/crypto/ring/key_derivation.rs index 2d904a0..7965ec3 100644 --- a/src/crypto/ring/key_expansion.rs +++ b/src/crypto/ring/key_derivation.rs @@ -4,25 +4,34 @@ use crate::{ crypto::{ cipher_suite::{CipherSuite, CipherSuiteVariant}, - key_expansion::{ - KeyExpansion, SFRAME_HDKF_SALT_EXPAND_INFO, SFRAME_HKDF_KEY_EXPAND_INFO, - SFRAME_HKDF_SALT, - }, + key_derivation::{get_hkdf_key_expand_info, get_hkdf_salt_expand_info, KeyDerivation}, secret::Secret, }, error::{Result, SframeError}, }; -impl KeyExpansion for Secret { - fn expand_from<T>(cipher_suite: &CipherSuite, key_material: T) -> Result<Secret> +impl KeyDerivation for Secret { + fn expand_from<M, K>(cipher_suite: &CipherSuite, key_material: M, key_id: K) -> Result<Secret> where - T: AsRef<[u8]>, + M: AsRef<[u8]>, + K: Into<u64>, { + let key_id = key_id.into(); let algorithm = cipher_suite.variant.into(); - let prk = ring::hkdf::Salt::new(algorithm, SFRAME_HKDF_SALT).extract(key_material.as_ref()); + // No salt used for the extraction: https://www.ietf.org/archive/id/draft-ietf-sframe-enc-03.html#name-key-derivation + let pseudo_random_key = + ring::hkdf::Salt::new(algorithm, b"").extract(key_material.as_ref()); - let key = expand_key(&prk, SFRAME_HKDF_KEY_EXPAND_INFO, cipher_suite.key_len)?; - let salt = expand_key(&prk, SFRAME_HDKF_SALT_EXPAND_INFO, cipher_suite.nonce_len)?; + let key = expand_key( + &pseudo_random_key, + &get_hkdf_key_expand_info(key_id), + cipher_suite.key_len, + )?; + let salt = expand_key( + &pseudo_random_key, + &get_hkdf_salt_expand_info(key_id), + cipher_suite.nonce_len, + )?; Ok(Secret { key, @@ -54,7 +63,7 @@ fn expand_key(prk: &ring::hkdf::Prk, info: &[u8], key_len: usize) -> Result<Vec< prk.expand(&[info], OkmKeyLength(key_len)) .and_then(|okm| okm.fill(sframe_key.as_mut_slice())) - .map_err(|_| SframeError::KeyExpansion)?; + .map_err(|_| SframeError::KeyDerivation)?; Ok(sframe_key) } diff --git a/src/crypto/ring/mod.rs b/src/crypto/ring/mod.rs index cf94d0f..9dc7c7d 100644 --- a/src/crypto/ring/mod.rs +++ b/src/crypto/ring/mod.rs @@ -2,4 +2,4 @@ // SPDX-License-Identifier: Apache-2.0 AND MIT pub mod aead; -pub mod key_expansion; +pub mod key_derivation; diff --git a/src/crypto/secret.rs b/src/crypto/secret.rs index 2194eda..3f4a3f3 100644 --- a/src/crypto/secret.rs +++ b/src/crypto/secret.rs @@ -20,48 +20,34 @@ impl Secret { iv } - - #[cfg(test)] - pub(crate) fn from_test_vector(test_vector: &crate::test_vectors::TestVector) -> Secret { - Secret { - key: test_vector.key.clone(), - salt: test_vector.salt.clone(), - auth: None, - } - } } #[cfg(test)] mod test { - use crate::crypto::cipher_suite::CipherSuite; - use crate::crypto::key_expansion::KeyExpansion; - use crate::test_vectors::get_test_vector; - + use crate::test_vectors::get_sframe_test_vector; use crate::{ crypto::cipher_suite::CipherSuiteVariant, header::FrameCount, util::test::assert_bytes_eq, }; use super::Secret; - + use test_case::test_case; const NONCE_LEN: usize = 12; - fn test_nonce(variant: CipherSuiteVariant) { - let tv = get_test_vector(&variant.to_string()); - - for enc in &tv.encryptions { - let secret = - Secret::expand_from(&CipherSuite::from(variant), &tv.key_material).unwrap(); - let nonce: [u8; NONCE_LEN] = secret.create_nonce(&FrameCount::from(enc.frame_count)); - assert_bytes_eq(&nonce, &enc.nonce); - } - } + #[test_case(CipherSuiteVariant::AesGcm128Sha256; "AesGcm128Sha256")] + #[test_case(CipherSuiteVariant::AesGcm256Sha512; "AesGcm256Sha512")] + #[cfg_attr(feature = "openssl", test_case(CipherSuiteVariant::AesCtr128HmacSha256_80; "AesCtr128HmacSha256_80"))] + #[cfg_attr(feature = "openssl", test_case(CipherSuiteVariant::AesCtr128HmacSha256_64; "AesCtr128HmacSha256_64"))] + #[cfg_attr(feature = "openssl", test_case(CipherSuiteVariant::AesCtr128HmacSha256_32; "AesCtr128HmacSha256_32"))] + fn create_correct_nonce(variant: CipherSuiteVariant) { + let test_vec = get_sframe_test_vector(&variant.to_string()); + + let secret = Secret { + key: test_vec.sframe_key.clone(), + salt: test_vec.sframe_salt.clone(), + auth: None, + }; - #[test] - fn create_correct_nonce_aes_gcm_128_sha256() { - test_nonce(CipherSuiteVariant::AesGcm128Sha256); - } - #[test] - fn create_correct_nonce_aes_gcm_256_sha512() { - test_nonce(CipherSuiteVariant::AesGcm256Sha512); + let nonce: [u8; NONCE_LEN] = secret.create_nonce(&FrameCount::from(test_vec.frame_count)); + assert_bytes_eq(&nonce, &test_vec.nonce); } } diff --git a/src/error.rs b/src/error.rs index b6502f1..707e9f0 100644 --- a/src/error.rs +++ b/src/error.rs @@ -27,7 +27,7 @@ pub enum SframeError { /// Could not expand encryption key for [`Sender`] or decryption key for [`Receiver`] with HKDF #[error("Unable to create unbound encryption key")] - KeyExpansion, + KeyDerivation, /// frame validation failed in the [`Receiver`] before decryption #[error("{0}")] diff --git a/src/header/basic_header.rs b/src/header/basic_header.rs index d140b85..ddb8068 100644 --- a/src/header/basic_header.rs +++ b/src/header/basic_header.rs @@ -11,7 +11,7 @@ use super::{ }; bitfield! { - /// Modeled after [sframe draft 00 4.2](https://datatracker.ietf.org/doc/html/draft-ietf-sframe-enc-01#name-sframe-header) + /// Modeled after [sframe draft 03 4.3](https://datatracker.ietf.org/doc/html/draft-ietf-sframe-enc-03#name-sframe-header) /// ```txt /// 0 1 2 3 4 5 6 7 /// +-+-+-+-+-+-+-+-+---------------------------------+ diff --git a/src/header/extended_header.rs b/src/header/extended_header.rs index 853b842..62a6f76 100644 --- a/src/header/extended_header.rs +++ b/src/header/extended_header.rs @@ -13,7 +13,7 @@ use super::{ }; bitfield! { - /// Modeled after [sframe draft 00 4.2](https://datatracker.ietf.org/doc/html/draft-ietf-sframe-enc-01#name-sframe-header) + /// Modeled after [sframe draft 03 4.3](https://datatracker.ietf.org/doc/html/draft-ietf-sframe-enc-03#name-sframe-header) /// ```txt /// 0 1 2 3 4 5 6 7 /// +-+-+-+-+-+-+-+-+---------------------------+---------------------------+ diff --git a/src/header/mod.rs b/src/header/mod.rs index 4646145..13be405 100644 --- a/src/header/mod.rs +++ b/src/header/mod.rs @@ -44,7 +44,7 @@ pub trait HeaderFields { } /// Sframe header with a KID with a length of up to 3bits -/// modeled after [sframe draft 00 4.2](https://datatracker.ietf.org/doc/html/draft-ietf-sframe-enc-01#name-sframe-header) +/// modeled after [sframe draft 03 4.3](https://datatracker.ietf.org/doc/html/draft-ietf-sframe-enc-03#name-sframe-header) /// ```txt /// 0 1 2 3 4 5 6 7 /// +-+-+-+-+-+-+-+-+---------------------------------+ @@ -73,7 +73,7 @@ impl BasicHeader { } } /// Extended sframe header with a KID with a length of up to 8 bytes -/// modeled after [sframe draft 00 4.2](https://datatracker.ietf.org/doc/html/draft-ietf-sframe-enc-01#name-sframe-header) +/// modeled after [sframe draft 03 4.3](https://datatracker.ietf.org/doc/html/draft-ietf-sframe-enc-03#name-sframe-header) /// ```txt /// 0 1 2 3 4 5 6 7 /// +-+-+-+-+-+-+-+-+---------------------------+---------------------------+ @@ -102,7 +102,7 @@ impl ExtendedHeader { } #[derive(Copy, Clone, Debug)] -/// Represents an Sframe header modeled after [sframe draft 00 4.2](https://datatracker.ietf.org/doc/html/draft-ietf-sframe-enc-01#name-sframe-header) +/// Represents an Sframe header modeled after [sframe draft 03 4.3](https://datatracker.ietf.org/doc/html/draft-ietf-sframe-enc-03#name-sframe-header) /// containing the key id of the sender (KID) and the current frame count (CTR). /// There are two variants, either with a KID represented by 3 bits (Basic) and an extended version with a KID of up to 8 bytes (Extended). /// The CTR field has a variable length of up to 8 bytes where the size is represented with LEN. Here LEN=0 represents a length of 1. @@ -218,7 +218,6 @@ mod test { use super::{frame_count::FrameCount, keyid::KeyId, Header}; use crate::header::{Deserialization, HeaderFields}; use crate::util::test::assert_bytes_eq; - use crate::CipherSuiteVariant::{AesGcm128Sha256, AesGcm256Sha512}; use pretty_assertions::assert_eq; @@ -254,25 +253,23 @@ mod test { #[test] fn serialize_test_vectors() { - crate::test_vectors::get_test_vector(&AesGcm128Sha256.to_string()) - .encryptions + crate::test_vectors::get_header_test_vectors() .iter() .for_each(|test_vector| { let header = Header::with_frame_count( KeyId::from(test_vector.key_id), FrameCount::from(test_vector.frame_count), ); - assert_bytes_eq(Vec::from(&header).as_slice(), &test_vector.header); + assert_bytes_eq(Vec::from(&header).as_slice(), &test_vector.encoded); }); } #[test] fn deserialize_test_vectors() { - crate::test_vectors::get_test_vector(&AesGcm256Sha512.to_string()) - .encryptions + crate::test_vectors::get_header_test_vectors() .iter() .for_each(|test_vector| { - let header = Header::deserialize(&test_vector.header).unwrap(); + let header = Header::deserialize(&test_vector.encoded).unwrap(); assert_eq!(header.key_id(), KeyId::from(test_vector.key_id)); assert_eq!(header.frame_count(), test_vector.frame_count); }); diff --git a/src/receiver.rs b/src/receiver.rs index 42f430d..e04a9f8 100644 --- a/src/receiver.rs +++ b/src/receiver.rs @@ -7,7 +7,7 @@ use crate::{ crypto::{ aead::AeadDecrypt, cipher_suite::{CipherSuite, CipherSuiteVariant}, - key_expansion::KeyExpansion, + key_derivation::KeyDerivation, secret::Secret, }, error::{Result, SframeError}, @@ -107,9 +107,10 @@ impl Receiver { Id: Into<KeyId>, KeyMaterial: AsRef<[u8]> + ?Sized, { + let key_id = key_id.into(); self.secrets.insert( - key_id.into(), - Secret::expand_from(&self.options.cipher_suite, key_material)?, + key_id, + Secret::expand_from(&self.options.cipher_suite, key_material, key_id)?, ); Ok(()) } diff --git a/src/sender.rs b/src/sender.rs index 003b775..68e7be2 100644 --- a/src/sender.rs +++ b/src/sender.rs @@ -5,7 +5,7 @@ use crate::{ crypto::{ aead::AeadEncrypt, cipher_suite::{CipherSuite, CipherSuiteVariant}, - key_expansion::KeyExpansion, + key_derivation::KeyDerivation, secret::Secret, }, error::{Result, SframeError}, @@ -108,74 +108,15 @@ impl Sender { where KeyMaterial: AsRef<[u8]> + ?Sized, { - self.secret = Some(Secret::expand_from(&self.cipher_suite, key_material)?); + self.secret = Some(Secret::expand_from( + &self.cipher_suite, + key_material, + self.key_id, + )?); Ok(()) } } -#[cfg(test)] -mod test_on_wire_format { - use super::*; - use crate::receiver::Receiver; - - fn hex(hex_str: &str) -> Vec<u8> { - hex::decode(hex_str).unwrap() - } - - const KEY_ID: u8 = 0; - - #[test] - fn deadbeef_decrypt() { - let material = hex("1234567890123456789012345678901212345678901234567890123456789012"); - let mut sender = Sender::new(KEY_ID); - let mut receiver = Receiver::default(); - - sender.set_encryption_key(&material).unwrap(); - receiver.set_encryption_key(KEY_ID, &material).unwrap(); - - let encrypted = sender.encrypt(&hex("deadbeafcacadebaca00"), 4).unwrap(); - let decrypted = receiver.decrypt(encrypted, 4).unwrap(); - - assert_eq!(decrypted, hex("deadbeafcacadebaca00")); - } - - #[test] - fn deadbeef_on_wire() { - let material = hex("1234567890123456789012345678901212345678901234567890123456789012"); - let mut sender = Sender::new(KEY_ID); - let mut receiver = Receiver::default(); - - sender.set_encryption_key(&material).unwrap(); - receiver.set_encryption_key(KEY_ID, &material).unwrap(); - - let encrypted = sender.encrypt(&hex("deadbeafcacadebaca00"), 4).unwrap(); - - assert_eq!( - hex::encode(encrypted), - "deadbeaf0000a160a9176ba4ce7ca128df74907d422e5064d1c23529" - ); - } - - #[test] - fn deadbeef_on_wire_long() { - let material = hex("1234567890123456789012345678901212345678901234567890123456789012"); - let mut sender = Sender::new(KEY_ID); - let mut receiver = Receiver::default(); - - sender.set_encryption_key(&material).unwrap(); - receiver.set_encryption_key(KEY_ID, &material).unwrap(); - - let encrypted = sender - .encrypt(&hex("deadbeafcacadebacacacadebacacacadebaca00"), 4) - .unwrap(); - - assert_eq!( - hex::encode(encrypted), - "deadbeaf0000a160a9176b6ebe53f594a64faa1f48a5246b202d13416bf671b3edae7704a862" - ); - } -} - #[cfg(test)] mod test { use super::*; diff --git a/src/test_vectors/mod.rs b/src/test_vectors/mod.rs index d2fcfba..47f722b 100644 --- a/src/test_vectors/mod.rs +++ b/src/test_vectors/mod.rs @@ -5,8 +5,28 @@ extern crate serde; use phf::phf_map; -pub fn get_test_vector(cipher_suite_variant: &str) -> &'static TestVector { +#[derive(serde::Deserialize, Debug, Clone)] +pub struct TestVectors { + pub header: Vec<HeaderTest>, + pub aes_ctr_hmac: Vec<AesCtrHmacTest>, + pub sframe: Vec<SframeTest>, +} + +pub fn get_header_test_vectors() -> &'static Vec<HeaderTest> { + &TEST_VECTORS.header +} + +pub fn get_aes_ctr_test_vector(cipher_suite_variant: &str) -> &'static AesCtrHmacTest { + TEST_VECTORS + .aes_ctr_hmac + .iter() + .find(|v| v.cipher_suite_variant == cipher_suite_variant) + .unwrap() +} + +pub fn get_sframe_test_vector(cipher_suite_variant: &str) -> &'static SframeTest { TEST_VECTORS + .sframe .iter() .find(|v| v.cipher_suite_variant == cipher_suite_variant) .unwrap() @@ -14,54 +34,111 @@ pub fn get_test_vector(cipher_suite_variant: &str) -> &'static TestVector { const TEST_VECTORS_STR: &str = std::include_str!("test-vectors.json"); lazy_static::lazy_static! { -static ref TEST_VECTORS: Vec<TestVector> = { +static ref TEST_VECTORS: TestVectors = { parse_test_vectors() }; } const CIPHER_SUITE_NAME_FROM_ID: phf::Map<u8, &str> = phf_map! { - // AesCtr128HmacSha256_80 is not included in the test vectors - 1u8 => "AesCtr128HmacSha256_32", + 1u8 => "AesCtr128HmacSha256_80", 2u8 => "AesCtr128HmacSha256_64", - 3u8 => "AesGcm128Sha256", - 4u8 => "AesGcm256Sha512", + 3u8 => "AesCtr128HmacSha256_32", + 4u8 => "AesGcm128Sha256", + 5u8 => "AesGcm256Sha512", }; #[derive(serde::Deserialize, Debug, Clone)] -pub struct EncryptionTestCase { +pub struct HeaderTest { #[serde(rename = "kid")] pub key_id: u64, #[serde(rename = "ctr")] pub frame_count: u64, #[serde(deserialize_with = "vec_from_hex_str")] - pub header: Vec<u8>, + pub encoded: Vec<u8>, +} + +#[derive(serde::Deserialize, Debug, Clone)] +pub struct AesCtrHmacTest { + #[serde( + rename = "cipher_suite", + deserialize_with = "cipher_suite_name_from_id" + )] + pub cipher_suite_variant: String, + + #[serde(rename = "key", deserialize_with = "vec_from_hex_str")] + pub base_key: Vec<u8>, + + #[serde(deserialize_with = "vec_from_hex_str")] + pub aead_label: Vec<u8>, + + #[serde(deserialize_with = "vec_from_hex_str")] + pub aead_secret: Vec<u8>, + + #[serde(deserialize_with = "vec_from_hex_str")] + pub enc_key: Vec<u8>, + + #[serde(deserialize_with = "vec_from_hex_str")] + pub auth_key: Vec<u8>, + #[serde(deserialize_with = "vec_from_hex_str")] pub nonce: Vec<u8>, - #[serde(rename = "ciphertext", deserialize_with = "vec_from_hex_str")] + + #[serde(deserialize_with = "vec_from_hex_str")] + pub aad: Vec<u8>, + + #[serde(rename = "pt", deserialize_with = "vec_from_hex_str")] + pub plain_text: Vec<u8>, + + #[serde(rename = "ct", deserialize_with = "vec_from_hex_str")] pub cipher_text: Vec<u8>, } #[derive(serde::Deserialize, Debug, Clone)] -pub struct TestVector { +pub struct SframeTest { #[serde( rename = "cipher_suite", deserialize_with = "cipher_suite_name_from_id" )] pub cipher_suite_variant: String, + #[serde(rename = "kid")] + pub key_id: u64, + + #[serde(rename = "ctr")] + pub frame_count: u64, + #[serde(rename = "base_key", deserialize_with = "vec_from_hex_str")] pub key_material: Vec<u8>, #[serde(deserialize_with = "vec_from_hex_str")] - pub key: Vec<u8>, + pub sframe_key_label: Vec<u8>, + + #[serde(deserialize_with = "vec_from_hex_str")] + pub sframe_salt_label: Vec<u8>, + + #[serde(deserialize_with = "vec_from_hex_str")] + pub sframe_secret: Vec<u8>, + + #[serde(deserialize_with = "vec_from_hex_str")] + pub sframe_key: Vec<u8>, #[serde(deserialize_with = "vec_from_hex_str")] - pub salt: Vec<u8>, + pub sframe_salt: Vec<u8>, - #[serde(rename = "plaintext", deserialize_with = "vec_from_hex_str")] + #[serde(deserialize_with = "vec_from_hex_str")] + pub metadata: Vec<u8>, + + #[serde(deserialize_with = "vec_from_hex_str")] + pub nonce: Vec<u8>, + + #[serde(deserialize_with = "vec_from_hex_str")] + pub aad: Vec<u8>, + + #[serde(rename = "pt", deserialize_with = "vec_from_hex_str")] pub plain_text: Vec<u8>, - pub encryptions: Vec<EncryptionTestCase>, + #[serde(rename = "ct", deserialize_with = "vec_from_hex_str")] + pub cipher_text: Vec<u8>, } fn vec_from_hex_str<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error> @@ -88,20 +165,36 @@ where } } -fn parse_test_vectors() -> Vec<TestVector> { +fn parse_test_vectors() -> TestVectors { serde_json::from_str(TEST_VECTORS_STR).unwrap() } #[cfg(test)] mod test { - use super::{get_test_vector, CIPHER_SUITE_NAME_FROM_ID}; + use crate::test_vectors::{get_aes_ctr_test_vector, get_sframe_test_vector}; + use super::{get_header_test_vectors, CIPHER_SUITE_NAME_FROM_ID}; + + #[test] + fn should_parse_header_test_vectors() { + let header_tests = get_header_test_vectors(); + assert_ne!(header_tests.len(), 0); + } #[test] - fn should_parse_test_vectors() { + fn should_parse_sframe_test_vectors() { let valid_cipher_suite_variants = CIPHER_SUITE_NAME_FROM_ID.values(); for &variant in valid_cipher_suite_variants { - let vector = get_test_vector(variant); - assert_eq!(vector.cipher_suite_variant, variant); + let sframe_test = get_sframe_test_vector(variant); + assert_eq!(sframe_test.cipher_suite_variant, variant); + } + } + + #[test] + fn should_parse_aes_test_vectors() { + for cipher_suite_id in 1..=3u8 { + let &variant = CIPHER_SUITE_NAME_FROM_ID.get(&cipher_suite_id).unwrap(); + let aes_ctr_test = get_aes_ctr_test_vector(variant); + assert_eq!(aes_ctr_test.cipher_suite_variant, variant); } } } diff --git a/src/test_vectors/test-vectors.json b/src/test_vectors/test-vectors.json index 1edecde..98a6c15 100644 --- a/src/test_vectors/test-vectors.json +++ b/src/test_vectors/test-vectors.json @@ -1,234 +1,1569 @@ -[ - { - "cipher_suite": 1, - "base_key": "101112131415161718191a1b1c1d1e1f", - "key": "343d3290f5c0b936415bea9a43c6f5a2", - "salt": "42d662fbad5cd81eb3aad79a", - "plaintext": "46726f6d2068656176656e6c79206861726d6f6e79202f2f205468697320756e6976657273616c206672616d6520626567616e", - "encryptions": [ - { - "kid": 7, - "ctr": 0, - "header": "0700", - "nonce": "42d662fbad5cd81eb3aad79a", - "ciphertext": "0700c5095af9dbbbed6a952de114ea7b42768509f1ffc9749abb1e95bf4514d8d82a0eef4b5ecac16fa193977fa1aa1c9fa5c7e730b934669c" - }, - { - "kid": 7, - "ctr": 1, - "header": "0701", - "nonce": "42d662fbad5cd81eb3aad79b", - "ciphertext": "0701559e262525382885c6c93be8f61a9064db2dd1e1e96ab1dbd829ca4af4f45f2b97a4889217a3f8a2159fb8201b7d71db01702b9caf8df6" - }, - { - "kid": 7, - "ctr": 2, - "header": "0702", - "nonce": "42d662fbad5cd81eb3aad798", - "ciphertext": "07020a8f21e052eaa09e50da0a909d156cc55b9ef2f2abbcca765f7af3cfb1af234e3eac1dbc376631c83cf1ff1f8ab339dbc41044742c668d" - }, - { - "kid": 15, - "ctr": 170, - "header": "080faa", - "nonce": "42d662fbad5cd81eb3aad730", - "ciphertext": "080faa9c65aa5b167873f25827f17bc34879a4aaa6b38dd9584472e1849d5da51555f288d08f03166a5f26af01794006255c88b589861e2f8e3e" - }, - { - "kid": 511, - "ctr": 170, - "header": "0901ffaa", - "nonce": "42d662fbad5cd81eb3aad730", - "ciphertext": "0901ffaa9c65aa5b167873f25827f17bc34879a4aaa6b38dd9584472e1849d5da51555f288d08f03166a5f26af01794006255c88b58986ca1ead10" - }, - { - "kid": 511, - "ctr": 43690, - "header": "1901ffaaaa", - "nonce": "42d662fbad5cd81eb3aa7d30", - "ciphertext": "1901ffaaaa990cbeb4ae2e3a76be8bb954b62591e791d0fa53c0553bc1d1e021d270b1a10688cd89195203b01978925373b04f9c08c3a4e563e2f6b9" - }, - { - "kid": 72057594037927935, - "ctr": 72057594037927935, - "header": "6effffffffffffffffffffffffffff", - "nonce": "42d662fbada327e14c552865", - "ciphertext": "6effffffffffffffffffffffffffff412c43c8077c286f7df3dd9988d1bd033f1067493e09421e5bfc363e50a3c803b4da9239514cb924dbcb5f33e33112083e99108de2ecd6" - } - ] - }, - { - "cipher_suite": 2, - "base_key": "202122232425262728292a2b2c2d2e2f", - "key": "3fce747d505e46ec9b92d9f58ee7a5d4", - "salt": "77fbf5f1d82c73f6d2b353c9", - "plaintext": "46726f6d2068656176656e6c79206861726d6f6e79202f2f205468697320756e6976657273616c206672616d6520626567616e", - "encryptions": [ - { - "kid": 7, - "ctr": 0, - "header": "0700", - "nonce": "77fbf5f1d82c73f6d2b353c9", - "ciphertext": "07009d89e5753e06edf3025f1ccd70b095ebaf10c250e11da740f50f57b6ce860d7321dfa49688a2cd6c6d9a71ae9d5c14ad0978efdd719a7f18c48f07" - }, - { - "kid": 7, - "ctr": 1, - "header": "0701", - "nonce": "77fbf5f1d82c73f6d2b353c8", - "ciphertext": "0701becd2e9d10e3eed586491b3e0ecedba89407ae2151787c5117b55707d6b8a0754f4dc937e30ebdf7cafbd3769d6585d7991b1a6bd31e8bddb1adec" - }, - { - "kid": 7, - "ctr": 2, - "header": "0702", - "nonce": "77fbf5f1d82c73f6d2b353cb", - "ciphertext": "070298508be6b16d034f15b504ced45a86d1bb43ed7cd3a62bf25557d1b082b04e8e6ba6fe76160835dd8953e1be9640c988627ea447127ae4c103eabd" - }, - { - "kid": 15, - "ctr": 170, - "header": "080faa", - "nonce": "77fbf5f1d82c73f6d2b35363", - "ciphertext": "080faae7eec4b0556ddfb8068998351cd670ce95f0ce9cd4c6dca2eeee73fb14d20a0d0fd487337ed43fa7f98dad0995b8b870325aa35a105af9b1004b22" - }, - { - "kid": 511, - "ctr": 170, - "header": "0901ffaa", - "nonce": "77fbf5f1d82c73f6d2b35363", - "ciphertext": "0901ffaae7eec4b0556ddfb8068998351cd670ce95f0ce9cd4c6dca2eeee73fb14d20a0d0fd487337ed43fa7f98dad0995b8b870325aa3437cce05a6e67ee8" - }, - { - "kid": 511, - "ctr": 43690, - "header": "1901ffaaaa", - "nonce": "77fbf5f1d82c73f6d2b3f963", - "ciphertext": "1901ffaaaa8c1789aa0abcd6abc27006aae4df5cba4ba07f8113080e9726baacd16c18539974a6204a36b9dc3dcd36ed9ab48e590d95d4adfb4290f4cb1ba184" - }, - { - "kid": 72057594037927935, - "ctr": 72057594037927935, - "header": "6effffffffffffffffffffffffffff", - "nonce": "77fbf5f1d8d38c092d4cac36", - "ciphertext": "6effffffffffffffffffffffffffffa9bc6c7edde0fdfd13255a5b145c5ce84db8f8960858eb998b8ea8f3e770160150813c5806441b64251bdd2be9e8cec1386b6f8e3b1982bcd16c84" - } - ] - }, - { - "cipher_suite": 3, - "base_key": "303132333435363738393a3b3c3d3e3f", - "key": "2ea2e8163ff56c0613e6fa9f20a213da", - "salt": "a80478b3f6fba19983d540d5", - "plaintext": "46726f6d2068656176656e6c79206861726d6f6e79202f2f205468697320756e6976657273616c206672616d6520626567616e", - "encryptions": [ - { - "kid": 7, - "ctr": 0, - "header": "0700", - "nonce": "a80478b3f6fba19983d540d5", - "ciphertext": "07000e426255e47ed70dd7d15d69d759bf459032ca15f5e8b2a91e7d348aa7c186d403f620801c495b1717a35097411aa97cbb1406afd9f4e5215b46e4a39dc40c27fd6bc7" - }, - { - "kid": 7, - "ctr": 1, - "header": "0701", - "nonce": "a80478b3f6fba19983d540d4", - "ciphertext": "070103bbafa34ada8a6b9f2066bc34a1959d87384c9f4b1ce34fed58e938bde143393910b1aeb55b48d91d5b0db3ea67e3d0e02b84e4cf8ecf81f8386f86cda48fcd754191" - }, - { - "kid": 7, - "ctr": 2, - "header": "0702", - "nonce": "a80478b3f6fba19983d540d7", - "ciphertext": "070258d58adebd8bf6f3cc0c1fcacf34ba4d7a763b2683fe302a57f1be7f2a274bf81b2236995fec1203cadb146cd402e1c52d5e6aceaa5252822d25acd0ce4ba14e31fa24" - }, - { - "kid": 15, - "ctr": 170, - "header": "080faa", - "nonce": "a80478b3f6fba19983d5407f", - "ciphertext": "080faad0b1743bf5248f90869c9456366d55724d16bbe08060875815565e90b114f9ccbdba192422b33848a1ae1e3bd266a001b2f5bb64c0f1216bba82ab24b1ebd677c2ca29" - }, - { - "kid": 511, - "ctr": 170, - "header": "0901ffaa", - "nonce": "a80478b3f6fba19983d5407f", - "ciphertext": "0901ffaad0b1743bf5248f90869c9456366d55724d16bbe08060875815565e90b114f9ccbdba192422b33848a1ae1e3bd266a001b2f5bb8c718170432b6f922c1f0fb307514a0e" - }, - { - "kid": 511, - "ctr": 43690, - "header": "1901ffaaaa", - "nonce": "a80478b3f6fba19983d5ea7f", - "ciphertext": "1901ffaaaa9de65e21e4f1ca2247b87943c03c5cb7b182090e93d508dcfb76e08174c6397356e682d2eaddabc0b3c1018d2c13c3570f61c185789dff3cb4469cf471ca71ceb025a5" - }, - { - "kid": 72057594037927935, - "ctr": 72057594037927935, - "header": "6effffffffffffffffffffffffffff", - "nonce": "a80478b3f6045e667c2abf2a", - "ciphertext": "6effffffffffffffffffffffffffff09981bdcdad80e380b6f74cf6afdbce946839bedadd57578bfcd809dbcea535546cc24660613d2761adea852155785011e633522450f95fd9f8ccc96fa3de9a247cfd3" - } - ] - }, - { - "cipher_suite": 4, - "base_key": "404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f", - "key": "436774b0b5ae45633d96547f8f3cb06c8e6628eff2e4255b5c4d77e721aa3355", - "salt": "31ed26f90a072e6aee646298", - "plaintext": "46726f6d2068656176656e6c79206861726d6f6e79202f2f205468697320756e6976657273616c206672616d6520626567616e", - "encryptions": [ - { - "kid": 7, - "ctr": 0, - "header": "0700", - "nonce": "31ed26f90a072e6aee646298", - "ciphertext": "0700f3e297c1e95207710bd31ccc4ba396fbef7b257440bde638ff0f3c8911540136df61b26220249d6c432c245ae8d55ef45bfccf3afe18dd36d64d8e341653e1a0f10be2" - }, - { - "kid": 7, - "ctr": 1, - "header": "0701", - "nonce": "31ed26f90a072e6aee646299", - "ciphertext": "070193268b0bf030071bff443bb6b4471bdfb1cc81bc9625f4697b0336ff4665d15f152f02169448d8a967fb06359a87d2145398de044ee92acfcc27b7a98f38712b60c28c" - }, - { - "kid": 7, - "ctr": 2, - "header": "0702", - "nonce": "31ed26f90a072e6aee64629a", - "ciphertext": "0702649691ba27c4c01a41280fba4657c03fa7fe21c8f5c862e9094227c3ca3ec0d9468b1a2cb060ff0978f25a24e6b106f5a6e10534b69d975605f31534caea88b33b455a" - }, - { - "kid": 15, - "ctr": 170, - "header": "080faa", - "nonce": "31ed26f90a072e6aee646232", - "ciphertext": "080faa2858c10b5ddd231c1f26819490521678603a050448d563c503b1fd890d02ead01d754f074ecb6f32da9b2f3859f380b4f47d4ed539d6103e61580a82c014b28eb48b4a" - }, - { - "kid": 511, - "ctr": 170, - "header": "0901ffaa", - "nonce": "31ed26f90a072e6aee646232", - "ciphertext": "0901ffaa2858c10b5ddd231c1f26819490521678603a050448d563c503b1fd890d02ead01d754f074ecb6f32da9b2f3859f380b4f47d4e32c565b3b3fa20fc7ecff21a1cee3eec" - }, - { - "kid": 511, - "ctr": 43690, - "header": "1901ffaaaa", - "nonce": "31ed26f90a072e6aee64c832", - "ciphertext": "1901ffaaaad9bc6a258a07d210a814d545eca70321c0e87498ada6e5c708b7ead162ffcf4fbaba1eb82650590a87122b4d95fe36bd88b278994922fe5c09f14c728521333297f84f" - }, - { - "kid": 72057594037927935, - "ctr": 72057594037927935, - "header": "6effffffffffffffffffffffffffff", - "nonce": "31ed26f90af8d195119b9d67", - "ciphertext": "6effffffffffffffffffffffffffffaf480d4779ce0c02b5137ee6a61e026c04ac999cb0c97319feceeb258d58df23bce14979e5c67a431777b34498062e72f939ca4acb471bad80259bb44f78a152487e67" - } - ] - } -] +{ + "header": [ + { + "kid": 0, + "ctr": 0, + "encoded": "0000" + }, + { + "kid": 0, + "ctr": 1, + "encoded": "0001" + }, + { + "kid": 0, + "ctr": 255, + "encoded": "00ff" + }, + { + "kid": 0, + "ctr": 256, + "encoded": "100100" + }, + { + "kid": 0, + "ctr": 65535, + "encoded": "10ffff" + }, + { + "kid": 0, + "ctr": 65536, + "encoded": "20010000" + }, + { + "kid": 0, + "ctr": 16777215, + "encoded": "20ffffff" + }, + { + "kid": 0, + "ctr": 16777216, + "encoded": "3001000000" + }, + { + "kid": 0, + "ctr": 4294967295, + "encoded": "30ffffffff" + }, + { + "kid": 0, + "ctr": 4294967296, + "encoded": "400100000000" + }, + { + "kid": 0, + "ctr": 1099511627775, + "encoded": "40ffffffffff" + }, + { + "kid": 0, + "ctr": 1099511627776, + "encoded": "50010000000000" + }, + { + "kid": 0, + "ctr": 281474976710655, + "encoded": "50ffffffffffff" + }, + { + "kid": 0, + "ctr": 281474976710656, + "encoded": "6001000000000000" + }, + { + "kid": 0, + "ctr": 72057594037927935, + "encoded": "60ffffffffffffff" + }, + { + "kid": 0, + "ctr": 72057594037927936, + "encoded": "700100000000000000" + }, + { + "kid": 0, + "ctr": 18446744073709551615, + "encoded": "70ffffffffffffffff" + }, + { + "kid": 1, + "ctr": 0, + "encoded": "0100" + }, + { + "kid": 1, + "ctr": 1, + "encoded": "0101" + }, + { + "kid": 1, + "ctr": 255, + "encoded": "01ff" + }, + { + "kid": 1, + "ctr": 256, + "encoded": "110100" + }, + { + "kid": 1, + "ctr": 65535, + "encoded": "11ffff" + }, + { + "kid": 1, + "ctr": 65536, + "encoded": "21010000" + }, + { + "kid": 1, + "ctr": 16777215, + "encoded": "21ffffff" + }, + { + "kid": 1, + "ctr": 16777216, + "encoded": "3101000000" + }, + { + "kid": 1, + "ctr": 4294967295, + "encoded": "31ffffffff" + }, + { + "kid": 1, + "ctr": 4294967296, + "encoded": "410100000000" + }, + { + "kid": 1, + "ctr": 1099511627775, + "encoded": "41ffffffffff" + }, + { + "kid": 1, + "ctr": 1099511627776, + "encoded": "51010000000000" + }, + { + "kid": 1, + "ctr": 281474976710655, + "encoded": "51ffffffffffff" + }, + { + "kid": 1, + "ctr": 281474976710656, + "encoded": "6101000000000000" + }, + { + "kid": 1, + "ctr": 72057594037927935, + "encoded": "61ffffffffffffff" + }, + { + "kid": 1, + "ctr": 72057594037927936, + "encoded": "710100000000000000" + }, + { + "kid": 1, + "ctr": 18446744073709551615, + "encoded": "71ffffffffffffffff" + }, + { + "kid": 255, + "ctr": 0, + "encoded": "08ff00" + }, + { + "kid": 255, + "ctr": 1, + "encoded": "08ff01" + }, + { + "kid": 255, + "ctr": 255, + "encoded": "08ffff" + }, + { + "kid": 255, + "ctr": 256, + "encoded": "18ff0100" + }, + { + "kid": 255, + "ctr": 65535, + "encoded": "18ffffff" + }, + { + "kid": 255, + "ctr": 65536, + "encoded": "28ff010000" + }, + { + "kid": 255, + "ctr": 16777215, + "encoded": "28ffffffff" + }, + { + "kid": 255, + "ctr": 16777216, + "encoded": "38ff01000000" + }, + { + "kid": 255, + "ctr": 4294967295, + "encoded": "38ffffffffff" + }, + { + "kid": 255, + "ctr": 4294967296, + "encoded": "48ff0100000000" + }, + { + "kid": 255, + "ctr": 1099511627775, + "encoded": "48ffffffffffff" + }, + { + "kid": 255, + "ctr": 1099511627776, + "encoded": "58ff010000000000" + }, + { + "kid": 255, + "ctr": 281474976710655, + "encoded": "58ffffffffffffff" + }, + { + "kid": 255, + "ctr": 281474976710656, + "encoded": "68ff01000000000000" + }, + { + "kid": 255, + "ctr": 72057594037927935, + "encoded": "68ffffffffffffffff" + }, + { + "kid": 255, + "ctr": 72057594037927936, + "encoded": "78ff0100000000000000" + }, + { + "kid": 255, + "ctr": 18446744073709551615, + "encoded": "78ffffffffffffffffff" + }, + { + "kid": 256, + "ctr": 0, + "encoded": "09010000" + }, + { + "kid": 256, + "ctr": 1, + "encoded": "09010001" + }, + { + "kid": 256, + "ctr": 255, + "encoded": "090100ff" + }, + { + "kid": 256, + "ctr": 256, + "encoded": "1901000100" + }, + { + "kid": 256, + "ctr": 65535, + "encoded": "190100ffff" + }, + { + "kid": 256, + "ctr": 65536, + "encoded": "290100010000" + }, + { + "kid": 256, + "ctr": 16777215, + "encoded": "290100ffffff" + }, + { + "kid": 256, + "ctr": 16777216, + "encoded": "39010001000000" + }, + { + "kid": 256, + "ctr": 4294967295, + "encoded": "390100ffffffff" + }, + { + "kid": 256, + "ctr": 4294967296, + "encoded": "4901000100000000" + }, + { + "kid": 256, + "ctr": 1099511627775, + "encoded": "490100ffffffffff" + }, + { + "kid": 256, + "ctr": 1099511627776, + "encoded": "590100010000000000" + }, + { + "kid": 256, + "ctr": 281474976710655, + "encoded": "590100ffffffffffff" + }, + { + "kid": 256, + "ctr": 281474976710656, + "encoded": "69010001000000000000" + }, + { + "kid": 256, + "ctr": 72057594037927935, + "encoded": "690100ffffffffffffff" + }, + { + "kid": 256, + "ctr": 72057594037927936, + "encoded": "7901000100000000000000" + }, + { + "kid": 256, + "ctr": 18446744073709551615, + "encoded": "790100ffffffffffffffff" + }, + { + "kid": 65535, + "ctr": 0, + "encoded": "09ffff00" + }, + { + "kid": 65535, + "ctr": 1, + "encoded": "09ffff01" + }, + { + "kid": 65535, + "ctr": 255, + "encoded": "09ffffff" + }, + { + "kid": 65535, + "ctr": 256, + "encoded": "19ffff0100" + }, + { + "kid": 65535, + "ctr": 65535, + "encoded": "19ffffffff" + }, + { + "kid": 65535, + "ctr": 65536, + "encoded": "29ffff010000" + }, + { + "kid": 65535, + "ctr": 16777215, + "encoded": "29ffffffffff" + }, + { + "kid": 65535, + "ctr": 16777216, + "encoded": "39ffff01000000" + }, + { + "kid": 65535, + "ctr": 4294967295, + "encoded": "39ffffffffffff" + }, + { + "kid": 65535, + "ctr": 4294967296, + "encoded": "49ffff0100000000" + }, + { + "kid": 65535, + "ctr": 1099511627775, + "encoded": "49ffffffffffffff" + }, + { + "kid": 65535, + "ctr": 1099511627776, + "encoded": "59ffff010000000000" + }, + { + "kid": 65535, + "ctr": 281474976710655, + "encoded": "59ffffffffffffffff" + }, + { + "kid": 65535, + "ctr": 281474976710656, + "encoded": "69ffff01000000000000" + }, + { + "kid": 65535, + "ctr": 72057594037927935, + "encoded": "69ffffffffffffffffff" + }, + { + "kid": 65535, + "ctr": 72057594037927936, + "encoded": "79ffff0100000000000000" + }, + { + "kid": 65535, + "ctr": 18446744073709551615, + "encoded": "79ffffffffffffffffffff" + }, + { + "kid": 65536, + "ctr": 0, + "encoded": "0a01000000" + }, + { + "kid": 65536, + "ctr": 1, + "encoded": "0a01000001" + }, + { + "kid": 65536, + "ctr": 255, + "encoded": "0a010000ff" + }, + { + "kid": 65536, + "ctr": 256, + "encoded": "1a0100000100" + }, + { + "kid": 65536, + "ctr": 65535, + "encoded": "1a010000ffff" + }, + { + "kid": 65536, + "ctr": 65536, + "encoded": "2a010000010000" + }, + { + "kid": 65536, + "ctr": 16777215, + "encoded": "2a010000ffffff" + }, + { + "kid": 65536, + "ctr": 16777216, + "encoded": "3a01000001000000" + }, + { + "kid": 65536, + "ctr": 4294967295, + "encoded": "3a010000ffffffff" + }, + { + "kid": 65536, + "ctr": 4294967296, + "encoded": "4a0100000100000000" + }, + { + "kid": 65536, + "ctr": 1099511627775, + "encoded": "4a010000ffffffffff" + }, + { + "kid": 65536, + "ctr": 1099511627776, + "encoded": "5a010000010000000000" + }, + { + "kid": 65536, + "ctr": 281474976710655, + "encoded": "5a010000ffffffffffff" + }, + { + "kid": 65536, + "ctr": 281474976710656, + "encoded": "6a01000001000000000000" + }, + { + "kid": 65536, + "ctr": 72057594037927935, + "encoded": "6a010000ffffffffffffff" + }, + { + "kid": 65536, + "ctr": 72057594037927936, + "encoded": "7a0100000100000000000000" + }, + { + "kid": 65536, + "ctr": 18446744073709551615, + "encoded": "7a010000ffffffffffffffff" + }, + { + "kid": 16777215, + "ctr": 0, + "encoded": "0affffff00" + }, + { + "kid": 16777215, + "ctr": 1, + "encoded": "0affffff01" + }, + { + "kid": 16777215, + "ctr": 255, + "encoded": "0affffffff" + }, + { + "kid": 16777215, + "ctr": 256, + "encoded": "1affffff0100" + }, + { + "kid": 16777215, + "ctr": 65535, + "encoded": "1affffffffff" + }, + { + "kid": 16777215, + "ctr": 65536, + "encoded": "2affffff010000" + }, + { + "kid": 16777215, + "ctr": 16777215, + "encoded": "2affffffffffff" + }, + { + "kid": 16777215, + "ctr": 16777216, + "encoded": "3affffff01000000" + }, + { + "kid": 16777215, + "ctr": 4294967295, + "encoded": "3affffffffffffff" + }, + { + "kid": 16777215, + "ctr": 4294967296, + "encoded": "4affffff0100000000" + }, + { + "kid": 16777215, + "ctr": 1099511627775, + "encoded": "4affffffffffffffff" + }, + { + "kid": 16777215, + "ctr": 1099511627776, + "encoded": "5affffff010000000000" + }, + { + "kid": 16777215, + "ctr": 281474976710655, + "encoded": "5affffffffffffffffff" + }, + { + "kid": 16777215, + "ctr": 281474976710656, + "encoded": "6affffff01000000000000" + }, + { + "kid": 16777215, + "ctr": 72057594037927935, + "encoded": "6affffffffffffffffffff" + }, + { + "kid": 16777215, + "ctr": 72057594037927936, + "encoded": "7affffff0100000000000000" + }, + { + "kid": 16777215, + "ctr": 18446744073709551615, + "encoded": "7affffffffffffffffffffff" + }, + { + "kid": 16777216, + "ctr": 0, + "encoded": "0b0100000000" + }, + { + "kid": 16777216, + "ctr": 1, + "encoded": "0b0100000001" + }, + { + "kid": 16777216, + "ctr": 255, + "encoded": "0b01000000ff" + }, + { + "kid": 16777216, + "ctr": 256, + "encoded": "1b010000000100" + }, + { + "kid": 16777216, + "ctr": 65535, + "encoded": "1b01000000ffff" + }, + { + "kid": 16777216, + "ctr": 65536, + "encoded": "2b01000000010000" + }, + { + "kid": 16777216, + "ctr": 16777215, + "encoded": "2b01000000ffffff" + }, + { + "kid": 16777216, + "ctr": 16777216, + "encoded": "3b0100000001000000" + }, + { + "kid": 16777216, + "ctr": 4294967295, + "encoded": "3b01000000ffffffff" + }, + { + "kid": 16777216, + "ctr": 4294967296, + "encoded": "4b010000000100000000" + }, + { + "kid": 16777216, + "ctr": 1099511627775, + "encoded": "4b01000000ffffffffff" + }, + { + "kid": 16777216, + "ctr": 1099511627776, + "encoded": "5b01000000010000000000" + }, + { + "kid": 16777216, + "ctr": 281474976710655, + "encoded": "5b01000000ffffffffffff" + }, + { + "kid": 16777216, + "ctr": 281474976710656, + "encoded": "6b0100000001000000000000" + }, + { + "kid": 16777216, + "ctr": 72057594037927935, + "encoded": "6b01000000ffffffffffffff" + }, + { + "kid": 16777216, + "ctr": 72057594037927936, + "encoded": "7b010000000100000000000000" + }, + { + "kid": 16777216, + "ctr": 18446744073709551615, + "encoded": "7b01000000ffffffffffffffff" + }, + { + "kid": 4294967295, + "ctr": 0, + "encoded": "0bffffffff00" + }, + { + "kid": 4294967295, + "ctr": 1, + "encoded": "0bffffffff01" + }, + { + "kid": 4294967295, + "ctr": 255, + "encoded": "0bffffffffff" + }, + { + "kid": 4294967295, + "ctr": 256, + "encoded": "1bffffffff0100" + }, + { + "kid": 4294967295, + "ctr": 65535, + "encoded": "1bffffffffffff" + }, + { + "kid": 4294967295, + "ctr": 65536, + "encoded": "2bffffffff010000" + }, + { + "kid": 4294967295, + "ctr": 16777215, + "encoded": "2bffffffffffffff" + }, + { + "kid": 4294967295, + "ctr": 16777216, + "encoded": "3bffffffff01000000" + }, + { + "kid": 4294967295, + "ctr": 4294967295, + "encoded": "3bffffffffffffffff" + }, + { + "kid": 4294967295, + "ctr": 4294967296, + "encoded": "4bffffffff0100000000" + }, + { + "kid": 4294967295, + "ctr": 1099511627775, + "encoded": "4bffffffffffffffffff" + }, + { + "kid": 4294967295, + "ctr": 1099511627776, + "encoded": "5bffffffff010000000000" + }, + { + "kid": 4294967295, + "ctr": 281474976710655, + "encoded": "5bffffffffffffffffffff" + }, + { + "kid": 4294967295, + "ctr": 281474976710656, + "encoded": "6bffffffff01000000000000" + }, + { + "kid": 4294967295, + "ctr": 72057594037927935, + "encoded": "6bffffffffffffffffffffff" + }, + { + "kid": 4294967295, + "ctr": 72057594037927936, + "encoded": "7bffffffff0100000000000000" + }, + { + "kid": 4294967295, + "ctr": 18446744073709551615, + "encoded": "7bffffffffffffffffffffffff" + }, + { + "kid": 4294967296, + "ctr": 0, + "encoded": "0c010000000000" + }, + { + "kid": 4294967296, + "ctr": 1, + "encoded": "0c010000000001" + }, + { + "kid": 4294967296, + "ctr": 255, + "encoded": "0c0100000000ff" + }, + { + "kid": 4294967296, + "ctr": 256, + "encoded": "1c01000000000100" + }, + { + "kid": 4294967296, + "ctr": 65535, + "encoded": "1c0100000000ffff" + }, + { + "kid": 4294967296, + "ctr": 65536, + "encoded": "2c0100000000010000" + }, + { + "kid": 4294967296, + "ctr": 16777215, + "encoded": "2c0100000000ffffff" + }, + { + "kid": 4294967296, + "ctr": 16777216, + "encoded": "3c010000000001000000" + }, + { + "kid": 4294967296, + "ctr": 4294967295, + "encoded": "3c0100000000ffffffff" + }, + { + "kid": 4294967296, + "ctr": 4294967296, + "encoded": "4c01000000000100000000" + }, + { + "kid": 4294967296, + "ctr": 1099511627775, + "encoded": "4c0100000000ffffffffff" + }, + { + "kid": 4294967296, + "ctr": 1099511627776, + "encoded": "5c0100000000010000000000" + }, + { + "kid": 4294967296, + "ctr": 281474976710655, + "encoded": "5c0100000000ffffffffffff" + }, + { + "kid": 4294967296, + "ctr": 281474976710656, + "encoded": "6c010000000001000000000000" + }, + { + "kid": 4294967296, + "ctr": 72057594037927935, + "encoded": "6c0100000000ffffffffffffff" + }, + { + "kid": 4294967296, + "ctr": 72057594037927936, + "encoded": "7c01000000000100000000000000" + }, + { + "kid": 4294967296, + "ctr": 18446744073709551615, + "encoded": "7c0100000000ffffffffffffffff" + }, + { + "kid": 1099511627775, + "ctr": 0, + "encoded": "0cffffffffff00" + }, + { + "kid": 1099511627775, + "ctr": 1, + "encoded": "0cffffffffff01" + }, + { + "kid": 1099511627775, + "ctr": 255, + "encoded": "0cffffffffffff" + }, + { + "kid": 1099511627775, + "ctr": 256, + "encoded": "1cffffffffff0100" + }, + { + "kid": 1099511627775, + "ctr": 65535, + "encoded": "1cffffffffffffff" + }, + { + "kid": 1099511627775, + "ctr": 65536, + "encoded": "2cffffffffff010000" + }, + { + "kid": 1099511627775, + "ctr": 16777215, + "encoded": "2cffffffffffffffff" + }, + { + "kid": 1099511627775, + "ctr": 16777216, + "encoded": "3cffffffffff01000000" + }, + { + "kid": 1099511627775, + "ctr": 4294967295, + "encoded": "3cffffffffffffffffff" + }, + { + "kid": 1099511627775, + "ctr": 4294967296, + "encoded": "4cffffffffff0100000000" + }, + { + "kid": 1099511627775, + "ctr": 1099511627775, + "encoded": "4cffffffffffffffffffff" + }, + { + "kid": 1099511627775, + "ctr": 1099511627776, + "encoded": "5cffffffffff010000000000" + }, + { + "kid": 1099511627775, + "ctr": 281474976710655, + "encoded": "5cffffffffffffffffffffff" + }, + { + "kid": 1099511627775, + "ctr": 281474976710656, + "encoded": "6cffffffffff01000000000000" + }, + { + "kid": 1099511627775, + "ctr": 72057594037927935, + "encoded": "6cffffffffffffffffffffffff" + }, + { + "kid": 1099511627775, + "ctr": 72057594037927936, + "encoded": "7cffffffffff0100000000000000" + }, + { + "kid": 1099511627775, + "ctr": 18446744073709551615, + "encoded": "7cffffffffffffffffffffffffff" + }, + { + "kid": 1099511627776, + "ctr": 0, + "encoded": "0d01000000000000" + }, + { + "kid": 1099511627776, + "ctr": 1, + "encoded": "0d01000000000001" + }, + { + "kid": 1099511627776, + "ctr": 255, + "encoded": "0d010000000000ff" + }, + { + "kid": 1099511627776, + "ctr": 256, + "encoded": "1d0100000000000100" + }, + { + "kid": 1099511627776, + "ctr": 65535, + "encoded": "1d010000000000ffff" + }, + { + "kid": 1099511627776, + "ctr": 65536, + "encoded": "2d010000000000010000" + }, + { + "kid": 1099511627776, + "ctr": 16777215, + "encoded": "2d010000000000ffffff" + }, + { + "kid": 1099511627776, + "ctr": 16777216, + "encoded": "3d01000000000001000000" + }, + { + "kid": 1099511627776, + "ctr": 4294967295, + "encoded": "3d010000000000ffffffff" + }, + { + "kid": 1099511627776, + "ctr": 4294967296, + "encoded": "4d0100000000000100000000" + }, + { + "kid": 1099511627776, + "ctr": 1099511627775, + "encoded": "4d010000000000ffffffffff" + }, + { + "kid": 1099511627776, + "ctr": 1099511627776, + "encoded": "5d010000000000010000000000" + }, + { + "kid": 1099511627776, + "ctr": 281474976710655, + "encoded": "5d010000000000ffffffffffff" + }, + { + "kid": 1099511627776, + "ctr": 281474976710656, + "encoded": "6d01000000000001000000000000" + }, + { + "kid": 1099511627776, + "ctr": 72057594037927935, + "encoded": "6d010000000000ffffffffffffff" + }, + { + "kid": 1099511627776, + "ctr": 72057594037927936, + "encoded": "7d0100000000000100000000000000" + }, + { + "kid": 1099511627776, + "ctr": 18446744073709551615, + "encoded": "7d010000000000ffffffffffffffff" + }, + { + "kid": 281474976710655, + "ctr": 0, + "encoded": "0dffffffffffff00" + }, + { + "kid": 281474976710655, + "ctr": 1, + "encoded": "0dffffffffffff01" + }, + { + "kid": 281474976710655, + "ctr": 255, + "encoded": "0dffffffffffffff" + }, + { + "kid": 281474976710655, + "ctr": 256, + "encoded": "1dffffffffffff0100" + }, + { + "kid": 281474976710655, + "ctr": 65535, + "encoded": "1dffffffffffffffff" + }, + { + "kid": 281474976710655, + "ctr": 65536, + "encoded": "2dffffffffffff010000" + }, + { + "kid": 281474976710655, + "ctr": 16777215, + "encoded": "2dffffffffffffffffff" + }, + { + "kid": 281474976710655, + "ctr": 16777216, + "encoded": "3dffffffffffff01000000" + }, + { + "kid": 281474976710655, + "ctr": 4294967295, + "encoded": "3dffffffffffffffffffff" + }, + { + "kid": 281474976710655, + "ctr": 4294967296, + "encoded": "4dffffffffffff0100000000" + }, + { + "kid": 281474976710655, + "ctr": 1099511627775, + "encoded": "4dffffffffffffffffffffff" + }, + { + "kid": 281474976710655, + "ctr": 1099511627776, + "encoded": "5dffffffffffff010000000000" + }, + { + "kid": 281474976710655, + "ctr": 281474976710655, + "encoded": "5dffffffffffffffffffffffff" + }, + { + "kid": 281474976710655, + "ctr": 281474976710656, + "encoded": "6dffffffffffff01000000000000" + }, + { + "kid": 281474976710655, + "ctr": 72057594037927935, + "encoded": "6dffffffffffffffffffffffffff" + }, + { + "kid": 281474976710655, + "ctr": 72057594037927936, + "encoded": "7dffffffffffff0100000000000000" + }, + { + "kid": 281474976710655, + "ctr": 18446744073709551615, + "encoded": "7dffffffffffffffffffffffffffff" + }, + { + "kid": 281474976710656, + "ctr": 0, + "encoded": "0e0100000000000000" + }, + { + "kid": 281474976710656, + "ctr": 1, + "encoded": "0e0100000000000001" + }, + { + "kid": 281474976710656, + "ctr": 255, + "encoded": "0e01000000000000ff" + }, + { + "kid": 281474976710656, + "ctr": 256, + "encoded": "1e010000000000000100" + }, + { + "kid": 281474976710656, + "ctr": 65535, + "encoded": "1e01000000000000ffff" + }, + { + "kid": 281474976710656, + "ctr": 65536, + "encoded": "2e01000000000000010000" + }, + { + "kid": 281474976710656, + "ctr": 16777215, + "encoded": "2e01000000000000ffffff" + }, + { + "kid": 281474976710656, + "ctr": 16777216, + "encoded": "3e0100000000000001000000" + }, + { + "kid": 281474976710656, + "ctr": 4294967295, + "encoded": "3e01000000000000ffffffff" + }, + { + "kid": 281474976710656, + "ctr": 4294967296, + "encoded": "4e010000000000000100000000" + }, + { + "kid": 281474976710656, + "ctr": 1099511627775, + "encoded": "4e01000000000000ffffffffff" + }, + { + "kid": 281474976710656, + "ctr": 1099511627776, + "encoded": "5e01000000000000010000000000" + }, + { + "kid": 281474976710656, + "ctr": 281474976710655, + "encoded": "5e01000000000000ffffffffffff" + }, + { + "kid": 281474976710656, + "ctr": 281474976710656, + "encoded": "6e0100000000000001000000000000" + }, + { + "kid": 281474976710656, + "ctr": 72057594037927935, + "encoded": "6e01000000000000ffffffffffffff" + }, + { + "kid": 281474976710656, + "ctr": 72057594037927936, + "encoded": "7e010000000000000100000000000000" + }, + { + "kid": 281474976710656, + "ctr": 18446744073709551615, + "encoded": "7e01000000000000ffffffffffffffff" + }, + { + "kid": 72057594037927935, + "ctr": 0, + "encoded": "0effffffffffffff00" + }, + { + "kid": 72057594037927935, + "ctr": 1, + "encoded": "0effffffffffffff01" + }, + { + "kid": 72057594037927935, + "ctr": 255, + "encoded": "0effffffffffffffff" + }, + { + "kid": 72057594037927935, + "ctr": 256, + "encoded": "1effffffffffffff0100" + }, + { + "kid": 72057594037927935, + "ctr": 65535, + "encoded": "1effffffffffffffffff" + }, + { + "kid": 72057594037927935, + "ctr": 65536, + "encoded": "2effffffffffffff010000" + }, + { + "kid": 72057594037927935, + "ctr": 16777215, + "encoded": "2effffffffffffffffffff" + }, + { + "kid": 72057594037927935, + "ctr": 16777216, + "encoded": "3effffffffffffff01000000" + }, + { + "kid": 72057594037927935, + "ctr": 4294967295, + "encoded": "3effffffffffffffffffffff" + }, + { + "kid": 72057594037927935, + "ctr": 4294967296, + "encoded": "4effffffffffffff0100000000" + }, + { + "kid": 72057594037927935, + "ctr": 1099511627775, + "encoded": "4effffffffffffffffffffffff" + }, + { + "kid": 72057594037927935, + "ctr": 1099511627776, + "encoded": "5effffffffffffff010000000000" + }, + { + "kid": 72057594037927935, + "ctr": 281474976710655, + "encoded": "5effffffffffffffffffffffffff" + }, + { + "kid": 72057594037927935, + "ctr": 281474976710656, + "encoded": "6effffffffffffff01000000000000" + }, + { + "kid": 72057594037927935, + "ctr": 72057594037927935, + "encoded": "6effffffffffffffffffffffffffff" + }, + { + "kid": 72057594037927935, + "ctr": 72057594037927936, + "encoded": "7effffffffffffff0100000000000000" + }, + { + "kid": 72057594037927935, + "ctr": 18446744073709551615, + "encoded": "7effffffffffffffffffffffffffffff" + }, + { + "kid": 72057594037927936, + "ctr": 0, + "encoded": "0f010000000000000000" + }, + { + "kid": 72057594037927936, + "ctr": 1, + "encoded": "0f010000000000000001" + }, + { + "kid": 72057594037927936, + "ctr": 255, + "encoded": "0f0100000000000000ff" + }, + { + "kid": 72057594037927936, + "ctr": 256, + "encoded": "1f01000000000000000100" + }, + { + "kid": 72057594037927936, + "ctr": 65535, + "encoded": "1f0100000000000000ffff" + }, + { + "kid": 72057594037927936, + "ctr": 65536, + "encoded": "2f0100000000000000010000" + }, + { + "kid": 72057594037927936, + "ctr": 16777215, + "encoded": "2f0100000000000000ffffff" + }, + { + "kid": 72057594037927936, + "ctr": 16777216, + "encoded": "3f010000000000000001000000" + }, + { + "kid": 72057594037927936, + "ctr": 4294967295, + "encoded": "3f0100000000000000ffffffff" + }, + { + "kid": 72057594037927936, + "ctr": 4294967296, + "encoded": "4f01000000000000000100000000" + }, + { + "kid": 72057594037927936, + "ctr": 1099511627775, + "encoded": "4f0100000000000000ffffffffff" + }, + { + "kid": 72057594037927936, + "ctr": 1099511627776, + "encoded": "5f0100000000000000010000000000" + }, + { + "kid": 72057594037927936, + "ctr": 281474976710655, + "encoded": "5f0100000000000000ffffffffffff" + }, + { + "kid": 72057594037927936, + "ctr": 281474976710656, + "encoded": "6f010000000000000001000000000000" + }, + { + "kid": 72057594037927936, + "ctr": 72057594037927935, + "encoded": "6f0100000000000000ffffffffffffff" + }, + { + "kid": 72057594037927936, + "ctr": 72057594037927936, + "encoded": "7f01000000000000000100000000000000" + }, + { + "kid": 72057594037927936, + "ctr": 18446744073709551615, + "encoded": "7f0100000000000000ffffffffffffffff" + }, + { + "kid": 18446744073709551615, + "ctr": 0, + "encoded": "0fffffffffffffffff00" + }, + { + "kid": 18446744073709551615, + "ctr": 1, + "encoded": "0fffffffffffffffff01" + }, + { + "kid": 18446744073709551615, + "ctr": 255, + "encoded": "0fffffffffffffffffff" + }, + { + "kid": 18446744073709551615, + "ctr": 256, + "encoded": "1fffffffffffffffff0100" + }, + { + "kid": 18446744073709551615, + "ctr": 65535, + "encoded": "1fffffffffffffffffffff" + }, + { + "kid": 18446744073709551615, + "ctr": 65536, + "encoded": "2fffffffffffffffff010000" + }, + { + "kid": 18446744073709551615, + "ctr": 16777215, + "encoded": "2fffffffffffffffffffffff" + }, + { + "kid": 18446744073709551615, + "ctr": 16777216, + "encoded": "3fffffffffffffffff01000000" + }, + { + "kid": 18446744073709551615, + "ctr": 4294967295, + "encoded": "3fffffffffffffffffffffffff" + }, + { + "kid": 18446744073709551615, + "ctr": 4294967296, + "encoded": "4fffffffffffffffff0100000000" + }, + { + "kid": 18446744073709551615, + "ctr": 1099511627775, + "encoded": "4fffffffffffffffffffffffffff" + }, + { + "kid": 18446744073709551615, + "ctr": 1099511627776, + "encoded": "5fffffffffffffffff010000000000" + }, + { + "kid": 18446744073709551615, + "ctr": 281474976710655, + "encoded": "5fffffffffffffffffffffffffffff" + }, + { + "kid": 18446744073709551615, + "ctr": 281474976710656, + "encoded": "6fffffffffffffffff01000000000000" + }, + { + "kid": 18446744073709551615, + "ctr": 72057594037927935, + "encoded": "6fffffffffffffffffffffffffffffff" + }, + { + "kid": 18446744073709551615, + "ctr": 72057594037927936, + "encoded": "7fffffffffffffffff0100000000000000" + }, + { + "kid": 18446744073709551615, + "ctr": 18446744073709551615, + "encoded": "7fffffffffffffffffffffffffffffffff" + } + ], + "aes_ctr_hmac": [ + { + "cipher_suite": 1, + "key": "000102030405060708090a0b0c0d0e0f", + "aead_label": "534672616d6520312e302041455320435452204145414420000000000000000a", + "aead_secret": "fda0fef7af62639ae1c6440f430395f54623f9a49db659201312ed6d9999a580", + "enc_key": "d6a61ca11fe8397b24954cda8b9543cf", + "auth_key": "0a43277c91120b7c7b6584bede06fcdfe0d07f9d1c9f15fcf0cad50aaecdd585", + "nonce": "101112131415161718191a1b", + "aad": "4945544620534672616d65205747", + "pt": "64726166742d696574662d736672616d652d656e63", + "ct": "1075c7114e10c12f20a709450ef8a891e9f070d4fae7b01f558599c929fdfd" + }, + { + "cipher_suite": 2, + "key": "000102030405060708090a0b0c0d0e0f", + "aead_label": "534672616d6520312e3020414553204354522041454144200000000000000008", + "aead_secret": "a0d71a69b2033a5a246eefbed19d95aee712a7639a752e5ad3a2b44c9f331caa", + "enc_key": "0ef75d1dd74b81e4d2252e6daa7226da", + "auth_key": "5584d32db18ede79fe8071a334ff31eb2ca0249a7845a61965d2ec620a50c59e", + "nonce": "101112131415161718191a1b", + "aad": "4945544620534672616d65205747", + "pt": "64726166742d696574662d736672616d652d656e63", + "ct": "f8551395579efc8dfdda575ed1a048f8b6cbf0e85653f0a514dea191e4" + }, + { + "cipher_suite": 3, + "key": "000102030405060708090a0b0c0d0e0f", + "aead_label": "534672616d6520312e3020414553204354522041454144200000000000000004", + "aead_secret": "ff69640f46d50930ce38bcf5aa5f6417a5bff98a991c79da06a0be460211dd36", + "enc_key": "96a673a94981bd85e71fcf05c79f2a01", + "auth_key": "bbf3b39da1eb8ed31fc5e0b26896a070f1a43e5ad3009b4c9d6c32e77ac68fce", + "nonce": "101112131415161718191a1b", + "aad": "4945544620534672616d65205747", + "pt": "64726166742d696574662d736672616d652d656e63", + "ct": "d6455bdbe7b5e8cdda861a8e90835637c0f7990349ce9052e6" + } + ], + "sframe": [ + { + "cipher_suite": 1, + "kid": 291, + "ctr": 17767, + "base_key": "000102030405060708090a0b0c0d0e0f", + "sframe_key_label": "534672616d6520312e3020536563726574206b6579200000000000000123", + "sframe_salt_label": "534672616d6520312e30205365637265742073616c74200000000000000123", + "sframe_secret": "d926952ca8b7ec4a95941d1ada3a5203ceff8cceee34f574d23909eb314c40c0", + "sframe_key": "73bb177a9fe6c02597132fe430ca2d99", + "sframe_salt": "55582aa5aaced36a74544d91", + "metadata": "4945544620534672616d65205747", + "nonce": "55582aa5aaced36a745408f6", + "aad": "19012345674945544620534672616d65205747", + "pt": "64726166742d696574662d736672616d652d656e63", + "ct": "190123456740043f25262c0ca52e9374b070f24b02764715c2e303388c9495324037d043" + }, + { + "cipher_suite": 2, + "kid": 291, + "ctr": 17767, + "base_key": "000102030405060708090a0b0c0d0e0f", + "sframe_key_label": "534672616d6520312e3020536563726574206b6579200000000000000123", + "sframe_salt_label": "534672616d6520312e30205365637265742073616c74200000000000000123", + "sframe_secret": "d926952ca8b7ec4a95941d1ada3a5203ceff8cceee34f574d23909eb314c40c0", + "sframe_key": "73bb177a9fe6c02597132fe430ca2d99", + "sframe_salt": "55582aa5aaced36a74544d91", + "metadata": "4945544620534672616d65205747", + "nonce": "55582aa5aaced36a745408f6", + "aad": "19012345674945544620534672616d65205747", + "pt": "64726166742d696574662d736672616d652d656e63", + "ct": "1901234567729eef4910d734abfd392cdff0f67d2a8d06041eef5f895e4cecc03a6d" + }, + { + "cipher_suite": 3, + "kid": 291, + "ctr": 17767, + "base_key": "000102030405060708090a0b0c0d0e0f", + "sframe_key_label": "534672616d6520312e3020536563726574206b6579200000000000000123", + "sframe_salt_label": "534672616d6520312e30205365637265742073616c74200000000000000123", + "sframe_secret": "d926952ca8b7ec4a95941d1ada3a5203ceff8cceee34f574d23909eb314c40c0", + "sframe_key": "73bb177a9fe6c02597132fe430ca2d99", + "sframe_salt": "55582aa5aaced36a74544d91", + "metadata": "4945544620534672616d65205747", + "nonce": "55582aa5aaced36a745408f6", + "aad": "19012345674945544620534672616d65205747", + "pt": "64726166742d696574662d736672616d652d656e63", + "ct": "190123456717fd0a325fdcd5f0d68089ee5bd17df6296b69b6b0e70c8d73" + }, + { + "cipher_suite": 4, + "kid": 291, + "ctr": 17767, + "base_key": "000102030405060708090a0b0c0d0e0f", + "sframe_key_label": "534672616d6520312e3020536563726574206b6579200000000000000123", + "sframe_salt_label": "534672616d6520312e30205365637265742073616c74200000000000000123", + "sframe_secret": "d926952ca8b7ec4a95941d1ada3a5203ceff8cceee34f574d23909eb314c40c0", + "sframe_key": "73bb177a9fe6c02597132fe430ca2d99", + "sframe_salt": "55582aa5aaced36a74544d91", + "metadata": "4945544620534672616d65205747", + "nonce": "55582aa5aaced36a745408f6", + "aad": "19012345674945544620534672616d65205747", + "pt": "64726166742d696574662d736672616d652d656e63", + "ct": "1901234567b8bf87709717f709a35b4e91b2109e5c1ca4f76179415f8bb15d70a9be7eb89c7adb76d300" + }, + { + "cipher_suite": 5, + "kid": 291, + "ctr": 17767, + "base_key": "000102030405060708090a0b0c0d0e0f", + "sframe_key_label": "534672616d6520312e3020536563726574206b6579200000000000000123", + "sframe_salt_label": "534672616d6520312e30205365637265742073616c74200000000000000123", + "sframe_secret": "0fc3ea6de6aac97a35f194cf9bed94d4b5230f1cb45a785c9fe5dce9c188938ab6ba005bc4c0a19181599e9d1bcf7b74aca48b60bf5e254e546d809313e083a3", + "sframe_key": "e9e405efb7cd325030760935bf49fd5669d7c19eb84ca74b419a1487cf835107", + "sframe_salt": "11007b537a1cf728a4c544c1", + "metadata": "4945544620534672616d65205747", + "nonce": "11007b537a1cf728a4c501a6", + "aad": "19012345674945544620534672616d65205747", + "pt": "64726166742d696574662d736672616d652d656e63", + "ct": "19012345671e11c62748536fd55fdbc9560daea4825bfecbb05489cd41cb7a1556e001989a4485e8a02f" + } + ] +}