use crate::{Error, Result};
use blake2::VarBlake2b;
use rand::{CryptoRng, Rng};
use std::fmt::{self, Debug};
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Hash([u8; HASH_LEN]);
impl From<[u8; HASH_LEN]> for Hash {
fn from(bytes: [u8; HASH_LEN]) -> Self {
Self(bytes)
}
}
impl AsRef<[u8]> for Hash {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl Debug for Hash {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{}", hex::encode(self.0))
}
}
#[derive(Copy, Clone)]
pub struct Mac([u8; MAC_LEN]);
impl From<[u8; MAC_LEN]> for Mac {
fn from(bytes: [u8; MAC_LEN]) -> Self {
Self(bytes)
}
}
impl AsRef<[u8]> for Mac {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl Debug for Mac {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{}", hex::encode(self.0))
}
}
impl Mac {
pub fn verify(&self, other: &Mac) -> Result<()> {
use subtle::ConstantTimeEq;
if self.0.ct_eq(&other.0).into() {
Ok(())
} else {
Err(Error::InvalidMac)
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct KeyPair {
secret: SecretKey,
public: PublicKey,
}
impl KeyPair {
pub fn generate<R: Rng + CryptoRng>(rng: &mut R) -> Self {
let sk = SecretKey::generate(rng);
Self {
secret: sk,
public: sk.public_key(),
}
}
pub fn secret(&self) -> &SecretKey {
&self.secret
}
pub fn public(&self) -> &PublicKey {
&self.public
}
}
impl From<SecretKey> for KeyPair {
fn from(sk: SecretKey) -> Self {
let pk = sk.public_key();
Self {
secret: sk,
public: pk,
}
}
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct SecretKey([u8; KEY_LEN]);
impl From<[u8; KEY_LEN]> for SecretKey {
fn from(bytes: [u8; KEY_LEN]) -> Self {
Self(bytes)
}
}
impl AsRef<[u8]> for SecretKey {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl Debug for SecretKey {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{}", hex::encode(self.0))
}
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct PublicKey([u8; KEY_LEN]);
impl From<[u8; KEY_LEN]> for PublicKey {
fn from(bytes: [u8; KEY_LEN]) -> Self {
Self(bytes)
}
}
impl AsRef<[u8]> for PublicKey {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl Debug for PublicKey {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{}", hex::encode(self.0))
}
}
impl SecretKey {
fn generate<R: Rng + CryptoRng>(rng: &mut R) -> Self {
let mut buf = [0u8; KEY_LEN];
rng.fill(&mut buf);
Self(buf)
}
fn public_key(&self) -> PublicKey {
let pk =
x25519_dalek::PublicKey::from(&x25519_dalek::StaticSecret::from(self.0)).to_bytes();
PublicKey(pk)
}
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct SymmetricKey([u8; KEY_LEN]);
impl From<[u8; KEY_LEN]> for SymmetricKey {
fn from(bytes: [u8; KEY_LEN]) -> Self {
Self(bytes)
}
}
impl From<Hash> for SymmetricKey {
fn from(hash: Hash) -> Self {
Self(hash.0)
}
}
impl AsRef<[u8]> for SymmetricKey {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl Debug for SymmetricKey {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{}", hex::encode(self.0))
}
}
impl SymmetricKey {
pub fn generate<R: Rng + CryptoRng>(rng: &mut R) -> Self {
let mut buf = [0u8; KEY_LEN];
rng.fill(&mut buf);
Self(buf)
}
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Nonce([u8; NONCE_LEN]);
impl From<[u8; NONCE_LEN]> for Nonce {
fn from(bytes: [u8; NONCE_LEN]) -> Self {
Self(bytes)
}
}
impl AsRef<[u8]> for Nonce {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl Debug for Nonce {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{}", hex::encode(self.0))
}
}
impl Nonce {
pub fn new<R>(rng: &mut R) -> Self
where
R: Rng + CryptoRng,
{
let mut buf = [0u8; NONCE_LEN];
rng.fill(&mut buf);
Self(buf)
}
}
struct TupleHasher(VarBlake2b);
impl TupleHasher {
pub fn new(label: &'static [u8]) -> Self {
use blake2::digest::VariableOutput;
Self(VarBlake2b::new(HASH_LEN).unwrap()).chain(label)
}
pub fn new_keyed(label: &'static [u8], key: &SymmetricKey) -> Self {
Self(VarBlake2b::new_keyed(&key.0, HASH_LEN)).chain(label)
}
pub fn new_exchange(
label: &'static [u8],
our_sk: &SecretKey,
their_pk: &PublicKey,
) -> Result<Self> {
let key = dh(our_sk, their_pk);
if key.as_ref() == [0u8; KEY_LEN] {
return Err(Error::FailedKeyExchange);
}
Ok(Self::new(label).chain(&key))
}
pub fn update(&mut self, data: impl AsRef<[u8]>) {
use blake2::digest::Update;
let data = data.as_ref();
let l = data.len() as u32;
self.0.update(&l.to_be_bytes());
self.0.update(data);
}
pub fn chain(mut self, data: impl AsRef<[u8]>) -> Self {
self.update(data);
self
}
pub fn finalize(mut self) -> [u8; HASH_LEN] {
use blake2::digest::VariableOutput;
let mut buf = [0u8; HASH_LEN];
self.0
.finalize_variable_reset(|res| buf.copy_from_slice(res));
buf
}
}
pub fn hash(label: &'static [u8], messages: &[&[u8]]) -> Hash {
let mut hasher = TupleHasher::new(label);
for m in messages {
hasher.update(m);
}
Hash(hasher.finalize())
}
pub fn mac(label: &'static [u8], key: &SymmetricKey, messages: &[&[u8]]) -> Mac {
let mut hasher = TupleHasher::new_keyed(label, key);
for m in messages {
hasher.update(m);
}
Mac(hasher.finalize())
}
pub fn kdf(label: &'static [u8], key: &SymmetricKey, messages: &[&[u8]]) -> SymmetricKey {
let mut hasher = TupleHasher::new_keyed(label, key);
for m in messages {
hasher.update(m);
}
SymmetricKey(hasher.finalize())
}
pub fn kex(
label: &'static [u8],
our_sk: &SecretKey,
their_pk: &PublicKey,
messages: &[&[u8]],
) -> Result<SymmetricKey> {
let mut hasher = TupleHasher::new_exchange(label, our_sk, their_pk)?;
for m in messages {
hasher.update(m);
}
Ok(SymmetricKey(hasher.finalize()))
}
pub fn dh(our_sk: &SecretKey, their_pk: &PublicKey) -> SymmetricKey {
use x25519_dalek::{PublicKey, StaticSecret as SecretKey};
SymmetricKey(
SecretKey::from(our_sk.0)
.diffie_hellman(&PublicKey::from(their_pk.0))
.to_bytes(),
)
}
pub fn stream(key: &SymmetricKey, buf: &mut [u8]) {
use salsa20::{
cipher::{NewCipher, StreamCipher},
Salsa20,
};
let mut cipher =
Salsa20::new_from_slices(key.as_ref(), &[0u8; 8]).expect("invalid key/nonce sizes");
buf.fill(0);
cipher.apply_keystream(buf)
}
pub fn prf(key: &SymmetricKey, message: &[u8]) -> [u8; PRF_LEN] {
use blake2::digest::Update;
use blake2::digest::VariableOutput;
let mut buf = [0u8; HASH_LEN];
VarBlake2b::new_keyed(&key.0, HASH_LEN)
.chain(message)
.finalize_variable_reset(|res| buf.copy_from_slice(res));
buf
}
pub fn enc(key: &SymmetricKey, nonce: &Nonce, buf: &mut [u8], auth: &mut [u8]) {
use xsalsa20poly1305::{
aead::{AeadInPlace, NewAead},
XSalsa20Poly1305,
};
assert!(auth.len() == AUTH_LEN);
let aead = XSalsa20Poly1305::new_from_slice(key.as_ref()).expect("invalid key size");
let nonce = xsalsa20poly1305::Nonce::from_slice(nonce.as_ref());
let tag = aead
.encrypt_in_place_detached(nonce, &[], buf)
.expect("encryption failed");
auth.copy_from_slice(&tag);
}
pub fn dec(key: &SymmetricKey, nonce: &Nonce, buf: &mut [u8], auth: &[u8]) -> Result<()> {
use xsalsa20poly1305::{
aead::{AeadInPlace, NewAead},
XSalsa20Poly1305,
};
assert!(auth.len() == AUTH_LEN);
let aead = XSalsa20Poly1305::new_from_slice(key.as_ref()).expect("invalid key size");
let nonce = xsalsa20poly1305::Nonce::from_slice(nonce.as_ref());
let tag = xsalsa20poly1305::Tag::from_slice(auth);
aead.decrypt_in_place_detached(nonce, &[], buf, tag)?;
Ok(())
}
pub const HASH_LEN: usize = 32;
pub const MAC_LEN: usize = HASH_LEN;
pub const KEY_LEN: usize = MAC_LEN;
pub const PRF_LEN: usize = KEY_LEN;
pub const AUTH_LEN: usize = 16;
pub const NONCE_LEN: usize = 24;
#[cfg(test)]
mod test {
use super::{dh, hash, kdf, kex, Hash, PublicKey, SecretKey, SymmetricKey, KEY_LEN};
use hex_literal::hex;
#[test]
fn hash_reference_values() {
for (m1, m2, m3, expected1, expected2) in HASH_TEST_VECTORS {
let hash1 = hash(b"test1", &[&m1, &m2, &m3]);
let hash2 = hash(b"test2", &[&m1, &m2, &m3]);
assert_eq!(hash1, expected1);
assert_eq!(hash2, expected2);
}
}
#[test]
fn hash_identical_inputs_produce_identical_outputs() {
let label = b"test";
let m1 = random_bytes(123);
let m2 = random_bytes(123);
let m3 = random_bytes(123);
let hash1 = hash(label, &[&m1, &m2, &m3]);
let hash2 = hash(label, &[&m1, &m2, &m3]);
assert_eq!(hash1, hash2);
}
#[test]
fn hash_different_labels_produce_different_outputs() {
let label1 = b"test1";
let label2 = b"test2";
let m1 = random_bytes(123);
let m2 = random_bytes(123);
let m3 = random_bytes(123);
let hash1 = hash(label1, &[&m1, &m2, &m3]);
let hash2 = hash(label2, &[&m1, &m2, &m3]);
assert_ne!(hash1, hash2);
}
#[test]
fn hash_different_inputs_produce_different_outputs() {
let label = b"test";
let m1 = random_bytes(123);
let m2 = random_bytes(123);
let m3 = random_bytes(123);
let hash1 = hash(label, &[&m1, &m2, &m3]);
let hash2 = hash(label, &[&m3, &m2, &m1]);
assert_ne!(hash1, hash2);
}
#[test]
fn kdf_reference_values() {
for (key, m1, m2, m3, expected1, expected2) in KDF_TEST_VECTORS {
let mac1 = kdf(b"test1", &key, &[&m1, &m2, &m3]);
let mac2 = kdf(b"test2", &key, &[&m1, &m2, &m3]);
assert_eq!(mac1, expected1);
assert!(expected1 == mac1);
assert_eq!(mac2, expected2);
assert!(expected2 == mac2);
}
}
#[test]
fn kdf_identical_keys_and_inputs_produce_identical_outputs() {
let label = b"test";
let key = random_key();
let m1 = random_bytes(123);
let m2 = random_bytes(123);
let m3 = random_bytes(123);
let mac1 = kdf(label, &key, &[&m1, &m2, &m3]);
let mac2 = kdf(label, &key, &[&m1, &m2, &m3]);
assert_eq!(mac1, mac2);
assert!(mac1 == mac2);
}
#[test]
fn kdf_different_labels_produce_different_outputs() {
let label1 = b"test1";
let label2 = b"test2";
let key = random_key();
let m1 = random_bytes(123);
let m2 = random_bytes(123);
let m3 = random_bytes(123);
let mac1 = kdf(label1, &key, &[&m1, &m2, &m3]);
let mac2 = kdf(label2, &key, &[&m1, &m2, &m3]);
assert_ne!(mac1, mac2);
assert!(mac1 != mac2);
assert!(mac2 != mac1);
}
#[test]
fn kdf_different_keys_produce_different_outputs() {
let label = b"test";
let key1 = random_key();
let key2 = random_key();
let m1 = random_bytes(123);
let m2 = random_bytes(123);
let m3 = random_bytes(123);
let mac1 = kdf(label, &key1, &[&m1, &m2, &m3]);
let mac2 = kdf(label, &key2, &[&m1, &m2, &m3]);
assert_ne!(mac1, mac2);
assert!(mac1 != mac2);
assert!(mac2 != mac1);
}
#[test]
fn kdf_different_inputs_produce_different_outputs() {
let label = b"test";
let key = random_key();
let m1 = random_bytes(123);
let m2 = random_bytes(123);
let m3 = random_bytes(123);
let mac1 = kdf(label, &key, &[&m1, &m2, &m3]);
let mac2 = kdf(label, &key, &[&m3, &m2, &m1]);
assert_ne!(mac1, mac2);
assert!(mac1 != mac2);
assert!(mac2 != mac1);
}
#[test]
fn dh_reference_values() {
let ss1 = dh(&ALICE_PRIVATE, &BOB_PUBLIC);
let ss2 = dh(&BOB_PRIVATE, &ALICE_PUBLIC);
assert_eq!(ss1, ss2);
assert_eq!(ss1, SHARED_SECRET);
assert_eq!(ss2, SHARED_SECRET);
}
#[test]
fn dh_derives_same_shared_secret_from_equivalent_public_key() {
let mut equiv = ALICE_PUBLIC;
equiv.0[31] ^= 0x80;
assert_ne!(equiv, ALICE_PUBLIC);
let ss1 = dh(&BOB_PRIVATE, &ALICE_PUBLIC);
let ss2 = dh(&BOB_PRIVATE, &equiv);
assert_eq!(ss1, SHARED_SECRET);
assert_eq!(ss2, SHARED_SECRET);
}
#[test]
fn kex_derives_shared_secret() {
let (sk1, pk1) = random_key_pair();
let (sk2, pk2) = random_key_pair();
let m1 = random_bytes(123);
let m2 = random_bytes(123);
let m3 = random_bytes(123);
let ss1 = kex(b"test", &sk1, &pk2, &[&m1, &m2, &m3]);
let ss2 = kex(b"test", &sk2, &pk1, &[&m1, &m2, &m3]);
assert_eq!(ss1.unwrap(), ss2.unwrap());
}
#[test]
fn kex_rejects_invalid_public_key() {
let (sk1, _) = random_key_pair();
let invalid = PublicKey([0u8; KEY_LEN]);
let m1 = random_bytes(123);
let m2 = random_bytes(123);
let m3 = random_bytes(123);
assert!(kex(b"test", &sk1, &invalid, &[&m1, &m2, &m3]).is_err());
}
#[test]
fn kex_derive_same_shared_secret_from_equivalent_public_keys_without_hashing_in() {
let (_, pk1) = random_key_pair();
let (sk2, _) = random_key_pair();
let mut equiv = pk1;
equiv.0[31] ^= 0x80;
let m1 = random_bytes(123);
let m2 = random_bytes(123);
let m3 = random_bytes(123);
let ss1 = kex(b"test", &sk2, &pk1, &[&m1, &m2, &m3]);
let ss2 = kex(b"test", &sk2, &equiv, &[&m1, &m2, &m3]);
assert_eq!(ss1.unwrap(), ss2.unwrap());
}
#[test]
fn kex_derive_same_shared_secret_from_equivalent_public_keys_with_hashing_in() {
let (_, pk1) = random_key_pair();
let (sk2, pk2) = random_key_pair();
let mut equiv = pk1;
equiv.0[31] ^= 0x80;
let m1 = random_bytes(123);
let m2 = random_bytes(123);
let m3 = random_bytes(123);
let ss1 = kex(
b"test",
&sk2,
&pk1,
&[pk1.as_ref(), pk2.as_ref(), &m1, &m2, &m3],
);
let ss2 = kex(
b"test",
&sk2,
&equiv,
&[equiv.as_ref(), pk2.as_ref(), &m1, &m2, &m3],
);
assert_ne!(ss1.unwrap(), ss2.unwrap());
}
fn random_bytes(n: usize) -> Vec<u8> {
use rand::distributions::Standard;
use rand::{thread_rng, Rng};
let rng = thread_rng();
rng.sample_iter(Standard).take(n).collect()
}
fn random_key() -> SymmetricKey {
use rand::{thread_rng, Rng};
let mut buf = [0u8; KEY_LEN];
let mut rng = thread_rng();
rng.fill(&mut buf);
SymmetricKey(buf)
}
fn random_key_pair() -> (SecretKey, PublicKey) {
let sk = random_key();
let pk = x25519_dalek::PublicKey::from(&x25519_dalek::StaticSecret::from(sk.0)).to_bytes();
(SecretKey(sk.0), PublicKey(pk))
}
const ALICE_PRIVATE: SecretKey = SecretKey(hex!(
"77076D0A7318A57D3C16C17251B26645DF4C2F87EBC0992AB177FBA51DB92C2A"
));
const ALICE_PUBLIC: PublicKey = PublicKey(hex!(
"8520F0098930A754748B7DDCB43EF75A0DBF3A0D26381AF4EBA4A98EAA9B4E6A"
));
const BOB_PRIVATE: SecretKey = SecretKey(hex!(
"5DAB087E624A8A4B79E17F8B83800EE66F3BB1292618B6FD1C2F8B27FF88E0EB"
));
const BOB_PUBLIC: PublicKey = PublicKey(hex!(
"DE9EDB7D7B7DC1B4D35B61C2ECE435373F8343C85B78674DADFC7E146F882B4F"
));
const SHARED_SECRET: SymmetricKey = SymmetricKey(hex!(
"4A5D9D5BA4CE2DE1728E3BF480350F25E07E21C947D19E3376F09B3C1E161742"
));
const HASH_TEST_VECTORS: [([u8; 64], [u8; 64], [u8; 64], Hash, Hash); 16]= [
(
hex!("44EE2E7DCD5C33C19FE601C1B38C1C3068409D96E49BACD0E093A2091EB5C734B9D0290092E4CDB0EC9BC81F30E0489916631EA66BCAB1A4679845738BE7B580"),
hex!("A2E238EFDE50E694CFBE2F1C3B16148880AD49DBAD459521E09B44D24FCAED47DE5884EB984EB34839A131AFAA1BA80735314A155B9E25EC3E6925961A9C8BA7"),
hex!("CEFAE5AEDB84593E40D5D6A3A98410BA87B624479B4EC82BDB695D2D33E42F4DD66E2F95742795A09F8D085438A380360E51C65185F41962F28D19B7F370001A"),
Hash(hex!("8BB5C31F5A540872FD3E8E3874E7CB2C4B3D6C5DDA969195D7B285A4EEDF5713")),
Hash(hex!("5D095D88F1013E6F72BC6DED575F285B3A87323E4CB5F7D12C11BD887EED06D1"))
),
(
hex!("DBFC6A076B5FA5DC82AC0AAB28B5908F6C7788827C5CE554F4065989331C11F7344F33BB69A2B7152DE0436F2C2CBD6244BBC00CFF7C5DD44BEB9E624A8D4ECE"),
hex!("63ED19DE0182B65080E3D28207BD8683561D71C216752545F4D20F8F3615787B6184256004F74ADFEA6322A35BB06F710D0DEDF61E745F5421A0EA9836BFA83A"),
hex!("2ABB8212FB0599027CC274F3A12367A7171085DD683CA1EEE4FE9AF59B64A07D40EF1F019F01EAC36D642183A34F3710E8C6D12DB80DF0BFB73DAB064ADB3F31"),
Hash(hex!("0257D05D007BC15A80A3EE8C9B02888BE0654484F678968D8D2E786A8C87B6B0")),
Hash(hex!("A11D3ED4F623AFBD9F03468E39B07DA732A9732101F7423F90263F025474412C"))
),
(
hex!("EA30E266DDCFF498F7EE84DFB314E2A57EE23C72C06CDCF25EC47C3F02CA743C950AEDC47185E521306BCD877B8295697E16ED2DC68BF01A9751FC9E3ADF506A"),
hex!("B962AA68A422AE5A09E32283770F3A9FB91502D56D5B840DA8EAAF7A1B8D5779EB62EA39B6D68543EA37F279968E4645F6793EE33DBCED637C6996DCEF4143EC"),
hex!("44A6C3051ABE4EE363027C401C251147C162E210339BD287642DE47E930FA012E265F64BF5D4CADAA6D23EA420C1FFDEE9E9C4E9408CAA4D95E30074F909FD67"),
Hash(hex!("AF612B99B64F509183F472AFF082342A708E224F1F0A1F5E97BD61982639B33E")),
Hash(hex!("461918BA348D96997721FF83D5D7C4030A9F0CE7796CC8C37D3717297DDC5932"))
),
(
hex!("75CFDDDE303F4E0E840E640627A52633DE48A66923861B9E1204FF9E3546124037720A6FE2CF964737950BB3FD3FFE7A1F3024741FC8813EBB3A70BAD26C2A57"),
hex!("DB4BE8EFAE9FDB4CE5C8E1F8F8A27D04A02D5AE67C73F00F647DE1D4BF765C401177CA08BFAE83DB7387F344D389618D064206006EDC0197376EF36ED2FB7AFA"),
hex!("8E0775C7F49B79D66BF9DDA31FD0156E37737F631FADE2A03E80BE3DF55C39CB8CA679125E4735727BC2E7F7BE1702FADEB0EF712B304331EAAF7EF1A5520C34"),
Hash(hex!("8BE489F466D789F32BC407A5DEC414EEF0606CA774F6B30237FF3B761CA17B86")),
Hash(hex!("B1E97A6EADA81E43E1ED9B716588E8655A82AE1B14E66B9508EA6EE3B27EDABB"))
),
(
hex!("81BBCAB8241EB0155163E3C12C29C6B3116C61110A091019E54BAE3A881A6E28FECF8E4729660D4FA77E6ED7E5500E294742FBD7DB1476C289BCE8B319767C64"),
hex!("09D9E8C4B69AE63736C95692C8B206D1480F8BE3018453577AB47D7AF6C510CFEEC688D063D7E3E8E0D594A8DE81B29A13E70DA0DD90527F9C5E2E9E01C200A8"),
hex!("7E1A62E8F957F882ABA5FC9E812EA76E6B724E8143E5FD0438925D03AE600A9D8EF1F306F8CA4AD541C84735E13C8F3E574351E8FD94CBBE7A7BCB6788951DBD"),
Hash(hex!("B67C87EA7B93AC2780F998D4052B360E39FEA686B09C55D496B97E523F8D11FE")),
Hash(hex!("A77777FB5A711565218A42D8E91EAACF704776F5BFCACE2DD3D05C6AFC4F61D3"))
),
(
hex!("986D1D67AE1E581EACC0B1B5BC2926C05EF7B7AA51F67CFA14ABE67E4D28F046D0AF687466E0B5608883F8EC3A5EE5155A65D6EAC10FA8F4B8BE5B752E71FFB0"),
hex!("0439A9F289AB98DC41A4618F7B7D9697B04731442EF925B89A63B0612BD376FD9F23F8679AB1145B33132D6A54F0ECF139E231B7A6F58038DBFD6310B04CE67B"),
hex!("0DC20AD1CF95C59B61E25DDC6CCA1A6D15AD1A9A28A163427E09976940E01BB93F1B1810926F5F80F255B7F9BFD06365281978052B9B271EECB2F802F08250AE"),
Hash(hex!("99FF047DCA092824F7E83993A25A5C748643DD2A4801999A4649644251DBEE9C")),
Hash(hex!("1FC2F1CFCC75F0870027C58B271CF23ECD86739D0EE46661C1BF1176B0959DAA"))
),
(
hex!("47FBCF0D756529708588ED3EA74383D6517FC7AEC5B8A204BC858B4EE94D14F51557D927ED6B92B4083F5996574B51A381FF1F010B8B2F7F63B6DE1EC3DF12D0"),
hex!("93801D48A7F132C2EE99A24679F2C1701C265A872A0E1C8F5CB4FB9EDA60AE05C6802FFC90E8395D917FDE1B2BC6850D59F353875C60B10885BD1EFAAA6CCEA8"),
hex!("39503B53CCD5D4246E3BB7A4E2BBF7CF324BA5294EB2B03C1E2328D640B8D20578C3FAA73284F3A2A97E1E49E5675AA2E829A7ECA0A18FD14AD29D79BC30DD07"),
Hash(hex!("610C80BAE7A922BC0FBB021A5C943581CF931A513AE7F89D2B54F37C8477EE2B")),
Hash(hex!("12649D9C636378ACC43E0A3F6346133A5054FB870F353A4A9849A24437C16EBD"))
),
(
hex!("A22E18B8578B514DF14EBF6811C5AD293991517CAABEC25E61F0F83D575C63DF3C4C068BC77CEE1BF71EE9D56D03710226443B91E7D62E3E88F117419B74CF0F"),
hex!("FEA19B0DC47556B94BED048C7CAF105094AB76FB8FC6C2F0BC6137B516F115BD0A5C8C2827832F22C21E9EDD2999A4B99580EC6687093E9213E9B10DCB90D3F9"),
hex!("855D24B67F36D6AED75020933406D0F8821F3328A6B7AD8B8BCEFABED69111A1179D7DDF8E089EE0284AC0F5B118037D742C7EFF398F40878370553FE4FFA690"),
Hash(hex!("B46CFAF84D30B021FBB6033AAF496E7CBCC20B7A436B2D5847D356DE2BA78451")),
Hash(hex!("FFFBE623632C26DEC80D8EBE8EDB43B7149EAB2CC6AA68E58850C8FE9438652B"))
),
(
hex!("BDAD3373E36EB230A90DA1B3F09A9FECABD2F22B34E3E4806A9BDA94A25C8AFF36EE5234314FA18D4B8753E8FE960AE47AC3AFD8F9DA4B008C72B71F1289B1B5"),
hex!("94740051495B857608F8392E154EE9FE648A9954ECB772DF9783F970026BBEC09334A15C72C56FB4B4BBAD4C6A213CE4D705390E1F86A9325F61A0C3869BBACC"),
hex!("75B0D0BB2606670244CA793D8B45DBF007874972174787611D59586742E8E00E7FC5CA4294EE2D1454983CF8D758D6B56BE6A2594BACFF27EBDA49AAF0D1CF80"),
Hash(hex!("FFF6BBFAA68236E2F863F6507552371B3FE5309FCED0FC59AD7B6D681E341066")),
Hash(hex!("F01C5DCC21625B8314E40D54F216FF521394E81567CEEBECC6632CF4A3BA2C09"))
),
(
hex!("333268EEDED5D6498BE79F87918E2148FF30BF4E10A80479A14E16666D252650FB1B606F1A3965E89B85FD9863A98A27F1094CCDD6FFBA57B45BE5C293E231B9"),
hex!("27CC2CACD2E18222FACDF212260101A49C357ED043A33E4431EA16C65A10477191126E093AE2E1EAF77B1615DD06C0A84A94455C151137FA28E87C5A5F084822"),
hex!("153517A73724753683DA56E862AC88098B589802FBE6952A8DA93794535E3322152CBE2BE52B8883B594D62ADE2AF9C8B28B29B11A4C5833B840BFE17E8EA14F"),
Hash(hex!("B58741E3E6A2330A38B445390E1B86D14C1D9C41AB714F65432FDDDCBE9A5E6F")),
Hash(hex!("185D7BF10CD25418E4B0E29BA4423314E19A8E3F089A3D45C8DF79BFE7EEBB3E"))
),
(
hex!("A1D09520C0DE7752167C26A412D3F5B4D02081FFDA3E0CA0B5F437EB6D40196603ECCF44A6CB0942A51477E6452EE3DBC34F3D4C89E801B9ACEAD30421C8E28C"),
hex!("8DA0B8D9B036180A9A70E6036682441B900017DC8BDEC326B1092914E9C2778BB41E81477B7CD7164003F22AC6FE2D24DE614F01C9A4CE0E90FBF1626F61CDA6"),
hex!("72046749DA32DBC80453F7F707517E9E19E44E5DA0D71B287B0B15B4F0639C6EC3095BD7549B08B6F8B94D7DA29BC834EF2DBA646146B931856EC9F1BEF86338"),
Hash(hex!("204494CA7BFCAF12407F8B99684EFA6D685AD953515535FB3827998F6E9C02BE")),
Hash(hex!("6CBB199BA1E1C8BE18CABF326291D3457610EAE9BF5A093C2BF33B244F54E832"))
),
(
hex!("2950F9CB3642D9ECEFCA1D92E7E23DDA7FED194BA66243DCBA360DE7EB1F8294CC732B50B0C48655CAEF84872577BFB26B385A5D0FFCD7D30204E3E6D167E7E7"),
hex!("1F45FA53661604FA8592F200E24F7097574EA05A2D8E02F7A17547DD139A2F74B349DD57E5F8BE8AE826907B3B39603BC6683EF093E4124C9F41DFDAE50445C6"),
hex!("1D7C0B986B987B035C4720A21FCBBB2B80025A48CAAC9EEEEA8A01AD922B0F2B7768ABD369AE6BFA6F65D790D28FA2170F3CB184CF40D853D1199B9EF7D4F40A"),
Hash(hex!("DD4FC490E3C5E32156262FEB6DE7F3ED8D9D303A593B040888D4AAF0F140C383")),
Hash(hex!("1CE8DC7A69756F681DC1FBC1DAB3BCAFB8195DCFA2FA7A2A06727BDAAE9C4497"))
),
(
hex!("F291FC88A06482E560A7720758AD114DAF18C1887A01182EA6A75E2145A4A711589F880A41D035F58FF690D3D690C3AB29A21E3DDDBECA59A94E03504C8CDB3A"),
hex!("3BB0BF9A2E3E1B4FFCEAE4E57939CE134ED176D288AEA3AB70EC62584BC87DEFC703C5895E9F50BC6C31C7E8A91EDFF2FB1634E53CD6CE89C083BAC0813A9268"),
hex!("AD65C638FA5060C3C440E16E2121D6C7D53449A02EB7C2EFC1DFD7F1C6EFFBDEA3BAA713E2EE869C8EFA06BE72E1A1FDC211B9A086C8003E7EBC1C88025E3836"),
Hash(hex!("046A6A69C032C3472A65B155D772E04999372F6EF7CCD9EF7A2CC25DDE38D350")),
Hash(hex!("F179B2CBE004B5C65466C33406E741A9A424A932F46B3065D6E122161ED94A4C"))
),
(
hex!("A408334992371AF6D6BB4D4DFF137EA3C7C920C7D0B5667BD37FF4136CF171BCAE18CE401C1AB9D11C208FBBFFF0CC3A828516B457FC8B4578DF46E450A2818C"),
hex!("C4D2579474ADDF556419BB645D3ECE0194DA2EE06FED52FEF2F2EF5E9BD0FAF32F04C7AF7D8C3C80EDB5FC9A4E5DA844B90D6DB3846B2121413AA2A61999BBD3"),
hex!("3C2EDEDDCC8FA59A99019458D80583C7F0D3D8C5F73DCE0E4AE9C4A5AD8861FCBC8204272E5056D66F96B2D059CD43D4FC969A179D3B357D5400B9DCCC0AB8AB"),
Hash(hex!("DBEF9E5AF1C30098BBA277B16BB0809ADD34F9360BA58E304FA8C194084F15FD")),
Hash(hex!("36733C9CC5F84229CD8F13395CE917C79F1ECB20FF001CE29517C14F094F6040"))
),
(
hex!("EE3FE00355EB6B02611D8C144DB8603A754D8DF71710A95C82E8549F659445A3573FB3F434AF5469BEFEA4E29C736A81BCE4B50E58C00F2DAA74CDEB2E0ECDE3"),
hex!("9FFFC9CE58B71440C51867BF97BA705B8DB9AA64A753122FDCFFCE03210CB89CAC20AB660E739FB0B0F3B428BE46A185FEF0F3689CDB0C10D5A7CF2217BC356B"),
hex!("E72DFE29DA303541DCD8A4D5E465E9DCEC4F5FC443883AAEB4B991737D51A9AABD0A04BCF25024AB4D532248B1B02CEF75EF42939D82473B7DBA8C40D6A30545"),
Hash(hex!("66ED10E4935150D14BD8731BCFCEE098C62B91740501DC5D658ECD47ADEDCB23")),
Hash(hex!("16C5C00FB0015C7AD4E79719661061E68D75DE87CF22C664D3CD89114876344C"))
),
(
hex!("0274A6756670DA3B366F46B60319D7D228A5D5FC30B0AF1654D7E913CAF85646E02FDAE732AFC08E67D321807CA8016165CBDBCCAF20E0375E417A3D4BD11E26"),
hex!("3663592E2EE415BA4D43664E81E4B7D8612B2EEF6CBEAD6E4B37A0A78E7F5BE504351D01932DC47A9DC9B6BC607DAA691047E3AAABCC4F7A13855609F7489494"),
hex!("50FF862C4FFA985BB285F1C838456D6AA97F9BEDA4B6F8AB92315D54005E637FA32BAAB187ECD216091C18A47B1682D6273A3C3F059A4F76097768ACB7A8B8B4"),
Hash(hex!("B878EEC15288593F91F2DE899061D26DAFD8FACEC4570D1BF70B251B5C77FA04")),
Hash(hex!("CEA2750E11D569DA1D5DE8C549646A5CC608207321A84D29A198324DE6E2A087"))
),
];
const KDF_TEST_VECTORS: [(SymmetricKey, [u8; 64], [u8; 64], [u8; 64], SymmetricKey, SymmetricKey); 16] = [
(
SymmetricKey(hex!("011591346B2B0239A076F8F66784C0571624ABB4A4F0412EFE39B9B962B6E6D0")),
hex!("76F4050C3EDC2E34FF137D27966CEB31DE03A60ADB02214367689A2713ED64A0DB6531AF22292B0CB74460158DE45304B0268543D3B6BE3DAED7B8B494E160CE"),
hex!("7C7883AD1B4733FD125DFDA107CF994B9C0EB5CD286AC621AF813605CA21687D4D4B1ADA006CDD19A083306BB6ADCF5296232F1A8E349C45CC927ACFD15591CC"),
hex!("64DDEEFBFE9481C7B335DDFDBE0BCCB7F60BD3464996EAB56AB64B6877D269A57B6E9BFB139D636CE4DB108C38B84DEFF89462DCB476C7C2727337B6BEFB1282"),
SymmetricKey(hex!("528FCBB00BD7D3EC03EC27C2290E42730A9ABEF834DC2D6BD4DC8C44AEA3757F")),
SymmetricKey(hex!("356C1D3D4106ED4066FFB6550A0E77E323ECBCD336075407CC7E34FF3EC0C9D4"))
),
(
SymmetricKey(hex!("6F6F5D7293A399C78C6E33D8B1D07CC23D2BE2DBBB720A74D198D8A25D77B9F3")),
hex!("C3023590A7C2E8AF4C2AF802A89B92A649E35F4D607BAEFBF8B9CEA0402FD0CC1E0D4469C91512A48554002E1333B25E0312630039C4587E5CBB78250424B915"),
hex!("C8D5CEDC4A104AACE10F6271DBFE3B8F37758634F0015FB3F76EC4057C0FC65D31378072CD23D489C84085765BFF25C917ECFE6EC2F8E6EEC540A57D2FD7BA8D"),
hex!("6B5FD3BCC9B6FC16EC810827E5E7221BB6BF10D8015BF92148F3034AD7CE3B1CAB20C5090A6BEB06BE28A0423D09A2658C7BB51992F7A13D056C39A5E3CAD167"),
SymmetricKey(hex!("9EB06394F343E046D75D94BA8D5986FF7C3A8FA8C98FB4E264BEE7E48BF7D2EC")),
SymmetricKey(hex!("68C106D4FE6D9F97E46F9B0C4DB6B7F44A49D6E25CF8087BBA9DE9469509C155"))
),
(
SymmetricKey(hex!("CCD12E6D30B407EAF659215B1C0CF285F555F4DE7038772F05906626F6026E05")),
hex!("CBBE6C7A2EBEE9780F2E2BAAAE7B10ECB128AFC127F1225F55303B7C66C497054C293255CCA311ADC8E51F701420F05566F9E5AA597DC62D8606FEBBBDF4AD8D"),
hex!("14D9AC1B26F5DE1BA42E6010E328403A1912B3673D2F54792DC1E7853C64E6A58D3C5A0E2C8E825D6B77FAEAA427FEE3B9A9817B1B0E388F6420239053F0F4C7"),
hex!("4519304420BDE406A754400852DA5C5F941C4106D1E4E94A482204422A76848D6FCCFA2B1AB9B9E228F5F306DFC5C91FE0B496EB51A04256793F48E91C95EBD8"),
SymmetricKey(hex!("5BB3797B7DB0B7B0F59E92AD311E8EF6C426210A50CF7FF3EBF91C90941EA891")),
SymmetricKey(hex!("52FE75CEBEEAD67369F25C7BF062D08F2BC345550BC18E695440A519C5EFBD07"))
),
(
SymmetricKey(hex!("601B139687683EA380A6FF61AFA01BB63403504621FEAEA29DB771BB3641C7F5")),
hex!("1394CD83A677573B8869E90E1A8D33050CC79799D98A993BDCED8F45BC25657AA67D45840ABF0C6BD99674AAEE239B224867AF1FA8F0A58365D50625A5D72726"),
hex!("DB5865F81BFA9AD0549323E5EC4EE977ADFA2E0CD09597C7E86D27E41AD84E9498F04E3294CD95FC9B948BA547F3F7C862E00D96268BFDD21B50AB9DFB66CC5D"),
hex!("67FA8406061ED49C9575AC62286C347A75E8F52393CAFDDB364A659A5A251330F646780F54B620CFEE9ABE8C2CD594D1540CA30395C5D9AC760CB974FD870572"),
SymmetricKey(hex!("ECC1364E68A666A16DB6EA3EA3C5E0FF2D35DF7FEBC300F1828B1E679302BA62")),
SymmetricKey(hex!("2729F34F8D21EEEC33AED8DCA5BBEB28268775A0553D61627FFFC2859BF1D3AE"))
),
(
SymmetricKey(hex!("98825A96363EE91194E72877E424FCF354B751ABBE43066B9DE5AB6DE019714B")),
hex!("C38558CEB68065163BC1901A531717102E9F7DA23491F0BC708FA087B18EBF4690359ED1B502F1ECDA24363274E8FB7E7D2C73D530FDCA58380B10AB53A5C74F"),
hex!("3FF4C59967E990A12CCB0DACB2DE16A2417375457FA8FA37428ED1915BDAE785B0A195FFD330E063305D4B1F6EA52DED5EBB7ABD04A400C45F7EC37596EAD432"),
hex!("EA2B2BA85432DCC2AAB84D017D7783DA1E99C171345FF852657EE7878125C63A97AFFAA71A7B4B5AA0441F9DA719687EAB95C03698660533AB8A4305CF8FE985"),
SymmetricKey(hex!("700C011046CA0481CEC14B55387B536B2D901D3FDE4D2DC1BE4A375E8F3C6EAC")),
SymmetricKey(hex!("74555D7AD903304D604669B6311C1A59DDC0F9EC35ED26A7A6EF78491B114DC9"))
),
(
SymmetricKey(hex!("8628408EAAF2B88CDD55FC6529A5BB0E9667324A4F724A5591251A57E7D54936")),
hex!("29B2C67D5A513D8A71A39119342231FA53BB407F89C44362F6934B0C640E90F8155827F2D6E690F12ECBE44A6CF2591ABA8B0FFD0DD89EA2C029F2A1934C4B61"),
hex!("8476E1D29EB01FCE2DE6185B690BC422880A2BA5B45EE9B058A68B01F802A813D6AAEE7F85C01993482D81993901B5AEDC189AA5EB8FB1592BA14153C935C161"),
hex!("0B54B49533F3B9F89DADB340DCE04B36BA4F97B035C7F1682A062343717DF5314BA37440A4F63C4E110D8E4AC7DA13C38B9832D2A772E1644AA260200FD9E937"),
SymmetricKey(hex!("195F0471A8CA586906EC9C238A926E0E9FF89AD86A8C651D0421868457E5070E")),
SymmetricKey(hex!("FB335CB495AFDEF0E3B5957E42C39EC53D183177376EA27974005E6D6478398B"))
),
(
SymmetricKey(hex!("5E3CA119A8A042E8CA5E5EA162BD51739B555DE26B51855F05C0DE4DF55024FB")),
hex!("3466B1B3619593D0B407A2088A3F96BA9A1A23203D029919D8D3AD53296968B85FCB5D2BC73D85C1FEB20C340F1B5FD51CF51099F1E1ABAAC3383C81E7633FE6"),
hex!("94CA634F270E76C49A56C9E737F7D01419450D9EEB398BC3CCFC52781C5456082E573232A01C1C80C04727A93A23D47E6D2522ADA5BE53697CBD2F29EDFF9B88"),
hex!("AB692243A507A0606B5F257BC3201EBE5964FCE52C5EC4B860944DC02E9348802D001D5F7E2CBE48DA2E8D5E75FEF184000C2155A45EACDA8913AFC6EC2139B6"),
SymmetricKey(hex!("8ECB6605E812672F9049F0678D4106152E208BDA35DDBCCB1BE2FB2C7DC457B1")),
SymmetricKey(hex!("2C91D48E7CDCC192FEF9E582A0356503D8B0574BCAE15F56DE09459F6E901599"))
),
(
SymmetricKey(hex!("F9AED0A2C62D6868114490D16482A154EB7A1B20C0CC8ED30D52BB3DE4FA489B")),
hex!("FBC0D82AEEC9A02A567E195798241913860C26E34A3AD541840800D009CA92B841E87758B9018CE9B47244228ED900F7A1510F5FA1CC2B6F8BBD6A48028BC3D6"),
hex!("7C7EC8A3BE8EED3C7BE0AC5EB6AC3B1AEFD85DEC369BE0524402CB61A94BE9208255847EEAA98F44BE358832F62AD0718A87F4060E5E6044D4BEAFA88DBE67A8"),
hex!("CE17C64CFB214C45D323BB83259D83016D81B9AB436C2A26E48EF199719DFCFAFE38660306C2B14CD7435DBD9112B2E0F9A10130830AD6C2212E7C60CBDBFDEE"),
SymmetricKey(hex!("733868886319C986D13AD1FEE05F54751EC5C8E8DBBDC30ED84E0A39C3ED107C")),
SymmetricKey(hex!("A8E27921FD3A372AF337E646001B5953A9B869F9A2E6E370615920406581FAA0"))
),
(
SymmetricKey(hex!("5476D58DF107805427CB5C4F7A3B2D0D7184C2B08F0903EFBDF4289546A93B65")),
hex!("36E796B7F92A738CE84F346694132C187D1CCD35BDB44FC4EB63BC2B40443083AF9DBBF72E721A06819DE464895C9570ABDE922B7710AEF266C258484C9C67D3"),
hex!("EBD60127F2DAB2FB1C99A4FF75E82E6DE97837E4BA68B2B6EBC8F710B2C448CDBFBB79DB7E0F40502836F97168B47B400D1BF166982FB57CBA5EBDAEEA36AB80"),
hex!("1EB1D1DE5DAD5DB4D97A272FE8D252AF4D4FF9F2B62BE2991966359B25E5E184A538ACF6EFDB8210A79432986C2679BAC7629041CFF68ECDD198CE05C41C26D6"),
SymmetricKey(hex!("87B782BE12D27200F64704860FAD745ECB9B3C26F163833691CCDCEE42679162")),
SymmetricKey(hex!("C37666B9C23C4D82CC632D156ACD19C37B124A9040C15F73157C18E4B1F15DA1"))
),
(
SymmetricKey(hex!("1061A100E832B272CBFCD7B6E2EBC76AFA5DD5C02FCC726EAF742496DE388CFF")),
hex!("C2C6CD35CEF0CFC2C5AC3BB92915AA964B8D74B738A799400438EA0FBF24ECCA422411447E8118EED96236EE9873FAC682996E7FE1B12CF226EE886563AE67B3"),
hex!("B8725ECDA754710F8CF6774E76B28C584A307ACC31036A26ED8BC296FFA87882749ABFC74D048E572CBDEF327F21EB96B43CC240C9AD65C7361CEC5079DFB0D2"),
hex!("68B3EE2A48CB231D46FE2CB5664F13D4B4AF0269581E6E1064FC90A6EBD695AEA9D5A652C24BA58A2E78A95A4D743B70A3D8459724CA2D64DA28915C24614225"),
SymmetricKey(hex!("4862F235EB4FEED6EC8CEF9D149A9CAD57373FCB817AA498C055223B36020D2D")),
SymmetricKey(hex!("8DDEE6A05669559D5EEC9B385187922272C5186712F4DEE6ED2701CF69823360"))
),
(
SymmetricKey(hex!("F2790E7FBDA540D47AF42F184EACEA5BBB4DC4F9882DE48A82990C3B26FFB779")),
hex!("206ADDE68BDD19BE87ECD06EF601EEDD9E64A9B9701A506649AEAD88A9130A85B74120E15492FB7FF33D1760C448F44DD03ABEE3DE562582A0AB245797E5CCFE"),
hex!("5B7EBBC69304F8C021EF6E3BAFC7DA03384E3D5B698B2729FD46E68F8E7272A25820104E996CB47AB803F0D29DB3F4F2A3A5501DB98144D058437FC061117F93"),
hex!("1CDB634D09A158112461FF79ED79D7474189FCA90CB347BAAE1D0F7E97E4BFF5B7D5EE025A0D5DD214C3774CEEDA75E626CB787DB42601B082C9BBD7EB1CED69"),
SymmetricKey(hex!("48649FC12281CB1A2D44D9EF3BBD00B44886DAC60A4BB9052F8D5251C4C3E29D")),
SymmetricKey(hex!("456E268BA37FCEA40250D504FC2BB2F9C58CD94F3993D363AE9E0B03A6371706"))
),
(
SymmetricKey(hex!("62FBB03B59F8B059FABF4CA165D493D5CA9F3A2397A0F989577D30B8CA0B6202")),
hex!("F5DB70F4A41AF3118EDDD9370B5CDD7B8A063192AE1F0E12378F7946D805D54E6E1C865A2F85B6214BB54FA30DEA291225C2F52F86AC8C742F61CF4E6B153951"),
hex!("71775164C3D70D9DF128F1B38BD3B6D53FE1F40EC277AC11D05D227C0E7D3389C34D84937AC7D6BF01A7122219756254E1D6CCB996487B01B0047AB3000ACFC6"),
hex!("CEC699D545F57F4A447F0D8B402D32A4F72269244E3B9A05E7067932B3365720218123E1661443D8454799E4FE26AD76D18A9929C5CF63F59373982A4D1D853A"),
SymmetricKey(hex!("9C935A745728ED8FA999EB52EE5C642218C29A7B89505B0BCC8DE3F0805FD7DE")),
SymmetricKey(hex!("45E35694EED05E2D405AE3C53A0FB8DE4C17DDD1CA0384E1B8891691C921AF10"))
),
(
SymmetricKey(hex!("EDD2CBE0F6600D2BD24E3DE742F4D5BFA2E12752EE4755EA54F4EB722A3A680D")),
hex!("889A2FB7606690F67F24CC9471F8CC170461AE804F56D593D019819257FEB473EE9EF1A8E41535A9222A1BECE4A265157391B083811CB22230B8ABD51932631D"),
hex!("3B80A9C4152DEB0E5839680F6779389FCDC2B87DB279F02DA153D1586527C6F1323890F25CEC0E6FFF571F9FBCF2FB97D8147C8922A9C6CBD59C85F365BC8888"),
hex!("B92A0C30721DDFF3BA7CF2CE16212E5ABC0F47FEA930DCDA7FFD09B7F92D37245BC67E1DEA693DBF716375C79F2C592E85CC343F301F2921DB34824333BA4084"),
SymmetricKey(hex!("26B31776AEE6E241BC3A904E9A6CE722B0C54B192F8BBCA1DF6A2FEB1536175E")),
SymmetricKey(hex!("47690A25891F3B96F5F5A9160776DF84A2406DE32A98F11B98B9475F365AEEB0"))
),
(
SymmetricKey(hex!("C5B4F5AEA501B30DCE71AF3AF29D7C46A2ADF20D339B0E772304708FDA129BF7")),
hex!("499BA1825B91F32DC0AB55AEA17865D069A712F046C182AE1BEB47DDE89F71545E6B341A198958E0FCB79EE2B025FF5F91182E548DD2694786F430830C928ADC"),
hex!("1D4389F6BDB20EE777F4E2E8182EE749B6325BCA42B3764BAE9241D929C54BA1C6DD375F7C18F02CED9A7AF145C5CD85D8F2B6D132B92CDDE08BCB1AD57289AD"),
hex!("3994F5715D3B44EE5EF58B9499236D57DCA9057340CADC1EEDF68847DBB488167EEDE5EFBC99E0BB8BA2BB5DE7B0214C0A15AC1EE1CAB717AB47BC19B9D7DF18"),
SymmetricKey(hex!("D726E36DCC8CF5E4CD1DEEEC85D92C11095CA7BC8A84957DA21071888D72B02D")),
SymmetricKey(hex!("B785AB54F3524F64B92189C1269ACBBFD6142668716979C4104C14E5D76D7EA4"))
),
(
SymmetricKey(hex!("3DBF3C21C88563067DEAF0AEF8FE6C128D06830A9F5C5026726B95F6237D1E91")),
hex!("46DED311044C831CFF22A0A20994ED4FF69D479A97EC2561A0F56D567E8E67730B5F965BCAA9AB2C1F244D724B8595E1BA10AA33FA1113FF155CAE8266FF6660"),
hex!("2166E3ADC39363E7B1CC370A62E129E1AF023D3D8F3CB982B8436EAF28604D19C3884A43704C35D5CC9664DFE7EA5462936EC7ED2FB343EDF0DC21674840BB5F"),
hex!("4FBD4381A5CA12504A3C73D1E622D518851EBBFF48E21BAE2B50E6F6FD60C6C1C6DBC40F087070554C6BF5DD612393008AB4D1525BFA685E5A3A3F0AB0B782ED"),
SymmetricKey(hex!("E6080B8B02C39D665F6148C06BE501759C58BD46BC8F830AA19CF1385E4FBA27")),
SymmetricKey(hex!("5F87F0949E6348DDD35C6621A253B1EDA4E5DE87CC85220DF38AED9178E7CF02"))
),
(
SymmetricKey(hex!("50AED6D0960F9013B58A37AFCA49A8AF094312047FDE7498733957ED8140B96A")),
hex!("B6918B421F44B629AA8EAD9C8D31A0314F75C18ADB625064EE8815FDC2A0B604E7A5F9FFC516441018DD758784FE7E2A0C48FEF62FDB50C449AE9AA47A995BC1"),
hex!("738E1A4881F5EE022E42A41981775687D5510D854CF940E58435F6E7E349D9FD13C3B2AB9EF99014DEF44653C8F07331A09B945697FB5E57A67D27E4EC41C32C"),
hex!("1F70A2453C7E4BC961AB57FC910671104A094A498B2B827E3695BBDCB76461BC16E7412BCE06F6B0B0BF0A878A27B1261452D69034AC0119C2269A671C9B6BDF"),
SymmetricKey(hex!("12864AA0913865829F8EC2DA9ABAC54D638F6A923A4F5B91B38782594486F736")),
SymmetricKey(hex!("9B2256F60DD687D26739F0DC41EB809B9A063260CE107C53ED11F0C8CEF96AC8"))
),
];
}