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 //! Salt used in a V1 advertisement. 16 use crate::np_salt_hkdf; 17 use crypto_provider::{hkdf::Hkdf, CryptoProvider, CryptoRng, FromCryptoRng}; 18 19 /// Length of a V1 extended salt 20 pub const EXTENDED_SALT_LEN: usize = 16; 21 22 /// Salt optionally included in V1 advertisement header. 23 /// 24 /// The salt is never used directly; rather, a derived salt should be extracted as needed for any 25 /// section or DE that requires it. 26 #[derive(Clone, Copy, PartialEq, Debug, Eq)] 27 pub struct ExtendedV1Salt { 28 data: [u8; EXTENDED_SALT_LEN], 29 } 30 31 impl ExtendedV1Salt { 32 /// Derive a salt for a particular DE, if applicable. 33 /// 34 /// Returns none if the requested size is larger than HKDF allows or if offset arithmetic 35 /// overflows. derive<const N: usize, C: CryptoProvider>( &self, de: Option<DataElementOffset>, ) -> Option<[u8; N]>36 pub fn derive<const N: usize, C: CryptoProvider>( 37 &self, 38 de: Option<DataElementOffset>, 39 ) -> Option<[u8; N]> { 40 let hkdf = np_salt_hkdf::<C>(&self.data); 41 let mut arr = [0_u8; N]; 42 // 0-based offsets -> 1-based indices w/ 0 indicating not present 43 hkdf.expand_multi_info( 44 &[ 45 b"V1 derived salt", 46 &de.and_then(|d| d.offset.checked_add(1)) 47 .map(|o| o.into()) 48 .unwrap_or(0_u32) 49 .to_be_bytes(), 50 ], 51 &mut arr, 52 ) 53 .map(|_| arr) 54 .ok() 55 } 56 57 /// Returns the salt bytes as a slice as_slice(&self) -> &[u8]58 pub fn as_slice(&self) -> &[u8] { 59 self.data.as_slice() 60 } 61 62 /// Returns the salt bytes as an array into_array(self) -> [u8; EXTENDED_SALT_LEN]63 pub fn into_array(self) -> [u8; EXTENDED_SALT_LEN] { 64 self.data 65 } 66 67 /// Returns the salt bytes as a reference to an array bytes(&self) -> &[u8; EXTENDED_SALT_LEN]68 pub fn bytes(&self) -> &[u8; EXTENDED_SALT_LEN] { 69 &self.data 70 } 71 } 72 73 impl From<[u8; EXTENDED_SALT_LEN]> for ExtendedV1Salt { from(arr: [u8; EXTENDED_SALT_LEN]) -> Self74 fn from(arr: [u8; EXTENDED_SALT_LEN]) -> Self { 75 Self { data: arr } 76 } 77 } 78 79 impl FromCryptoRng for ExtendedV1Salt { new_random<R: CryptoRng>(rng: &mut R) -> Self80 fn new_random<R: CryptoRng>(rng: &mut R) -> Self { 81 rng.gen::<[u8; EXTENDED_SALT_LEN]>().into() 82 } 83 } 84 85 /// Offset of a data element in its containing section, used with [ExtendedV1Salt]. 86 #[derive(PartialEq, Eq, Debug, Clone, Copy, PartialOrd, Ord)] 87 pub struct DataElementOffset { 88 /// 0-based offset of the DE in the advertisement 89 offset: u8, 90 } 91 92 impl DataElementOffset { 93 /// The zero offset 94 pub const ZERO: DataElementOffset = Self { offset: 0 }; 95 96 /// Returns the offset as a usize as_u8(&self) -> u897 pub fn as_u8(&self) -> u8 { 98 self.offset 99 } 100 101 /// Returns the next offset. 102 /// 103 /// Does not handle overflow as there can't be more than 2^8 DEs in a section. incremented(&self) -> Self104 pub const fn incremented(&self) -> Self { 105 Self { offset: self.offset + 1 } 106 } 107 } 108 109 impl From<u8> for DataElementOffset { from(num: u8) -> Self110 fn from(num: u8) -> Self { 111 Self { offset: num } 112 } 113 } 114