From 892fec9aafd2bd7d4d001c5e5c60587f0a69693b Mon Sep 17 00:00:00 2001
From: Tobias Waurick <tobias.waurick@goto.com>
Date: Fri, 25 Aug 2023 14:53:33 +0200
Subject: [PATCH 1/8] test: add test vectors from draft 03

---
 Cargo.toml                         |    1 +
 src/crypto/aead.rs                 |  247 ++--
 src/crypto/key_expansion.rs        |   48 +-
 src/crypto/secret.rs               |   48 +-
 src/header/mod.rs                  |   10 +-
 src/test_vectors/mod.rs            |  134 ++-
 src/test_vectors/test-vectors.json | 1798 ++++++++++++++++++++++++----
 7 files changed, 1821 insertions(+), 465 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index 7e284ef..bb408fb 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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/src/crypto/aead.rs b/src/crypto/aead.rs
index fbdf9c6..051ecc7 100644
--- a/src/crypto/aead.rs
+++ b/src/crypto/aead.rs
@@ -34,167 +34,116 @@ 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_expansion::KeyExpansion;
+    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()).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.into_iter())
+            .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).unwrap()
+        } else {
+            Secret {
+                key: test_vec.sframe_key.clone(),
+                salt: test_vec.sframe_salt.clone(),
+                auth: None,
             }
         }
     }
