1 // Copyright 2022 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #![allow(clippy::indexing_slicing, clippy::unwrap_used)]
16
17 use anyhow::anyhow;
18 use crypto_provider::aes::AesKey;
19 use crypto_provider_default::CryptoProviderImpl;
20 use np_hkdf::{v1_salt::ExtendedV1Salt, *};
21 use serde_json::json;
22 use std::{fs, io::Read as _};
23 use test_helper::extract_key_array;
24 use test_vector_hkdf::TestVectorHkdf;
25
26 #[test]
hkdf_test_vectors() -> Result<(), anyhow::Error>27 fn hkdf_test_vectors() -> Result<(), anyhow::Error> {
28 let full_path =
29 test_helper::get_data_file("presence/np_hkdf/resources/test/hkdf-test-vectors.json");
30 let mut file = fs::File::open(full_path)?;
31 let mut data = String::new();
32 let _ = file.read_to_string(&mut data)?;
33 let test_cases = match serde_json::de::from_str(&data)? {
34 serde_json::Value::Array(a) => a,
35 _ => return Err(anyhow!("bad json")),
36 };
37
38 for tc in test_cases {
39 {
40 let group = &tc["key_seed_hkdf"];
41 let key_seed = extract_key_array::<32>(group, "key_seed");
42 let hkdf = NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed);
43 assert_eq!(
44 extract_key_array::<64>(group, "v0_ldt_key"),
45 hkdf.v0_ldt_key().as_concatenated()
46 );
47 assert_eq!(
48 &extract_key_array::<32>(group, "v0_identity_token_hmac_key"),
49 hkdf.v0_identity_token_hmac_key().as_bytes()
50 );
51 assert_eq!(
52 extract_key_array::<12>(group, "v0_metadata_nonce"),
53 hkdf.v0_metadata_nonce()
54 );
55 assert_eq!(
56 extract_key_array::<12>(group, "v1_metadata_nonce"),
57 hkdf.v1_metadata_nonce()
58 );
59 assert_eq!(
60 &extract_key_array::<32>(group, "v1_mic_short_salt_identity_token_hmac_key"),
61 hkdf.v1_mic_short_salt_keys().identity_token_hmac_key().as_bytes()
62 );
63 assert_eq!(
64 extract_key_array::<16>(group, "v1_mic_short_salt_aes_key"),
65 *hkdf.v1_mic_short_salt_keys().aes_key().as_array()
66 );
67 assert_eq!(
68 &extract_key_array::<32>(group, "v1_mic_short_salt_mic_hmac_key"),
69 hkdf.v1_mic_short_salt_keys().mic_hmac_key().as_bytes()
70 );
71 assert_eq!(
72 &extract_key_array::<32>(group, "v1_mic_extended_salt_identity_token_hmac_key"),
73 hkdf.v1_mic_extended_salt_keys().identity_token_hmac_key().as_bytes()
74 );
75 assert_eq!(
76 extract_key_array::<16>(group, "v1_mic_extended_salt_aes_key"),
77 *hkdf.v1_mic_extended_salt_keys().aes_key().as_array()
78 );
79 assert_eq!(
80 &extract_key_array::<32>(group, "v1_mic_extended_salt_mic_hmac_key"),
81 hkdf.v1_mic_extended_salt_keys().mic_hmac_key().as_bytes()
82 );
83 assert_eq!(
84 &extract_key_array::<32>(group, "v1_signature_identity_token_hmac_key"),
85 hkdf.v1_signature_keys().identity_token_hmac_key().as_bytes()
86 );
87 assert_eq!(
88 extract_key_array::<16>(group, "v1_signature_section_aes_key"),
89 *hkdf.v1_signature_keys().aes_key().as_array()
90 );
91 }
92
93 {
94 let group = &tc["v0_adv_salt_hkdf"];
95 let ikm = extract_key_array::<2>(group, "adv_salt");
96 assert_eq!(
97 extract_key_array::<16>(group, "expanded_salt"),
98 v0_ldt_expanded_salt::<CryptoProviderImpl>(&ikm)
99 )
100 }
101
102 {
103 let group = &tc["v0_identity_token_hkdf"];
104 let ikm = extract_key_array::<14>(group, "v0_identity_token");
105 assert_eq!(
106 extract_key_array::<16>(group, "expanded_key"),
107 v0_metadata_expanded_key::<CryptoProviderImpl>(&ikm)
108 )
109 }
110
111 {
112 let group = &tc["v1_section_extended_salt_hkdf"];
113 let ikm = extract_key_array::<16>(group, "section_extended_salt");
114 let salt = ExtendedV1Salt::from(ikm);
115 assert_eq!(
116 extract_key_array::<16>(group, "derived_salt_nonce"),
117 salt.derive::<16, CryptoProviderImpl>(None).unwrap(),
118 );
119 assert_eq!(
120 extract_key_array::<16>(group, "derived_salt_first_de"),
121 salt.derive::<16, CryptoProviderImpl>(Some(0.into())).unwrap(),
122 );
123 assert_eq!(
124 extract_key_array::<16>(group, "derived_salt_third_de"),
125 salt.derive::<16, CryptoProviderImpl>(Some(2.into())).unwrap(),
126 );
127 }
128
129 {
130 let group = &tc["v1_mic_section_short_salt_hkdf"];
131 let ikm = extract_key_array::<2>(group, "section_short_salt");
132 assert_eq!(
133 extract_key_array::<12>(group, "short_salt_nonce"),
134 extended_mic_section_short_salt_nonce::<CryptoProviderImpl>(ikm),
135 );
136 }
137 }
138
139 Ok(())
140 }
141
142 // disable unless you want to print out a new set of test vectors
143 #[ignore]
144 #[allow(clippy::panic)]
145 #[test]
gen_test_vectors()146 fn gen_test_vectors() {
147 let mut array = Vec::<serde_json::Value>::new();
148
149 for i in 0_u32..100 {
150 // build "random" things in a repeatable way so future changes don't
151 // rebuild unrelated things, with some /dev/random thrown in for good measure
152 let test_vector_seed_hkdf = TestVectorHkdf::<CryptoProviderImpl>::new(
153 "NP HKDF test vectors pb4qoNqM9aL/ezSC2FU5EQzu8JJoJ25B+rLqbU5kVN8",
154 &i.to_be_bytes(),
155 );
156
157 let key_seed: [u8; 32] = test_vector_seed_hkdf.derive_array("key seed");
158 let v0_adv_salt: [u8; 2] = test_vector_seed_hkdf.derive_array("legacy adv salt");
159 let v0_identity_token: [u8; 14] = test_vector_seed_hkdf.derive_array("v0 identity token");
160 let extended_salt_bytes: [u8; 16] =
161 test_vector_seed_hkdf.derive_array("v1 section extended salt");
162 let v1_mic_short_salt: [u8; 2] =
163 test_vector_seed_hkdf.derive_array("v1 mic section short salt");
164 let v1_extended_salt = ExtendedV1Salt::from(extended_salt_bytes);
165
166 let key_seed_hkdf = NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed);
167 array
168 .push(json!({
169 "key_seed_hkdf": {
170 "key_seed": hex::encode_upper(key_seed),
171 "v0_ldt_key": hex::encode_upper(key_seed_hkdf.v0_ldt_key().as_concatenated()),
172 "v0_identity_token_hmac_key":
173 hex::encode_upper(key_seed_hkdf.v0_identity_token_hmac_key().as_bytes()),
174 "v0_metadata_nonce": hex::encode_upper(key_seed_hkdf.v0_metadata_nonce()),
175 "v1_metadata_nonce": hex::encode_upper(key_seed_hkdf.v1_metadata_nonce()),
176 "v1_mic_short_salt_identity_token_hmac_key": hex::encode_upper(key_seed_hkdf.v1_mic_short_salt_keys().identity_token_hmac_key().as_bytes()),
177 "v1_mic_short_salt_aes_key": hex::encode_upper(key_seed_hkdf.v1_mic_short_salt_keys().aes_key().as_array()),
178 "v1_mic_short_salt_mic_hmac_key": hex::encode_upper(key_seed_hkdf.v1_mic_short_salt_keys().mic_hmac_key().as_bytes()),
179 "v1_mic_extended_salt_identity_token_hmac_key": hex::encode_upper(key_seed_hkdf.v1_mic_extended_salt_keys().identity_token_hmac_key().as_bytes()),
180 "v1_mic_extended_salt_aes_key": hex::encode_upper(key_seed_hkdf.v1_mic_extended_salt_keys().aes_key().as_array()),
181 "v1_mic_extended_salt_mic_hmac_key": hex::encode_upper(key_seed_hkdf.v1_mic_extended_salt_keys().mic_hmac_key().as_bytes()),
182 "v1_signature_identity_token_hmac_key": hex::encode_upper(key_seed_hkdf.v1_signature_keys().identity_token_hmac_key().as_bytes()),
183 "v1_signature_section_aes_key": hex::encode_upper(key_seed_hkdf.v1_signature_keys().aes_key().as_array()),
184 },
185 "v0_adv_salt_hkdf": {
186 "adv_salt": hex::encode_upper(v0_adv_salt),
187 "expanded_salt": hex::encode_upper(v0_ldt_expanded_salt::<CryptoProviderImpl>(&v0_adv_salt))
188 },
189 "v0_identity_token_hkdf": {
190 "v0_identity_token": hex::encode_upper(v0_identity_token),
191 "expanded_key":
192 hex::encode_upper(v0_metadata_expanded_key::<CryptoProviderImpl>(&v0_identity_token))
193 },
194 "v1_section_extended_salt_hkdf": {
195 "section_extended_salt": hex::encode_upper(v1_extended_salt.bytes()),
196 // 0-based offsets -> 1-based indexing
197 "derived_salt_nonce": hex::encode_upper(v1_extended_salt.derive::<16, CryptoProviderImpl>(None).unwrap()),
198 "derived_salt_first_de": hex::encode_upper(v1_extended_salt.derive::<16, CryptoProviderImpl>(Some(0.into())).unwrap()),
199 "derived_salt_third_de": hex::encode_upper(v1_extended_salt.derive::<16, CryptoProviderImpl>(Some(2.into())).unwrap()),
200 },
201 "v1_mic_section_short_salt_hkdf": {
202 "section_short_salt": hex::encode_upper(v1_mic_short_salt),
203 "short_salt_nonce": hex::encode_upper(extended_mic_section_short_salt_nonce::<CryptoProviderImpl>(v1_mic_short_salt)),
204 }
205 }));
206 }
207
208 println!("{}", serde_json::ser::to_string_pretty(&array).unwrap());
209 panic!("Don't leave this test enabled. Meanwhile, enjoy the text output above.");
210 }
211