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 use crate::credential::v1::V1BroadcastCredential;
16 use crate::extended::salt::{MultiSalt, ShortV1Salt, V1Salt};
17 use crate::header::VERSION_HEADER_V1;
18 use crate::{
19     extended::{
20         deserialize::SectionMic,
21         section_signature_payload::SectionSignaturePayload,
22         serialize::{section::header::SectionHeader, AdvertisementType, DeSalt},
23         V1IdentityToken, V1_IDENTITY_TOKEN_LEN,
24     },
25     NP_SVC_UUID,
26 };
27 use crypto_provider::{
28     aes,
29     aes::ctr::{AesCtr as _, AesCtrNonce, NonceAndCounter},
30     ed25519,
31     hmac::Hmac,
32     CryptoProvider, CryptoRng as _,
33 };
34 use np_hkdf::v1_salt::EXTENDED_SALT_LEN;
35 use np_hkdf::{
36     v1_salt::{DataElementOffset, ExtendedV1Salt},
37     DerivedSectionKeys,
38 };
39 
40 /// Everything needed to properly encode a section
41 pub trait SectionEncoder {
42     /// How much space needs to be reserved after the DEs
43     const SUFFIX_LEN: usize;
44 
45     /// The advertisement type that can support this section
46     const ADVERTISEMENT_TYPE: AdvertisementType;
47 
48     /// The type of derived salt produced for a DE sharing a section with this identity.
49     type DerivedSalt;
50 
51     /// Header to write at the start of the section contents
header(&self) -> SectionHeader52     fn header(&self) -> SectionHeader;
53 
54     /// Postprocess the contents of the section (the data after the section header byte), which will
55     /// start with the contents of [Self::header()], and similarly end with
56     /// [Self::SUFFIX_LEN] bytes, with DEs (if any) in the middle.
57     ///
58     /// `section_header_without_length` is the bytes of the section header up until but not
59     /// including the length byte
60     /// `section_len` is the length of the contents that come after the length byte which includes
61     /// the de contents + the suffix. This is the length of `remaining_content_bytes` stored as an u8
62     /// `remaining_content_bytes` are the bytes of the rest of the contents that come after section length
postprocess<C: CryptoProvider>( &mut self, section_header_without_length: &mut [u8], section_len: u8, remaining_content_bytes: &mut [u8], )63     fn postprocess<C: CryptoProvider>(
64         &mut self,
65         section_header_without_length: &mut [u8],
66         section_len: u8,
67         remaining_content_bytes: &mut [u8],
68     );
69 
70     /// Produce a `Self::Output` salt for a DE.
de_salt(&self, de_offset: DataElementOffset) -> Self::DerivedSalt71     fn de_salt(&self, de_offset: DataElementOffset) -> Self::DerivedSalt;
72 }
73 
74 /// Encoder for plaintext data elements
75 #[derive(Debug)]
76 pub struct UnencryptedSectionEncoder;
77 
78 impl UnencryptedSectionEncoder {}
79 
80 impl SectionEncoder for UnencryptedSectionEncoder {
81     const SUFFIX_LEN: usize = 0;
82     const ADVERTISEMENT_TYPE: AdvertisementType = AdvertisementType::Plaintext;
83 
84     type DerivedSalt = ();
85 
header(&self) -> SectionHeader86     fn header(&self) -> SectionHeader {
87         SectionHeader::unencrypted()
88     }
postprocess<C: CryptoProvider>( &mut self, _section_header_without_length: &mut [u8], _section_len: u8, _remaining_content_bytes: &mut [u8], )89     fn postprocess<C: CryptoProvider>(
90         &mut self,
91         _section_header_without_length: &mut [u8],
92         _section_len: u8,
93         _remaining_content_bytes: &mut [u8],
94     ) {
95         // no op
96     }
97 
de_salt(&self, _de_offset: DataElementOffset) -> Self::DerivedSalt98     fn de_salt(&self, _de_offset: DataElementOffset) -> Self::DerivedSalt {}
99 }
100 
101 /// Encrypts the data elements and protects integrity with an np_ed25519 signature
102 /// using key material derived from an NP identity.
103 pub struct SignedEncryptedSectionEncoder {
104     pub(crate) salt: ExtendedV1Salt,
105     identity_token: V1IdentityToken,
106     private_key: ed25519::PrivateKey,
107     aes_key: aes::Aes128Key,
108 }
109 
110 impl SignedEncryptedSectionEncoder {
111     /// Build a [SignedEncryptedSectionEncoder] from an identity type,
112     /// some broadcast crypto-material, and with a random salt.
new_random_salt<C: CryptoProvider>( rng: &mut C::CryptoRng, crypto_material: &V1BroadcastCredential, ) -> Self113     pub fn new_random_salt<C: CryptoProvider>(
114         rng: &mut C::CryptoRng,
115         crypto_material: &V1BroadcastCredential,
116     ) -> Self {
117         let salt: ExtendedV1Salt = rng.gen::<[u8; 16]>().into();
118         Self::new::<C>(salt, crypto_material)
119     }
120 
121     /// Build a [SignedEncryptedSectionEncoder] from an identity type,
122     /// a provided salt, and some broadcast crypto-material.
new<C: CryptoProvider>( salt: ExtendedV1Salt, crypto_material: &V1BroadcastCredential, ) -> Self123     pub(crate) fn new<C: CryptoProvider>(
124         salt: ExtendedV1Salt,
125         crypto_material: &V1BroadcastCredential,
126     ) -> Self {
127         let identity_token = crypto_material.identity_token();
128         let key_seed = crypto_material.key_seed();
129         let key_seed_hkdf = np_hkdf::NpKeySeedHkdf::<C>::new(&key_seed);
130         let private_key = crypto_material.signing_key();
131         let aes_key = key_seed_hkdf.v1_signature_keys().aes_key();
132         Self { salt, identity_token, private_key, aes_key }
133     }
134 }
135 
136 impl SectionEncoder for SignedEncryptedSectionEncoder {
137     /// Ed25519 signature
138     const SUFFIX_LEN: usize = crypto_provider::ed25519::SIGNATURE_LENGTH;
139     const ADVERTISEMENT_TYPE: AdvertisementType = AdvertisementType::Encrypted;
140 
141     type DerivedSalt = DeSalt;
142 
header(&self) -> SectionHeader143     fn header(&self) -> SectionHeader {
144         SectionHeader::encrypted_signature_extended_salt(&self.salt, &self.identity_token)
145     }
146 
postprocess<C: CryptoProvider>( &mut self, section_header_without_length: &mut [u8], section_len: u8, remaining_contents: &mut [u8], )147     fn postprocess<C: CryptoProvider>(
148         &mut self,
149         section_header_without_length: &mut [u8],
150         section_len: u8,
151         remaining_contents: &mut [u8],
152     ) {
153         let nonce: AesCtrNonce = self.salt.compute_nonce::<C>();
154         let mut cipher = C::AesCtr128::new(&self.aes_key, NonceAndCounter::from_nonce(nonce));
155 
156         let start_of_identity_token = section_header_without_length.len() - V1_IDENTITY_TOKEN_LEN;
157         let (format_and_salt_bytes, identity_token) =
158             section_header_without_length.split_at_mut(start_of_identity_token);
159         debug_assert!(identity_token.len() == V1_IDENTITY_TOKEN_LEN);
160 
161         let start_of_salt = format_and_salt_bytes.len() - EXTENDED_SALT_LEN;
162         let (format_bytes, salt_bytes) = format_and_salt_bytes.split_at_mut(start_of_salt);
163         debug_assert!(salt_bytes.len() == EXTENDED_SALT_LEN);
164         debug_assert!((1..=2).contains(&format_bytes.len()));
165 
166         let start_of_signature = remaining_contents.len() - Self::SUFFIX_LEN;
167         let (plaintext_data_elements, sig) = remaining_contents.split_at_mut(start_of_signature);
168         debug_assert!(sig.len() == Self::SUFFIX_LEN);
169 
170         let section_signature_payload = SectionSignaturePayload::new(
171             format_bytes,
172             salt_bytes,
173             &nonce,
174             identity_token,
175             section_len,
176             plaintext_data_elements,
177         );
178 
179         sig.copy_from_slice(
180             &section_signature_payload.sign::<C::Ed25519>(&self.private_key).to_bytes(),
181         );
182 
183         cipher.apply_keystream(identity_token);
184         cipher.apply_keystream(plaintext_data_elements);
185         cipher.apply_keystream(sig);
186     }
187 
de_salt(&self, de_offset: DataElementOffset) -> Self::DerivedSalt188     fn de_salt(&self, de_offset: DataElementOffset) -> Self::DerivedSalt {
189         DeSalt { salt: self.salt, de_offset }
190     }
191 }
192 
193 /// Encrypts the data elements and protects integrity with a MIC using key material derived from
194 /// an NP identity.
195 pub struct MicEncryptedSectionEncoder<S> {
196     pub(crate) salt: S,
197     identity_token: V1IdentityToken,
198     aes_key: aes::Aes128Key,
199     mic_hmac_key: np_hkdf::NpHmacSha256Key,
200 }
201 
202 impl<S: MicSectionEncoderSalt> MicEncryptedSectionEncoder<S> {
203     /// Build a [MicEncryptedSectionEncoder] from the provided identity info.
new<C: CryptoProvider>( salt: S, broadcast_credential: &V1BroadcastCredential, ) -> Self204     pub(crate) fn new<C: CryptoProvider>(
205         salt: S,
206         broadcast_credential: &V1BroadcastCredential,
207     ) -> Self {
208         let identity_token = broadcast_credential.identity_token();
209         let key_seed = broadcast_credential.key_seed();
210         let key_seed_hkdf = np_hkdf::NpKeySeedHkdf::<C>::new(&key_seed);
211         let aes_key = salt.derive_aes_key(&key_seed_hkdf);
212         let mic_hmac_key = salt.derive_mic_hmac_key(&key_seed_hkdf);
213 
214         Self { salt, identity_token, aes_key, mic_hmac_key }
215     }
216 
217     /// Build a [MicEncryptedSectionEncoder] from the provided identity info.
218     /// Exposed outside of this crate for testing purposes only, since this
219     /// does not handle the generation of random salts.
220     #[cfg(any(test, feature = "testing", feature = "devtools"))]
new_with_salt<C: CryptoProvider>( salt: S, broadcast_credential: &V1BroadcastCredential, ) -> Self221     pub fn new_with_salt<C: CryptoProvider>(
222         salt: S,
223         broadcast_credential: &V1BroadcastCredential,
224     ) -> Self {
225         Self::new::<C>(salt, broadcast_credential)
226     }
227 }
228 
229 impl MicEncryptedSectionEncoder<ExtendedV1Salt> {
230     /// Build a [MicEncryptedSectionEncoder] from the provided identity
231     /// info with a random extended salt.
new_random_salt<C: CryptoProvider>( rng: &mut C::CryptoRng, broadcast_credential: &V1BroadcastCredential, ) -> Self232     pub fn new_random_salt<C: CryptoProvider>(
233         rng: &mut C::CryptoRng,
234         broadcast_credential: &V1BroadcastCredential,
235     ) -> Self {
236         Self::new::<C>(rng.gen(), broadcast_credential)
237     }
238 }
239 
240 impl MicEncryptedSectionEncoder<MultiSalt> {
241     /// Build a [MicEncryptedSectionEncoder] from the provided identity
242     /// info with a random extended salt wrapped in [MultiSalt].
243     ///
244     /// Prefer [Self::new_random_salt] unless there is a need for the type
245     /// parameter to be [MultiSalt].
new_wrapped_salt<C: CryptoProvider>( rng: &mut C::CryptoRng, broadcast_credential: &V1BroadcastCredential, ) -> Self246     pub fn new_wrapped_salt<C: CryptoProvider>(
247         rng: &mut C::CryptoRng,
248         broadcast_credential: &V1BroadcastCredential,
249     ) -> Self {
250         Self::new::<C>(rng.gen::<ExtendedV1Salt>().into(), broadcast_credential)
251     }
252 }
253 
254 impl<S: MicSectionEncoderSalt> SectionEncoder for MicEncryptedSectionEncoder<S> {
255     /// Length of mic
256     const SUFFIX_LEN: usize = SectionMic::CONTENTS_LEN;
257 
258     const ADVERTISEMENT_TYPE: AdvertisementType = AdvertisementType::Encrypted;
259 
260     type DerivedSalt = S::DerivedSalt;
261 
header(&self) -> SectionHeader262     fn header(&self) -> SectionHeader {
263         self.salt.header(&self.identity_token)
264     }
265 
postprocess<C: CryptoProvider>( &mut self, section_header_without_length: &mut [u8], section_len: u8, remaining_contents: &mut [u8], )266     fn postprocess<C: CryptoProvider>(
267         &mut self,
268         section_header_without_length: &mut [u8],
269         section_len: u8,
270         remaining_contents: &mut [u8],
271     ) {
272         let nonce: AesCtrNonce = self.salt.compute_nonce::<C>();
273         let mut cipher = C::AesCtr128::new(&self.aes_key, NonceAndCounter::from_nonce(nonce));
274 
275         let start_of_identity_token = section_header_without_length.len() - V1_IDENTITY_TOKEN_LEN;
276         let (format_and_salt_bytes, identity_token) =
277             section_header_without_length.split_at_mut(start_of_identity_token);
278         debug_assert!(identity_token.len() == V1_IDENTITY_TOKEN_LEN);
279         // format can be 1-2 bytes
280         debug_assert!((1 + self.salt.into().as_slice().len()
281             ..=2 + self.salt.into().as_slice().len())
282             .contains(&format_and_salt_bytes.len()));
283 
284         let start_of_mic = remaining_contents.len() - Self::SUFFIX_LEN;
285         let (data_element_contents, mic) = remaining_contents.split_at_mut(start_of_mic);
286         debug_assert!(mic.len() == Self::SUFFIX_LEN);
287 
288         // First encrypt the identity token
289         cipher.apply_keystream(identity_token);
290 
291         // Now encrypt the rest of the ciphertext bytes that come after the section length byte
292         cipher.apply_keystream(data_element_contents);
293 
294         // calculate MAC per the spec
295         let mut section_hmac = self.mic_hmac_key.build_hmac::<C>();
296         // svc uuid
297         section_hmac.update(NP_SVC_UUID.as_slice());
298         // adv header
299         section_hmac.update(&[VERSION_HEADER_V1]);
300         // section format and salt
301         section_hmac.update(format_and_salt_bytes);
302         // nonce
303         section_hmac.update(&nonce);
304         // encrypted identity token
305         section_hmac.update(identity_token);
306         // section len
307         section_hmac.update(&[section_len]);
308         // rest of the ciphertext
309         section_hmac.update(data_element_contents);
310 
311         // write truncated MIC
312         mic.copy_from_slice(&section_hmac.finalize()[..SectionMic::CONTENTS_LEN]);
313     }
314 
de_salt(&self, de_offset: DataElementOffset) -> Self::DerivedSalt315     fn de_salt(&self, de_offset: DataElementOffset) -> Self::DerivedSalt {
316         self.salt.derive_de_salt(de_offset)
317     }
318 }
319 
320 /// Behavior for salts used with MIC sections.
321 pub trait MicSectionEncoderSalt: V1Salt {
322     /// The type of derived data produced, or `()` if no data can be derived.
323     type DerivedSalt;
324 
325     /// Build the appropriate header for the type of salt used
header(&self, identity_token: &V1IdentityToken) -> SectionHeader326     fn header(&self, identity_token: &V1IdentityToken) -> SectionHeader;
327 
328     /// Derive a DE salt at the specified offset.
derive_de_salt(&self, de_offset: DataElementOffset) -> Self::DerivedSalt329     fn derive_de_salt(&self, de_offset: DataElementOffset) -> Self::DerivedSalt;
330 
331     /// Derive the AES key  suitable for this salt type
derive_aes_key<C: CryptoProvider>(&self, hkdf: &np_hkdf::NpKeySeedHkdf<C>) -> aes::Aes128Key332     fn derive_aes_key<C: CryptoProvider>(&self, hkdf: &np_hkdf::NpKeySeedHkdf<C>)
333         -> aes::Aes128Key;
334 
335     /// Derive the MIC HMAC key suitable for this salt type
derive_mic_hmac_key<C: CryptoProvider>( &self, hkdf: &np_hkdf::NpKeySeedHkdf<C>, ) -> np_hkdf::NpHmacSha256Key336     fn derive_mic_hmac_key<C: CryptoProvider>(
337         &self,
338         hkdf: &np_hkdf::NpKeySeedHkdf<C>,
339     ) -> np_hkdf::NpHmacSha256Key;
340 }
341 
342 impl MicSectionEncoderSalt for ExtendedV1Salt {
343     type DerivedSalt = DeSalt;
344 
header(&self, identity_token: &V1IdentityToken) -> SectionHeader345     fn header(&self, identity_token: &V1IdentityToken) -> SectionHeader {
346         SectionHeader::encrypted_mic_extended_salt(self, identity_token)
347     }
348 
derive_de_salt(&self, de_offset: DataElementOffset) -> Self::DerivedSalt349     fn derive_de_salt(&self, de_offset: DataElementOffset) -> Self::DerivedSalt {
350         DeSalt { salt: *self, de_offset }
351     }
352 
derive_aes_key<C: CryptoProvider>( &self, hkdf: &np_hkdf::NpKeySeedHkdf<C>, ) -> aes::Aes128Key353     fn derive_aes_key<C: CryptoProvider>(
354         &self,
355         hkdf: &np_hkdf::NpKeySeedHkdf<C>,
356     ) -> aes::Aes128Key {
357         hkdf.v1_mic_extended_salt_keys().aes_key()
358     }
359 
derive_mic_hmac_key<C: CryptoProvider>( &self, hkdf: &np_hkdf::NpKeySeedHkdf<C>, ) -> np_hkdf::NpHmacSha256Key360     fn derive_mic_hmac_key<C: CryptoProvider>(
361         &self,
362         hkdf: &np_hkdf::NpKeySeedHkdf<C>,
363     ) -> np_hkdf::NpHmacSha256Key {
364         hkdf.v1_mic_extended_salt_keys().mic_hmac_key()
365     }
366 }
367 
368 // TODO is this impl used?
369 impl MicSectionEncoderSalt for ShortV1Salt {
370     type DerivedSalt = ();
371 
header(&self, identity_token: &V1IdentityToken) -> SectionHeader372     fn header(&self, identity_token: &V1IdentityToken) -> SectionHeader {
373         SectionHeader::encrypted_mic_short_salt(*self, identity_token)
374     }
375 
derive_de_salt(&self, _de_offset: DataElementOffset) -> Self::DerivedSalt376     fn derive_de_salt(&self, _de_offset: DataElementOffset) -> Self::DerivedSalt {}
377 
derive_aes_key<C: CryptoProvider>( &self, hkdf: &np_hkdf::NpKeySeedHkdf<C>, ) -> aes::Aes128Key378     fn derive_aes_key<C: CryptoProvider>(
379         &self,
380         hkdf: &np_hkdf::NpKeySeedHkdf<C>,
381     ) -> aes::Aes128Key {
382         hkdf.v1_mic_short_salt_keys().aes_key()
383     }
384 
derive_mic_hmac_key<C: CryptoProvider>( &self, hkdf: &np_hkdf::NpKeySeedHkdf<C>, ) -> np_hkdf::NpHmacSha256Key385     fn derive_mic_hmac_key<C: CryptoProvider>(
386         &self,
387         hkdf: &np_hkdf::NpKeySeedHkdf<C>,
388     ) -> np_hkdf::NpHmacSha256Key {
389         hkdf.v1_mic_short_salt_keys().mic_hmac_key()
390     }
391 }
392 
393 impl MicSectionEncoderSalt for MultiSalt {
394     type DerivedSalt = Option<DeSalt>;
395 
header(&self, identity_token: &V1IdentityToken) -> SectionHeader396     fn header(&self, identity_token: &V1IdentityToken) -> SectionHeader {
397         match self {
398             MultiSalt::Short(s) => SectionHeader::encrypted_mic_short_salt(*s, identity_token),
399             MultiSalt::Extended(s) => SectionHeader::encrypted_mic_extended_salt(s, identity_token),
400         }
401     }
402 
derive_de_salt(&self, de_offset: DataElementOffset) -> Self::DerivedSalt403     fn derive_de_salt(&self, de_offset: DataElementOffset) -> Self::DerivedSalt {
404         match self {
405             MultiSalt::Short(_) => None,
406             MultiSalt::Extended(s) => Some(DeSalt { salt: *s, de_offset }),
407         }
408     }
409 
derive_aes_key<C: CryptoProvider>( &self, hkdf: &np_hkdf::NpKeySeedHkdf<C>, ) -> aes::Aes128Key410     fn derive_aes_key<C: CryptoProvider>(
411         &self,
412         hkdf: &np_hkdf::NpKeySeedHkdf<C>,
413     ) -> aes::Aes128Key {
414         match self {
415             MultiSalt::Short(_) => hkdf.v1_mic_short_salt_keys().aes_key(),
416             MultiSalt::Extended(_) => hkdf.v1_mic_extended_salt_keys().aes_key(),
417         }
418     }
419 
derive_mic_hmac_key<C: CryptoProvider>( &self, hkdf: &np_hkdf::NpKeySeedHkdf<C>, ) -> np_hkdf::NpHmacSha256Key420     fn derive_mic_hmac_key<C: CryptoProvider>(
421         &self,
422         hkdf: &np_hkdf::NpKeySeedHkdf<C>,
423     ) -> np_hkdf::NpHmacSha256Key {
424         match self {
425             MultiSalt::Short(_) => hkdf.v1_mic_short_salt_keys().mic_hmac_key(),
426             MultiSalt::Extended(_) => hkdf.v1_mic_extended_salt_keys().mic_hmac_key(),
427         }
428     }
429 }
430