blob: ded25aa6f059b60f10c1d050f5c69054a4167012 [file]
// Copyright 2026 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use aes::cipher::{BlockCipherEncrypt, KeyInit};
/// Set Identity Hash (SIH) function as defined in CSIS 1.1 Specification,
/// Section 4.7. `sih(k, r) = e(k, r') mod 2^24`
/// where `r' = padding || r`, padding is 104 bits of 0.
/// The LSO of r becomes the LSO of r'.
pub fn set_identity_hash(key: &[u8; 16], r: &[u8; 3]) -> [u8; 3] {
let mut plaintext = [0u8; 16];
// r' = padding || r. LSO of r is LSO of r'.
// Since Bluetooth is little endian, LSO is at index 0.
plaintext[0] = r[0];
plaintext[1] = r[1];
plaintext[2] = r[2];
// The rest of the bytes are already 0 (padding).
// Bluetooth `e` function uses AES-128 but is LSB-first (little endian).
// The `aes` crate is MSB-first. We need to reverse the input and output.
let mut key_reversed = *key;
key_reversed.reverse();
plaintext.reverse();
let key_block = key_reversed.into();
let mut block = plaintext.into();
let cipher = aes::Aes128::new(&key_block);
cipher.encrypt_block(&mut block);
// sih keeps the least significant 24 bits of e, the last three octets of
// the MSB-first block, returned LSO first.
[block[15], block[14], block[13]]
}
/// Sample values from the CSIS v1.1 specification, least significant octet
/// first.
#[cfg(test)]
pub(crate) mod test_vectors {
/// Appendix A.1, `k`.
pub(crate) const SIRK: [u8; 16] = [
0xcd, 0xcc, 0x72, 0xdd, 0x86, 0x8c, 0xcd, 0xce, 0x22, 0xfd, 0xa1, 0x21, 0x09, 0x7d, 0x7d,
0x45,
];
/// Appendix A.1, `r`. In MSB-first notation, 0x69f563.
pub(crate) const PRAND: [u8; 3] = [0x63, 0xf5, 0x69];
/// Appendix A.1, `sih(k, r)`. In MSB-first notation, 0x1948da.
pub(crate) const HASH: [u8; 3] = [0xda, 0x48, 0x19];
/// The RSI that a Set Member holding `SIRK` advertises for `PRAND`, which
/// is `hash || prand`.
pub(crate) const RSI: [u8; 6] = [HASH[0], HASH[1], HASH[2], PRAND[0], PRAND[1], PRAND[2]];
}
#[cfg(test)]
mod tests {
use super::test_vectors::{HASH, PRAND, SIRK};
use super::*;
#[test]
fn set_identity_hash_matches_the_spec_vector() {
assert_eq!(set_identity_hash(&SIRK, &PRAND), HASH);
}
}