diff --git a/src/crypto/key_expansion.rs b/src/crypto/key_expansion.rs
index 0e83d0e..ef1dab4 100644
--- a/src/crypto/key_expansion.rs
+++ b/src/crypto/key_expansion.rs
@@ -23,46 +23,46 @@ pub const SFRAME_HDKF_SUB_AUTH_EXPAND_INFO: &[u8] = b"auth";
 
 #[cfg(test)]
 mod test {
+    use super::KeyExpansion;
     use crate::crypto::cipher_suite::CipherSuite;
     use crate::crypto::secret::Secret;
-    use crate::test_vectors::get_test_vector;
-
+    use crate::test_vectors::get_sframe_test_vector;
     use crate::{crypto::cipher_suite::CipherSuiteVariant, util::test::assert_bytes_eq};
 
-    use super::KeyExpansion;
+    mod aes_gcm {
+        use super::*;
 
-    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();
+        use test_case::test_case;
 
-        assert_bytes_eq(&secret.key, &test_vector.key);
-        assert_bytes_eq(&secret.salt, &test_vector.salt);
-    }
+        #[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());
+            let secret =
+                Secret::expand_from(&CipherSuite::from(variant), &test_vec.key_material).unwrap();
 
-    #[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);
+            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 crate::test_vectors::get_aes_ctr_test_vector;
+
+        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_vector = get_test_vector(&variant.to_string());
+            let test_vec = get_aes_ctr_test_vector(&variant.to_string());
             let cipher_suite = CipherSuite::from(variant);
-            let secret = Secret::expand_from(&cipher_suite, &test_vector.key_material).unwrap();
+            let secret = Secret::expand_from(&cipher_suite, &test_vec.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);
+            assert_bytes_eq(&secret.auth.unwrap(), &test_vec.auth_key);
+            assert_bytes_eq(&secret.key, &test_vec.enc_key);
         }
 
         #[test]
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/header/mod.rs b/src/header/mod.rs
index 4646145..6d8658d 100644
--- a/src/header/mod.rs
+++ b/src/header/mod.rs
@@ -254,25 +254,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/test_vectors/mod.rs b/src/test_vectors/mod.rs
index d2fcfba..89596e8 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 {
-    TEST_VECTORS
+#[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,110 @@ 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")]
-    pub cipher_text: Vec<u8>,
+
+    #[serde(deserialize_with = "vec_from_hex_str")]
+    pub aad: Vec<u8>,
+
+    // TODO rename
+    #[serde(deserialize_with = "vec_from_hex_str")]
+    pub pt: Vec<u8>,
+
+    // TODO rename
+    #[serde(deserialize_with = "vec_from_hex_str")]
+    pub ct: 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_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 +164,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..382b9ce 100644
--- a/src/test_vectors/test-vectors.json
+++ b/src/test_vectors/test-vectors.json
@@ -1,234 +1,1564 @@
-[
-  {
-    "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_label": "534672616d6520312e3020",
+      "sframe_secret": "d926952ca8b7ec4a95941d1ada3a5203ceff8cceee34f574d23909eb314c40c0",
+      "sframe_key": "52cef96e29191912a6be442a9651c43a",
+      "sframe_salt": "9655c98fdad276683deb279c",
+      "metadata": "4945544620534672616d65205747",
+      "nonce": "9655c98fdad276683deb62fb",
+      "aad": "19012345674945544620534672616d65205747",
+      "pt": "64726166742d696574662d736672616d652d656e63",
+      "ct": "1901234567b6a27b2d24f1f06d49cffe6c82af5a96e0d89443a7a93a8700f96fdda3e43c"
+    },
+    {
+      "cipher_suite": 2,
+      "kid": 291,
+      "ctr": 17767,
+      "base_key": "000102030405060708090a0b0c0d0e0f",
+      "sframe_label": "534672616d6520312e3020",
+      "sframe_secret": "d926952ca8b7ec4a95941d1ada3a5203ceff8cceee34f574d23909eb314c40c0",
+      "sframe_key": "52cef96e29191912a6be442a9651c43a",
+      "sframe_salt": "9655c98fdad276683deb279c",
+      "metadata": "4945544620534672616d65205747",
+      "nonce": "9655c98fdad276683deb62fb",
+      "aad": "19012345674945544620534672616d65205747",
+      "pt": "64726166742d696574662d736672616d652d656e63",
+      "ct": "190123456728b1faac3515d5ca29f3db9c52f27789c5ec8386ff0b570853ebcf721c"
+    },
+    {
+      "cipher_suite": 3,
+      "kid": 291,
+      "ctr": 17767,
+      "base_key": "000102030405060708090a0b0c0d0e0f",
+      "sframe_label": "534672616d6520312e3020",
+      "sframe_secret": "d926952ca8b7ec4a95941d1ada3a5203ceff8cceee34f574d23909eb314c40c0",
+      "sframe_key": "52cef96e29191912a6be442a9651c43a",
+      "sframe_salt": "9655c98fdad276683deb279c",
+      "metadata": "4945544620534672616d65205747",
+      "nonce": "9655c98fdad276683deb62fb",
+      "aad": "19012345674945544620534672616d65205747",
+      "pt": "64726166742d696574662d736672616d652d656e63",
+      "ct": "190123456754719dcfbe065e1606068cb6b6b5f1a9a371e633ff088485e7"
+    },
+    {
+      "cipher_suite": 4,
+      "kid": 291,
+      "ctr": 17767,
+      "base_key": "000102030405060708090a0b0c0d0e0f",
+      "sframe_label": "534672616d6520312e3020",
+      "sframe_secret": "d926952ca8b7ec4a95941d1ada3a5203ceff8cceee34f574d23909eb314c40c0",
+      "sframe_key": "52cef96e29191912a6be442a9651c43a",
+      "sframe_salt": "9655c98fdad276683deb279c",
+      "metadata": "4945544620534672616d65205747",
+      "nonce": "9655c98fdad276683deb62fb",
+      "aad": "19012345674945544620534672616d65205747",
+      "pt": "64726166742d696574662d736672616d652d656e63",
+      "ct": "1901234567d4dfcd537dbd054dcf4bdab53bf451826843325838178391f63dc15b9475d6081b59c776a5"
+    },
+    {
+      "cipher_suite": 5,
+      "kid": 291,
+      "ctr": 17767,
+      "base_key": "000102030405060708090a0b0c0d0e0f",
+      "sframe_label": "534672616d6520312e3020",
+      "sframe_secret": "0fc3ea6de6aac97a35f194cf9bed94d4b5230f1cb45a785c9fe5dce9c188938ab6ba005bc4c0a19181599e9d1bcf7b74aca48b60bf5e254e546d809313e083a3",
+      "sframe_key": "5f3f7c1b277d9cad86b906da39702c3fcdf720902817977ae99bd10f2e5ad56a",
+      "sframe_salt": "a653f558a8018877314fb8d9",
+      "metadata": "4945544620534672616d65205747",
+      "nonce": "a653f558a8018877314ffdbe",
+      "aad": "19012345674945544620534672616d65205747",
+      "pt": "64726166742d696574662d736672616d652d656e63",
+      "ct": "19012345672f55e5feb46d118576dc715566003f4becf5252149c839aea7dd5434bf8eceb8b4d59bbfb2"
+    }
+  ]
+}

From b8f7953a9fc4dfcf8c459142b17baccfb6107693 Mon Sep 17 00:00:00 2001
From: Tobias Waurick <tobias.waurick@goto.com>
Date: Fri, 1 Sep 2023 17:16:20 +0200
Subject: [PATCH 2/8] feat(crypto): update key derivation / tag computation to
 draft-03

