blob: ae327db1bece9d7ad28ee76caf65fb6e0a67e4f6 [file] [log] [blame]
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Salt used in a V1 advertisement.
use crate::np_salt_hkdf;
use core::fmt;
use crypto_provider::hkdf::Hkdf;
use crypto_provider::CryptoProvider;
/// Salt optionally included in V1 advertisement header.
///
/// The salt is never used directly; rather, a derived salt should be extracted as needed for any
/// section or DE that requires it.
#[derive(Clone)]
pub struct V1Salt<C>
where
C: CryptoProvider,
{
// kept around for Eq and Debug impl, should not be exposed
data: [u8; 16],
hkdf: C::HkdfSha256,
}
impl<C: CryptoProvider> V1Salt<C> {
/// Derive a salt for a particular section and DE, if applicable.
///
/// Returns none if the requested size is larger than HKDF allows or if offset arithmetic
/// overflows.
pub fn derive<const N: usize>(&self, de: Option<DataElementOffset>) -> Option<[u8; N]> {
let mut arr = [0_u8; N];
// 0-based offsets -> 1-based indices w/ 0 indicating not present
self.hkdf
.expand_multi_info(
&[
b"V1 derived salt",
&de.and_then(|d| d.offset.checked_add(1))
.and_then(|o| o.try_into().ok())
.unwrap_or(0_u32)
.to_be_bytes(),
],
&mut arr,
)
.map(|_| arr)
.ok()
}
/// Returns the salt bytes as a slice
pub fn as_slice(&self) -> &[u8] {
self.data.as_slice()
}
/// Returns the salt bytes as an array
pub fn into_array(self) -> [u8; 16] {
self.data
}
/// Returns the salt bytes as a reference to an array
pub fn as_array_ref(&self) -> &[u8; 16] {
&self.data
}
}
impl<C: CryptoProvider> From<[u8; 16]> for V1Salt<C> {
fn from(arr: [u8; 16]) -> Self {
Self { data: arr, hkdf: np_salt_hkdf::<C>(&arr) }
}
}
impl<C: CryptoProvider> PartialEq<Self> for V1Salt<C> {
fn eq(&self, other: &Self) -> bool {
// no need to compare hkdf (which it doesn't allow anyway)
self.data == other.data
}
}
impl<C: CryptoProvider> Eq for V1Salt<C> {}
impl<C: CryptoProvider> fmt::Debug for V1Salt<C> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.data.fmt(f)
}
}
/// Offset of a data element in its containing section, used with [V1Salt].
#[derive(PartialEq, Eq, Debug, Clone, Copy, PartialOrd, Ord)]
pub struct DataElementOffset {
/// 0-based offset of the DE in the advertisement
offset: u8,
}
impl DataElementOffset {
/// The zero offset
pub const ZERO: DataElementOffset = Self { offset: 0 };
/// Returns the offset as a usize
pub fn as_u8(&self) -> u8 {
self.offset
}
/// Returns the next offset.
///
/// Does not handle overflow as there can't be more than 2^8 DEs in a section.
pub const fn incremented(&self) -> Self {
Self { offset: self.offset + 1 }
}
}
impl From<u8> for DataElementOffset {
fn from(num: u8) -> Self {
Self { offset: num }
}
}