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 §ion_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(§ion_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