bake_kdf/
lib.rs

1#![no_std]
2#![doc(
3    html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
4    html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
5    html_root_url = "https://docs.rs/bake-kdf/0.0.0"
6)]
7#![doc = include_str!("../README.md")]
8#![cfg_attr(docsrs, feature(doc_auto_cfg))]
9#![forbid(unsafe_code)]
10#![warn(missing_docs, rust_2018_idioms)]
11
12use belt_hash::digest::FixedOutput;
13use belt_hash::{belt_compress, BeltHash, Digest};
14
15/// `belt-keyexpand` key expansion algorithm described in STB 34.101.34-2020 8.1.2.
16///
17/// # Panics
18/// If `N` is not equal to 16, 24, or 32.
19// TODO: use compile-time checks for `N`
20#[inline]
21pub fn belt_keyexpand<const N: usize>(k: &[u8; N]) -> [u32; 8] {
22    let mut t = [0u32; 8];
23    // TODO: move this conversion into `belt_keyrep` when we will be able
24    // to use generic paramaters as `[u32; N / 4]`.
25    for (src, dst) in k.chunks_exact(4).zip(t.iter_mut()) {
26        *dst = u32::from_le_bytes(src.try_into().unwrap());
27    }
28    match N {
29        16 => {
30            t[4] = t[0];
31            t[5] = t[1];
32            t[6] = t[2];
33            t[7] = t[3];
34        }
35        24 => {
36            t[6] = t[0] ^ t[1] ^ t[2];
37            t[7] = t[3] ^ t[4] ^ t[5];
38        }
39        32 => {}
40        _ => panic!("Invalid key size n={N}. Expected 16, 24, or 32."),
41    }
42    t
43}
44
45/// `belt-keyrep` key repetition algorithm described in STB 34.101.34-2020 8.1.3.
46///
47/// # Panics
48/// If `(N, M)` is not equal to `(16, 16)`, `(24, 16)`, `(24, 24)`,
49/// `(32, 16)`, `(32, 24)`, or `(32, 32)`.
50// TODO: use compile-time check for `N` and `M`
51#[inline]
52pub fn belt_keyrep<const N: usize, const M: usize>(
53    x: &[u8; N],
54    d: &[u8; 12],
55    i: &[u8; 16],
56) -> [u8; M] {
57    let r: u32 = match (N, M) {
58        (16, 16) => 0xC8BA94B1,
59        (24, 16) => 0x12D6E35B,
60        (24, 24) => 0xFFC0B05C,
61        (32, 16) => 0x1ADC2BE1,
62        (32, 24) => 0x3876ABC1,
63        (32, 32) => 0x7B653CF3,
64        _ => panic!("belt-keyrep: invalid combination of N ({N}) and M ({M})"),
65    };
66
67    let s = belt_keyexpand(x);
68
69    let d = [
70        u32::from_le_bytes(d[..4].try_into().unwrap()),
71        u32::from_le_bytes(d[4..][..4].try_into().unwrap()),
72        u32::from_le_bytes(d[8..][..4].try_into().unwrap()),
73    ];
74
75    let i = [
76        u32::from_le_bytes(i[0..][..4].try_into().unwrap()),
77        u32::from_le_bytes(i[4..][..4].try_into().unwrap()),
78        u32::from_le_bytes(i[8..][..4].try_into().unwrap()),
79        u32::from_le_bytes(i[12..][..4].try_into().unwrap()),
80    ];
81
82    let (_, s) = belt_compress([r, d[0], d[1], d[2]], i, s);
83
84    let mut y = [0u8; M];
85    for (src, dst) in s.iter().zip(y.chunks_exact_mut(4)) {
86        dst.copy_from_slice(&src.to_le_bytes());
87    }
88    y
89}
90
91/// `bake-kdf` key derivation algorithm described in STB 34.101.66-2014 8.1.4.
92#[inline]
93pub fn bake_kdf(x: &[u8], s: &[u8], c: u128) -> [u8; 32] {
94    let mut hasher = BeltHash::default();
95    hasher.update(x);
96    hasher.update(s);
97    let y = hasher.finalize_fixed().0;
98
99    belt_keyrep(&y, &[0xFF; 12], &c.to_le_bytes())
100}