With the newest draft now also the key id/auth tag length is used during the key derivation
to create distinct salts. Also for AES CTR mode ciphers the tag length is also taken into
account when computing the tag

BREAKING CHANGE:
The latest [changes in the draft](https://author-tools.ietf.org/diff?doc_1=draft-ietf-sframe-enc-01&doc_2=draft-ietf-sframe-enc-03) regarding the key derivation and tag computation, make theimplementation incompatible with previous versions
---
 Cargo.toml                          |   2 +-
 src/crypto/aead.rs                  |   5 +-
 src/crypto/cipher_suite.rs          |   2 +-
 src/crypto/key_expansion.rs         | 102 ++++++++++++++++++----------
 src/crypto/openssl/aead.rs          |   9 ++-
 src/crypto/openssl/key_expansion.rs |  52 +++++++++++---
 src/crypto/ring/key_expansion.rs    |  27 +++++---
 src/header/basic_header.rs          |   2 +-
 src/header/extended_header.rs       |   2 +-
 src/header/mod.rs                   |   7 +-
 src/receiver.rs                     |   5 +-
 src/sender.rs                       |  69 ++-----------------
 src/test_vectors/mod.rs             |  10 ++-
 13 files changed, 154 insertions(+), 140 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index bb408fb..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"
diff --git a/src/crypto/aead.rs b/src/crypto/aead.rs
index 051ecc7..abe7815 100644
--- a/src/crypto/aead.rs
+++ b/src/crypto/aead.rs
@@ -60,7 +60,8 @@ mod test {
         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 secret =
+            Secret::expand_from(&cipher_suite, KEY_MATERIAL.as_bytes(), KeyId::default()).unwrap();
 
         let _tag = cipher_suite
             .encrypt(
@@ -138,7 +139,7 @@ mod test {
     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).unwrap()
+            Secret::expand_from(cipher_suite, &test_vec.key_material, test_vec.key_id).unwrap()
         } else {
             Secret {
                 key: test_vec.sframe_key.clone(),
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_expansion.rs b/src/crypto/key_expansion.rs
index ef1dab4..d0201e9 100644
--- a/src/crypto/key_expansion.rs
+++ b/src/crypto/key_expansion.rs
@@ -5,22 +5,58 @@ 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>
+    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>;
 }
 
-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";
+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()
+}
 
-#[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";
+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 ";
+
+// For the current test vectors different labels than specified were used
+// see https://github.com/sframe-wg/sframe/issues/137
+cfg_if::cfg_if! {
+    if #[cfg(test)] {
+        const SFRAME_HKDF_KEY_EXPAND_INFO: &[u8] = b"key ";
+        const SFRAME_HDKF_SALT_EXPAND_INFO: &[u8] = b"salt ";
+    } else {
+        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
+            return [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(feature = "openssl")]
 #[cfg(test)]
 mod test {
     use super::KeyExpansion;
@@ -30,16 +66,26 @@ mod test {
     use crate::{crypto::cipher_suite::CipherSuiteVariant, util::test::assert_bytes_eq};
 
     mod aes_gcm {
+        use crate::crypto::key_expansion::SFRAME_LABEL;
+
         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());
-            let secret =
-                Secret::expand_from(&CipherSuite::from(variant), &test_vec.key_material).unwrap();
+
+            assert_bytes_eq(SFRAME_LABEL, &test_vec.sframe_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);
@@ -49,37 +95,23 @@ mod test {
     #[cfg(feature = "openssl")]
     mod aes_ctr {
         use super::*;
-        use crate::test_vectors::get_aes_ctr_test_vector;
-
         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 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).unwrap();
 
-            assert_bytes_eq(&secret.auth.unwrap(), &test_vec.auth_key);
-            assert_bytes_eq(&secret.key, &test_vec.enc_key);
-        }
-
-        #[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);
-        }
+            let secret =
+                Secret::expand_from(&cipher_suite, &test_vec.key_material, test_vec.key_id)
+                    .unwrap();
 
-        #[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);
+            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/openssl/aead.rs b/src/crypto/openssl/aead.rs
index ad8d9ee..6c1e1d9 100644
--- a/src/crypto/openssl/aead.rs
+++ b/src/crypto/openssl/aead.rs
@@ -190,11 +190,14 @@ 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] {
+        let aad_len = &(aad.len() as u64).to_be_bytes();
+        let ct_len = &(encrypted.len() as u64).to_be_bytes();
+        let tag_len = &(self.auth_tag_len as u64).to_be_bytes();
+
+        for buf in [aad_len, ct_len, tag_len, nonce, aad, encrypted] {
             signer.update(buf)?;
         }
+
         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_expansion.rs
index 1cf4346..f2b9dbe 100644
--- a/src/crypto/openssl/key_expansion.rs
+++ b/src/crypto/openssl/key_expansion.rs
@@ -5,9 +5,8 @@ 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,
+            get_hkdf_aead_label, get_hkdf_key_expand_info, get_hkdf_salt_expand_info, KeyExpansion,
+            SFRAME_HDKF_SUB_AUTH_EXPAND_INFO, SFRAME_HKDF_SUB_ENC_EXPAND_INFO,
         },
         secret::Secret,
     },
@@ -15,12 +14,14 @@ use crate::{
 };
 
 impl KeyExpansion for Secret {
-    fn expand_from<T>(cipher_suite: &CipherSuite, key_material: T) -> Result<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))
@@ -38,18 +39,20 @@ impl KeyExpansion for Secret {
 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/ring/key_expansion.rs b/src/crypto/ring/key_expansion.rs
index 2d904a0..04cc90a 100644
--- a/src/crypto/ring/key_expansion.rs
+++ b/src/crypto/ring/key_expansion.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_expansion::{get_hkdf_key_expand_info, get_hkdf_salt_expand_info, KeyExpansion},
         secret::Secret,
     },
     error::{Result, SframeError},
 };
 
 impl KeyExpansion for Secret {
-    fn expand_from<T>(cipher_suite: &CipherSuite, key_material: T) -> Result<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,
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 6d8658d..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;
 
diff --git a/src/receiver.rs b/src/receiver.rs
index 42f430d..1654f35 100644
--- a/src/receiver.rs
+++ b/src/receiver.rs
@@ -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..fc464c8 100644
--- a/src/sender.rs
+++ b/src/sender.rs
@@ -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 89596e8..29bfc12 100644
--- a/src/test_vectors/mod.rs
+++ b/src/test_vectors/mod.rs
@@ -86,13 +86,11 @@ pub struct AesCtrHmacTest {
     #[serde(deserialize_with = "vec_from_hex_str")]
     pub aad: Vec<u8>,
 
-    // TODO rename
-    #[serde(deserialize_with = "vec_from_hex_str")]
-    pub pt: Vec<u8>,
+    #[serde(rename = "pt", deserialize_with = "vec_from_hex_str")]
+    pub plain_text: Vec<u8>,
 
-    // TODO rename
-    #[serde(deserialize_with = "vec_from_hex_str")]
-    pub ct: Vec<u8>,
+    #[serde(rename = "ct", deserialize_with = "vec_from_hex_str")]
+    pub cipher_text: Vec<u8>,
 }
 
 #[derive(serde::Deserialize, Debug, Clone)]

From 4014407dc333780dac83a95004b70dfea1553b5c Mon Sep 17 00:00:00 2001
From: Tobias Waurick <tobias.waurick@goto.com>
Date: Fri, 1 Sep 2023 17:19:52 +0200
Subject: [PATCH 3/8] refactor: rename KeyExpansion to KeyDerivation

so the name matches the one in the spec

BREAKING CHANGE:

Instead of `SframeError.KeyExpansion` use `SframeError.KeyDerivation`
---
 src/crypto/aead.rs                                     |  2 +-
 src/crypto/{key_expansion.rs => key_derivation.rs}     |  6 +++---
 src/crypto/mod.rs                                      |  2 +-
 .../openssl/{key_expansion.rs => key_derivation.rs}    | 10 +++++-----
 src/crypto/openssl/mod.rs                              |  2 +-
 src/crypto/ring/aead.rs                                |  2 +-
 .../ring/{key_expansion.rs => key_derivation.rs}       |  6 +++---
 src/crypto/ring/mod.rs                                 |  2 +-
 src/error.rs                                           |  2 +-
 src/receiver.rs                                        |  2 +-
 src/sender.rs                                          |  2 +-
 11 files changed, 19 insertions(+), 19 deletions(-)
 rename src/crypto/{key_expansion.rs => key_derivation.rs} (97%)
 rename src/crypto/openssl/{key_expansion.rs => key_derivation.rs} (96%)
 rename src/crypto/ring/{key_expansion.rs => key_derivation.rs} (91%)

diff --git a/src/crypto/aead.rs b/src/crypto/aead.rs
index abe7815..cef8432 100644
--- a/src/crypto/aead.rs
+++ b/src/crypto/aead.rs
@@ -34,7 +34,7 @@ pub trait AeadDecrypt {
 #[cfg(test)]
 mod test {
 
-    use crate::crypto::key_expansion::KeyExpansion;
+    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;
diff --git a/src/crypto/key_expansion.rs b/src/crypto/key_derivation.rs
similarity index 97%
rename from src/crypto/key_expansion.rs
rename to src/crypto/key_derivation.rs
index d0201e9..fb579ee 100644
--- a/src/crypto/key_expansion.rs
+++ b/src/crypto/key_derivation.rs
@@ -4,7 +4,7 @@
 use super::{cipher_suite::CipherSuite, secret::Secret};
 use crate::error::Result;
 
-pub trait KeyExpansion {
+pub trait KeyDerivation {
     fn expand_from<M, K>(cipher_suite: &CipherSuite, key_material: M, key_id: K) -> Result<Secret>
     where
         M: AsRef<[u8]>,
@@ -59,14 +59,14 @@ cfg_if::cfg_if! {
 #[cfg(feature = "openssl")]
 #[cfg(test)]
 mod test {
-    use super::KeyExpansion;
+    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_expansion::SFRAME_LABEL;
+        use crate::crypto::key_derivation::SFRAME_LABEL;
 
         use super::*;
 
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/key_expansion.rs b/src/crypto/openssl/key_derivation.rs
similarity index 96%
rename from src/crypto/openssl/key_expansion.rs
rename to src/crypto/openssl/key_derivation.rs
index f2b9dbe..ee68ccd 100644
--- a/src/crypto/openssl/key_expansion.rs
+++ b/src/crypto/openssl/key_derivation.rs
@@ -4,16 +4,16 @@
 use crate::{
     crypto::{
         cipher_suite::{CipherSuite, CipherSuiteVariant},
-        key_expansion::{
-            get_hkdf_aead_label, get_hkdf_key_expand_info, get_hkdf_salt_expand_info, KeyExpansion,
-            SFRAME_HDKF_SUB_AUTH_EXPAND_INFO, SFRAME_HKDF_SUB_ENC_EXPAND_INFO,
+        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 {
+impl KeyDerivation for Secret {
     fn expand_from<M, K>(cipher_suite: &CipherSuite, key_material: M, key_id: K) -> Result<Secret>
     where
         M: AsRef<[u8]>,
@@ -32,7 +32,7 @@ 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)
     }
 }
 
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 91%
rename from src/crypto/ring/key_expansion.rs
rename to src/crypto/ring/key_derivation.rs
index 04cc90a..7965ec3 100644
--- a/src/crypto/ring/key_expansion.rs
+++ b/src/crypto/ring/key_derivation.rs
@@ -4,13 +4,13 @@
 use crate::{
     crypto::{
         cipher_suite::{CipherSuite, CipherSuiteVariant},
-        key_expansion::{get_hkdf_key_expand_info, get_hkdf_salt_expand_info, KeyExpansion},
+        key_derivation::{get_hkdf_key_expand_info, get_hkdf_salt_expand_info, KeyDerivation},
         secret::Secret,
     },
     error::{Result, SframeError},
 };
 
-impl KeyExpansion for Secret {
+impl KeyDerivation for Secret {
     fn expand_from<M, K>(cipher_suite: &CipherSuite, key_material: M, key_id: K) -> Result<Secret>
     where
         M: AsRef<[u8]>,
@@ -63,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/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/receiver.rs b/src/receiver.rs
index 1654f35..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},
diff --git a/src/sender.rs b/src/sender.rs
index fc464c8..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},

From a7b988f2203c5fd70fcdb9a1b4b098d70d7812ab Mon Sep 17 00:00:00 2001
From: Tobias Waurick <tobtherock@proton.me>
Date: Sat, 2 Sep 2023 17:45:26 +0200
Subject: [PATCH 4/8] test: update test vectors

upstream bug was closed
---
 src/crypto/key_derivation.rs       | 27 +++++++--------
 src/test_vectors/mod.rs            |  9 +++--
 src/test_vectors/test-vectors.json | 55 ++++++++++++++++--------------
 3 files changed, 48 insertions(+), 43 deletions(-)

diff --git a/src/crypto/key_derivation.rs b/src/crypto/key_derivation.rs
index fb579ee..2103e76 100644
--- a/src/crypto/key_derivation.rs
+++ b/src/crypto/key_derivation.rs
@@ -31,23 +31,14 @@ pub fn get_hkdf_salt_expand_info(key_id: u64) -> Vec<u8> {
 
 const SFRAME_LABEL: &[u8] = b"SFrame 1.0 ";
 
-// For the current test vectors different labels than specified were used
-// see https://github.com/sframe-wg/sframe/issues/137
-cfg_if::cfg_if! {
-    if #[cfg(test)] {
-        const SFRAME_HKDF_KEY_EXPAND_INFO: &[u8] = b"key ";
-        const SFRAME_HDKF_SALT_EXPAND_INFO: &[u8] = b"salt ";
-    } else {
-        const SFRAME_HKDF_KEY_EXPAND_INFO: &[u8] = b"Secret key ";
-        const SFRAME_HDKF_SALT_EXPAND_INFO: &[u8] = b"Secret salt ";
-    }
-}
+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
-            return [SFRAME_HDKF_SUB_AEAD_LABEL, &(tag_len).to_be_bytes()].concat()
+            [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 ";
@@ -56,7 +47,6 @@ cfg_if::cfg_if! {
     }
 }
 
-#[cfg(feature = "openssl")]
 #[cfg(test)]
 mod test {
     use super::KeyDerivation;
@@ -66,7 +56,7 @@ mod test {
     use crate::{crypto::cipher_suite::CipherSuiteVariant, util::test::assert_bytes_eq};
 
     mod aes_gcm {
-        use crate::crypto::key_derivation::SFRAME_LABEL;
+        use crate::crypto::key_derivation::{get_hkdf_key_expand_info, get_hkdf_salt_expand_info};
 
         use super::*;
 
@@ -78,7 +68,14 @@ mod test {
         fn derive_correct_base_keys(variant: CipherSuiteVariant) {
             let test_vec = get_sframe_test_vector(&variant.to_string());
 
-            assert_bytes_eq(SFRAME_LABEL, &test_vec.sframe_label);
+            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),
diff --git a/src/test_vectors/mod.rs b/src/test_vectors/mod.rs
index 29bfc12..47f722b 100644
--- a/src/test_vectors/mod.rs
+++ b/src/test_vectors/mod.rs
@@ -17,7 +17,7 @@ pub fn get_header_test_vectors() -> &'static Vec<HeaderTest> {
 }
 
 pub fn get_aes_ctr_test_vector(cipher_suite_variant: &str) -> &'static AesCtrHmacTest {
-    &TEST_VECTORS
+    TEST_VECTORS
         .aes_ctr_hmac
         .iter()
         .find(|v| v.cipher_suite_variant == cipher_suite_variant)
@@ -25,7 +25,7 @@ pub fn get_aes_ctr_test_vector(cipher_suite_variant: &str) -> &'static AesCtrHma
 }
 
 pub fn get_sframe_test_vector(cipher_suite_variant: &str) -> &'static SframeTest {
-    &TEST_VECTORS
+    TEST_VECTORS
         .sframe
         .iter()
         .find(|v| v.cipher_suite_variant == cipher_suite_variant)
@@ -111,7 +111,10 @@ pub struct SframeTest {
     pub key_material: Vec<u8>,
 
     #[serde(deserialize_with = "vec_from_hex_str")]
-    pub sframe_label: 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>,
diff --git a/src/test_vectors/test-vectors.json b/src/test_vectors/test-vectors.json
index 382b9ce..98a6c15 100644
--- a/src/test_vectors/test-vectors.json
+++ b/src/test_vectors/test-vectors.json
@@ -1490,75 +1490,80 @@
       "kid": 291,
       "ctr": 17767,
       "base_key": "000102030405060708090a0b0c0d0e0f",
-      "sframe_label": "534672616d6520312e3020",
+      "sframe_key_label": "534672616d6520312e3020536563726574206b6579200000000000000123",
+      "sframe_salt_label": "534672616d6520312e30205365637265742073616c74200000000000000123",
       "sframe_secret": "d926952ca8b7ec4a95941d1ada3a5203ceff8cceee34f574d23909eb314c40c0",
-      "sframe_key": "52cef96e29191912a6be442a9651c43a",
-      "sframe_salt": "9655c98fdad276683deb279c",
+      "sframe_key": "73bb177a9fe6c02597132fe430ca2d99",
+      "sframe_salt": "55582aa5aaced36a74544d91",
       "metadata": "4945544620534672616d65205747",
-      "nonce": "9655c98fdad276683deb62fb",
+      "nonce": "55582aa5aaced36a745408f6",
       "aad": "19012345674945544620534672616d65205747",
       "pt": "64726166742d696574662d736672616d652d656e63",
-      "ct": "1901234567b6a27b2d24f1f06d49cffe6c82af5a96e0d89443a7a93a8700f96fdda3e43c"
+      "ct": "190123456740043f25262c0ca52e9374b070f24b02764715c2e303388c9495324037d043"
     },
     {
       "cipher_suite": 2,
       "kid": 291,
       "ctr": 17767,
       "base_key": "000102030405060708090a0b0c0d0e0f",
-      "sframe_label": "534672616d6520312e3020",
+      "sframe_key_label": "534672616d6520312e3020536563726574206b6579200000000000000123",
+      "sframe_salt_label": "534672616d6520312e30205365637265742073616c74200000000000000123",
       "sframe_secret": "d926952ca8b7ec4a95941d1ada3a5203ceff8cceee34f574d23909eb314c40c0",
-      "sframe_key": "52cef96e29191912a6be442a9651c43a",
-      "sframe_salt": "9655c98fdad276683deb279c",
+      "sframe_key": "73bb177a9fe6c02597132fe430ca2d99",
+      "sframe_salt": "55582aa5aaced36a74544d91",
       "metadata": "4945544620534672616d65205747",
-      "nonce": "9655c98fdad276683deb62fb",
+      "nonce": "55582aa5aaced36a745408f6",
       "aad": "19012345674945544620534672616d65205747",
       "pt": "64726166742d696574662d736672616d652d656e63",
-      "ct": "190123456728b1faac3515d5ca29f3db9c52f27789c5ec8386ff0b570853ebcf721c"
+      "ct": "1901234567729eef4910d734abfd392cdff0f67d2a8d06041eef5f895e4cecc03a6d"
     },
     {
       "cipher_suite": 3,
       "kid": 291,
       "ctr": 17767,
       "base_key": "000102030405060708090a0b0c0d0e0f",
-      "sframe_label": "534672616d6520312e3020",
+      "sframe_key_label": "534672616d6520312e3020536563726574206b6579200000000000000123",
+      "sframe_salt_label": "534672616d6520312e30205365637265742073616c74200000000000000123",
       "sframe_secret": "d926952ca8b7ec4a95941d1ada3a5203ceff8cceee34f574d23909eb314c40c0",
-      "sframe_key": "52cef96e29191912a6be442a9651c43a",
-      "sframe_salt": "9655c98fdad276683deb279c",
+      "sframe_key": "73bb177a9fe6c02597132fe430ca2d99",
+      "sframe_salt": "55582aa5aaced36a74544d91",
       "metadata": "4945544620534672616d65205747",
-      "nonce": "9655c98fdad276683deb62fb",
+      "nonce": "55582aa5aaced36a745408f6",
       "aad": "19012345674945544620534672616d65205747",
       "pt": "64726166742d696574662d736672616d652d656e63",
-      "ct": "190123456754719dcfbe065e1606068cb6b6b5f1a9a371e633ff088485e7"
+      "ct": "190123456717fd0a325fdcd5f0d68089ee5bd17df6296b69b6b0e70c8d73"
     },
     {
       "cipher_suite": 4,
       "kid": 291,
       "ctr": 17767,
       "base_key": "000102030405060708090a0b0c0d0e0f",
-      "sframe_label": "534672616d6520312e3020",
+      "sframe_key_label": "534672616d6520312e3020536563726574206b6579200000000000000123",
+      "sframe_salt_label": "534672616d6520312e30205365637265742073616c74200000000000000123",
       "sframe_secret": "d926952ca8b7ec4a95941d1ada3a5203ceff8cceee34f574d23909eb314c40c0",
-      "sframe_key": "52cef96e29191912a6be442a9651c43a",
-      "sframe_salt": "9655c98fdad276683deb279c",
+      "sframe_key": "73bb177a9fe6c02597132fe430ca2d99",
+      "sframe_salt": "55582aa5aaced36a74544d91",
       "metadata": "4945544620534672616d65205747",
-      "nonce": "9655c98fdad276683deb62fb",
+      "nonce": "55582aa5aaced36a745408f6",
       "aad": "19012345674945544620534672616d65205747",
       "pt": "64726166742d696574662d736672616d652d656e63",
-      "ct": "1901234567d4dfcd537dbd054dcf4bdab53bf451826843325838178391f63dc15b9475d6081b59c776a5"
+      "ct": "1901234567b8bf87709717f709a35b4e91b2109e5c1ca4f76179415f8bb15d70a9be7eb89c7adb76d300"
     },
     {
       "cipher_suite": 5,
       "kid": 291,
       "ctr": 17767,
       "base_key": "000102030405060708090a0b0c0d0e0f",
-      "sframe_label": "534672616d6520312e3020",
+      "sframe_key_label": "534672616d6520312e3020536563726574206b6579200000000000000123",
+      "sframe_salt_label": "534672616d6520312e30205365637265742073616c74200000000000000123",
       "sframe_secret": "0fc3ea6de6aac97a35f194cf9bed94d4b5230f1cb45a785c9fe5dce9c188938ab6ba005bc4c0a19181599e9d1bcf7b74aca48b60bf5e254e546d809313e083a3",
-      "sframe_key": "5f3f7c1b277d9cad86b906da39702c3fcdf720902817977ae99bd10f2e5ad56a",
-      "sframe_salt": "a653f558a8018877314fb8d9",
+      "sframe_key": "e9e405efb7cd325030760935bf49fd5669d7c19eb84ca74b419a1487cf835107",
+      "sframe_salt": "11007b537a1cf728a4c544c1",
       "metadata": "4945544620534672616d65205747",
-      "nonce": "a653f558a8018877314ffdbe",
+      "nonce": "11007b537a1cf728a4c501a6",
       "aad": "19012345674945544620534672616d65205747",
       "pt": "64726166742d696574662d736672616d652d656e63",
-      "ct": "19012345672f55e5feb46d118576dc715566003f4becf5252149c839aea7dd5434bf8eceb8b4d59bbfb2"
+      "ct": "19012345671e11c62748536fd55fdbc9560daea4825bfecbb05489cd41cb7a1556e001989a4485e8a02f"
     }
   ]
 }

From a1b3c4cc5a848be45410293ede59667c2cb4e27d Mon Sep 17 00:00:00 2001
From: Tobias Waurick <tobtherock@proton.me>
Date: Sun, 3 Sep 2023 20:14:18 +0200
Subject: [PATCH 5/8] refactor: fix clippy warning

---
 src/crypto/aead.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/crypto/aead.rs b/src/crypto/aead.rs
index cef8432..6eec782 100644
--- a/src/crypto/aead.rs
+++ b/src/crypto/aead.rs
@@ -100,7 +100,7 @@ mod test {
 
         let full_frame: Vec<u8> = header_buffer
             .into_iter()
-            .chain(data_buffer.into_iter())
+            .chain(data_buffer)
             .chain(tag.as_ref().iter().cloned())
             .collect();
 

From 493c831ad783159606a4fd31910397eeae39b442 Mon Sep 17 00:00:00 2001
From: Tobias Waurick <tobtherock@proton.me>
Date: Wed, 11 Oct 2023 13:21:46 +0200
Subject: [PATCH 6/8] docs: update README

---
 README.md | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

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)
 ![maintenance](https://img.shields.io/maintenance/yes/2023)
 
 
-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.

From e4c8a6e31edaeb7d3ac4fe32d9d486f80f42641b Mon Sep 17 00:00:00 2001
From: Tobias Waurick <tobtherock@proton.me>
Date: Sat, 21 Oct 2023 19:02:07 +0200
Subject: [PATCH 7/8] test: add aes-ctr benches

---
 benches/crypto.rs | 6 ++++++
 1 file changed, 6 insertions(+)

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);

From 987db3b943ce584eb318f3ffba764f5047aeddd8 Mon Sep 17 00:00:00 2001
From: Hendrik Sollich <hendrik@hoodie.de>
Date: Sat, 28 Oct 2023 11:42:55 +0200
Subject: [PATCH 8/8] refactor: manually unroll loop

---
 src/crypto/openssl/aead.rs | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/src/crypto/openssl/aead.rs b/src/crypto/openssl/aead.rs
index 6c1e1d9..4102711 100644
--- a/src/crypto/openssl/aead.rs
+++ b/src/crypto/openssl/aead.rs
@@ -190,13 +190,12 @@ 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();
-        let tag_len = &(self.auth_tag_len as u64).to_be_bytes();
-
-        for buf in [aad_len, ct_len, tag_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);