• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #![allow(clippy::indexing_slicing, clippy::unwrap_used, clippy::panic, clippy::expect_used)]
15 
16 extern crate alloc;
17 
18 use crate::{
19     build_np_adv_decrypter_from_key_seed, salt_padder, AuthenticatedNpLdtDecryptCipher,
20     LdtAdvDecryptError, NpLdtDecryptCipher, NpLdtEncryptCipher, V0IdentityToken, V0Salt,
21     LDT_XTS_AES_MAX_LEN, V0_IDENTITY_TOKEN_LEN,
22 };
23 use alloc::vec::Vec;
24 use crypto_provider::{CryptoProvider, CryptoRng};
25 use crypto_provider_default::CryptoProviderImpl;
26 use ldt::{DefaultPadder, LdtCipher, LdtError, LdtKey, XorPadder};
27 use np_hkdf::NpKeySeedHkdf;
28 use rand::Rng;
29 use rand_ext::{random_bytes, random_vec, seeded_rng};
30 
31 extern crate std;
32 
33 use crypto_provider::aes::BLOCK_SIZE;
34 use std::vec;
35 
36 #[test]
decrypt_matches_correct_ciphertext()37 fn decrypt_matches_correct_ciphertext() {
38     let mut rng = CryptoRng::new();
39     for _ in 0..1_000 {
40         let test_state = make_test_components::<CryptoProviderImpl>(&mut rng);
41 
42         let cipher = build_np_adv_decrypter_from_key_seed(&test_state.hkdf, test_state.hmac);
43         let (token, plaintext) =
44             cipher.decrypt_and_verify(&test_state.ciphertext, &test_state.padder).unwrap();
45 
46         assert_eq!(test_state.identity_token, token);
47         assert_eq!(&test_state.remaining_plaintext, plaintext.as_ref());
48     }
49 }
50 
51 #[test]
decrypt_doesnt_match_when_ciphertext_mangled()52 fn decrypt_doesnt_match_when_ciphertext_mangled() {
53     let mut rng = CryptoRng::new();
54     for _ in 0..1_000 {
55         let mut test_state = make_test_components::<CryptoProviderImpl>(&mut rng);
56 
57         // mangle the ciphertext
58         test_state.ciphertext[0] ^= 0xAA;
59 
60         let cipher = build_np_adv_decrypter_from_key_seed(&test_state.hkdf, test_state.hmac);
61         assert_eq!(
62             Err(LdtAdvDecryptError::MacMismatch),
63             cipher.decrypt_and_verify(&test_state.ciphertext, &test_state.padder)
64         );
65     }
66 }
67 
68 #[test]
decrypt_doesnt_match_when_plaintext_doesnt_match_mac()69 fn decrypt_doesnt_match_when_plaintext_doesnt_match_mac() {
70     let mut rng = CryptoRng::new();
71     for _ in 0..1_000 {
72         let mut test_state = make_test_components::<CryptoProviderImpl>(&mut rng);
73 
74         // mangle the mac
75         test_state.hmac[0] ^= 0xAA;
76 
77         let cipher = build_np_adv_decrypter_from_key_seed(&test_state.hkdf, test_state.hmac);
78         assert_eq!(
79             Err(LdtAdvDecryptError::MacMismatch),
80             cipher.decrypt_and_verify(&test_state.ciphertext, &test_state.padder)
81         );
82     }
83 }
84 
85 #[test]
86 #[allow(deprecated)]
encrypt_works()87 fn encrypt_works() {
88     let mut rng = CryptoRng::new();
89     for _ in 0..1_000 {
90         let test_state = make_test_components::<CryptoProviderImpl>(&mut rng);
91 
92         let cipher = test_state.ldt_enc;
93 
94         let mut plaintext_copy = test_state.all_plaintext.clone();
95         cipher.encrypt(&mut plaintext_copy[..], &test_state.padder).unwrap();
96 
97         assert_eq!(test_state.ciphertext, plaintext_copy);
98     }
99 }
100 
101 #[test]
102 #[allow(deprecated)]
encrypt_too_short_err()103 fn encrypt_too_short_err() {
104     let ldt_enc =
105         NpLdtEncryptCipher::<CryptoProviderImpl>::new(&LdtKey::from_concatenated(&[0; 64]));
106 
107     let mut payload = vec![0; BLOCK_SIZE - 1];
108     assert_eq!(
109         Err(LdtError::InvalidLength(BLOCK_SIZE - 1)),
110         ldt_enc.encrypt(&mut payload, &DefaultPadder)
111     );
112 }
113 
114 #[test]
115 #[allow(deprecated)]
encrypt_too_long_err()116 fn encrypt_too_long_err() {
117     let ldt_enc =
118         NpLdtEncryptCipher::<CryptoProviderImpl>::new(&LdtKey::from_concatenated(&[0; 64]));
119 
120     let mut payload = vec![0; BLOCK_SIZE * 2];
121     assert_eq!(
122         Err(LdtError::InvalidLength(BLOCK_SIZE * 2)),
123         ldt_enc.encrypt(&mut payload, &DefaultPadder)
124     );
125 }
126 
127 #[test]
decrypt_too_short_err()128 fn decrypt_too_short_err() {
129     let adv_cipher: AuthenticatedNpLdtDecryptCipher<CryptoProviderImpl> =
130         AuthenticatedNpLdtDecryptCipher {
131             ldt_decrypter: NpLdtDecryptCipher::<CryptoProviderImpl>::new(
132                 &LdtKey::from_concatenated(&[0; 64]),
133             ),
134             metadata_key_tag: [0; 32],
135             metadata_key_hmac_key: np_hkdf::NpHmacSha256Key::from([0; 32]),
136         };
137 
138     // 1 byte less than a full block
139     let payload = vec![0; BLOCK_SIZE - 1];
140     assert_eq!(
141         Err(LdtAdvDecryptError::InvalidLength(BLOCK_SIZE - 1)),
142         adv_cipher.decrypt_and_verify(&payload, &XorPadder::from([0_u8; BLOCK_SIZE]))
143     );
144 }
145 
146 #[test]
decrypt_too_long_err()147 fn decrypt_too_long_err() {
148     let adv_cipher: AuthenticatedNpLdtDecryptCipher<CryptoProviderImpl> =
149         AuthenticatedNpLdtDecryptCipher {
150             ldt_decrypter: NpLdtDecryptCipher::<CryptoProviderImpl>::new(
151                 &LdtKey::from_concatenated(&[0; 64]),
152             ),
153             metadata_key_tag: [0; 32],
154             metadata_key_hmac_key: np_hkdf::NpHmacSha256Key::from([0; 32]),
155         };
156 
157     // 2 full blocks
158     let payload = [0; BLOCK_SIZE * 2];
159     assert_eq!(
160         Err(LdtAdvDecryptError::InvalidLength(BLOCK_SIZE * 2)),
161         adv_cipher.decrypt_and_verify(&payload, &XorPadder::from([0; BLOCK_SIZE]))
162     );
163 }
164 
165 #[test]
verify_input_len_const()166 fn verify_input_len_const() {
167     // make sure it matches the authoritative upstream
168     assert_eq!(crate::VALID_INPUT_LEN, NpLdtEncryptCipher::<CryptoProviderImpl>::VALID_INPUT_LEN);
169 }
170 
171 #[test]
ldt_ffi_test_scenario()172 fn ldt_ffi_test_scenario() {
173     // used in ldt_ffi_tests.cc and LdtNpJniTests
174     let key_seed: [u8; 32] = [
175         204, 219, 36, 137, 233, 252, 172, 66, 179, 147, 72, 184, 148, 30, 209, 154, 29, 54, 14,
176         117, 224, 152, 200, 193, 94, 107, 28, 194, 182, 32, 205, 57,
177     ];
178 
179     let salt: V0Salt = [12, 15].into();
180     let plaintext = [
181         205_u8, 104, 63, 225, 161, 209, 248, 70, 84, 61, 10, 19, 212, 174, 164, 0, 64, 200, 214,
182         123,
183     ];
184 
185     let hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed);
186     let ldt_key = hkdf.v0_ldt_key();
187     let identity_token_hmac = hkdf
188         .v0_identity_token_hmac_key()
189         .calculate_hmac::<CryptoProviderImpl>(&plaintext[..V0_IDENTITY_TOKEN_LEN]);
190     let decrypter = build_np_adv_decrypter_from_key_seed(&hkdf, identity_token_hmac);
191 
192     let padder = salt_padder::<CryptoProviderImpl>(salt);
193     let mut ciphertext = plaintext;
194     NpLdtEncryptCipher::<CryptoProviderImpl>::new(&ldt_key)
195         .encrypt(&mut ciphertext, &padder)
196         .unwrap();
197 
198     let (token, contents) = decrypter.decrypt_and_verify(&ciphertext, &padder).unwrap();
199     assert_eq!(&plaintext[..V0_IDENTITY_TOKEN_LEN], token.as_slice());
200     assert_eq!(&plaintext[V0_IDENTITY_TOKEN_LEN..], contents.as_slice());
201 
202     // Uncomment if updating the FFI test
203     // {
204     //     use std::println;
205     //     use test_helper::hex_bytes;
206     //     println!("Key seed:\n{}\n{}", hex_bytes(&key_seed), hex::encode_upper(&key_seed));
207     //     println!("Identity token HMAC:\n{}\n{}", hex_bytes(&identity_token_hmac), hex::encode_upper(&identity_token_hmac));
208     //     println!("Plaintext:\n{}\n{}", hex_bytes(&plaintext), hex::encode_upper(&plaintext));
209     //     println!("Salt:\n{}\n{}", hex_bytes(salt.bytes()), hex::encode_upper(salt.bytes()));
210     //     println!("Ciphertext:\n{}\n{}", hex_bytes(&ciphertext), hex::encode_upper(&ciphertext));
211     //     panic!();
212     // }
213 }
214 
215 /// Returns (plaintext, ciphertext, padder, hmac key, MAC, ldt)
make_test_components<C: crypto_provider::CryptoProvider>( rng: &mut C::CryptoRng, ) -> LdtAdvTestComponents<C>216 fn make_test_components<C: crypto_provider::CryptoProvider>(
217     rng: &mut C::CryptoRng,
218 ) -> LdtAdvTestComponents<C> {
219     // [1, 2) blocks of XTS-AES
220     let mut rc_rng = seeded_rng();
221     let payload_len = rc_rng.gen_range(BLOCK_SIZE..=(BLOCK_SIZE * 2 - 1));
222     let all_plaintext = random_vec::<C>(rng, payload_len);
223 
224     let salt = V0Salt { bytes: random_bytes::<2, C>(rng) };
225     let padder = salt_padder::<C>(salt);
226 
227     let key_seed: [u8; 32] = random_bytes::<32, C>(rng);
228     let hkdf = np_hkdf::NpKeySeedHkdf::new(&key_seed);
229     let ldt_key = hkdf.v0_ldt_key();
230     let hmac_key = hkdf.v0_identity_token_hmac_key();
231     let identity_token: [u8; V0_IDENTITY_TOKEN_LEN] =
232         all_plaintext[..V0_IDENTITY_TOKEN_LEN].try_into().unwrap();
233     let hmac: [u8; 32] = hmac_key.calculate_hmac::<C>(&identity_token);
234 
235     let ldt_enc = NpLdtEncryptCipher::<C>::new(&ldt_key);
236 
237     let mut ciphertext = [0_u8; LDT_XTS_AES_MAX_LEN];
238     ciphertext[..all_plaintext.len()].copy_from_slice(&all_plaintext);
239     ldt_enc.encrypt(&mut ciphertext[..all_plaintext.len()], &padder).unwrap();
240     let remaining_plaintext = all_plaintext[V0_IDENTITY_TOKEN_LEN..].to_vec();
241     LdtAdvTestComponents {
242         all_plaintext,
243         identity_token: identity_token.into(),
244         remaining_plaintext,
245         ciphertext: ciphertext[..payload_len].to_vec(),
246         padder,
247         hmac,
248         ldt_enc,
249         hkdf,
250     }
251 }
252 
253 struct LdtAdvTestComponents<C: CryptoProvider> {
254     all_plaintext: Vec<u8>,
255     identity_token: V0IdentityToken,
256     /// Plaintext after the identity token
257     remaining_plaintext: Vec<u8>,
258     ciphertext: Vec<u8>,
259     padder: XorPadder<{ BLOCK_SIZE }>,
260     hmac: [u8; 32],
261     ldt_enc: NpLdtEncryptCipher<C>,
262     hkdf: NpKeySeedHkdf<C>,
263 }
264 
265 mod coverage_gaming {
266     extern crate std;
267 
268     use crate::{V0IdentityToken, V0_IDENTITY_TOKEN_LEN};
269     use crypto_provider::{CryptoProvider, CryptoRng};
270     use crypto_provider_default::CryptoProviderImpl;
271     use std::{collections, format};
272 
273     #[test]
legacy_identity_token()274     fn legacy_identity_token() {
275         let token = V0IdentityToken::from([0; V0_IDENTITY_TOKEN_LEN]);
276         // debug
277         let _ = format!("{:?}", token);
278         // hash
279         let _ = collections::HashSet::new().insert(&token);
280         // bytes
281         assert_eq!(token.0, token.bytes());
282         // AsRef
283         assert_eq!(token.0.as_slice(), token.as_ref());
284         // FromCryptoRng
285         let mut rng = <CryptoProviderImpl as CryptoProvider>::CryptoRng::new();
286         let _: V0IdentityToken = rng.gen();
287     }
288 }
289