encryption/kdf/
hkdf_sha256.rs1use hkdf::Hkdf;
6use sha2::Sha256;
7
8use crate::contract::{Identified, KeyDerivation};
9use crate::error::{Error, Result};
10
11const MAX_OUTPUT_LEN: usize = 255 * 32;
13
14#[derive(Debug, Default, Clone, Copy)]
16pub struct HkdfSha256;
17
18impl HkdfSha256 {
19 pub const IDENTIFIER: &'static str = "hkdf-sha256";
20
21 pub fn new() -> Self {
22 Self
23 }
24}
25
26impl Identified for HkdfSha256 {
27 fn identifier(&self) -> &str {
28 Self::IDENTIFIER
29 }
30}
31
32impl KeyDerivation for HkdfSha256 {
33 fn derive(&self, ikm: &[u8], salt: &[u8], length: usize, info: &[u8]) -> Result<Vec<u8>> {
35 if length == 0 || length > MAX_OUTPUT_LEN {
36 return Err(Error::InvalidOutputLength {
37 requested: length,
38 max: MAX_OUTPUT_LEN,
39 });
40 }
41
42 let hkdf = if salt.is_empty() {
43 Hkdf::<Sha256>::new(None, ikm)
44 } else {
45 Hkdf::<Sha256>::new(Some(salt), ikm)
46 };
47
48 let mut output = vec![0u8; length];
49 hkdf.expand(info, &mut output)
50 .map_err(|_| Error::InvalidOutputLength {
51 requested: length,
52 max: MAX_OUTPUT_LEN,
53 })?;
54 Ok(output)
55 }
56}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61
62 #[test]
64 fn matches_rfc5869_test_vector() {
65 let ikm = [0x0bu8; 22];
66 let salt: Vec<u8> = (0x00u8..=0x0c).collect();
67 let info: Vec<u8> = (0xf0u8..=0xf9).collect();
68
69 let okm = HkdfSha256::new().derive(&ikm, &salt, 42, &info).unwrap();
70 assert_eq!(
71 crate::internal::hex_encode(&okm),
72 "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865"
73 );
74 }
75
76 #[test]
77 fn empty_salt_and_limits() {
78 let kdf = HkdfSha256::new();
79 assert_eq!(kdf.derive(b"ikm", b"", 16, b"").unwrap().len(), 16);
80 assert_eq!(
81 kdf.derive(b"ikm", b"", 0, b"").unwrap_err(),
82 Error::InvalidOutputLength {
83 requested: 0,
84 max: MAX_OUTPUT_LEN
85 }
86 );
87 assert_eq!(
88 kdf.derive(b"ikm", b"", MAX_OUTPUT_LEN + 1, b"")
89 .unwrap_err(),
90 Error::InvalidOutputLength {
91 requested: MAX_OUTPUT_LEN + 1,
92 max: MAX_OUTPUT_LEN
93 }
94 );
95 }
96}