1#![forbid(unsafe_code)]
22#![deny(missing_docs)]
23#![warn(missing_debug_implementations)]
24
25#[cfg(all(feature = "lib", feature = "handrolled"))]
26compile_error!("select exactly one CSP backend: 'lib' (default) or 'handrolled'");
27
28#[cfg(not(any(feature = "lib", feature = "handrolled")))]
29compile_error!("select exactly one CSP backend: 'lib' (default) or 'handrolled'");
30
31#[cfg(feature = "lib")]
32mod lib_backend;
33
34#[cfg(feature = "lib")]
35pub use lib_backend::*;
36
37#[cfg(feature = "lib")]
38pub(crate) mod csp_call {
39 pub fn md4(data: &[u8]) -> [u8; 16] { crate::lib_backend::md4(data) }
40 pub fn hmac_sha256(key: &[u8], data: &[u8]) -> [u8; 32] { crate::lib_backend::hmac_sha256(key, data) }
41}
42
43#[cfg(feature = "handrolled")]
44mod bundled {
45 pub mod aes128;
46 pub mod des;
47 pub mod hmac;
48 pub mod hmac_sha256;
49 pub mod md4;
50 pub mod md5;
51 pub mod rc4;
52 pub mod sha256;
53 pub mod sha512;
54}
55
56#[cfg(feature = "handrolled")]
57mod backend {
58 pub use super::bundled::aes128::{aes128_cmac, aes128_encrypt_block};
59 pub use super::bundled::des::{des_encrypt_key7, ntlmv1_response};
60 pub use super::bundled::hmac::hmac_md5;
61 pub use super::bundled::hmac_sha256::hmac_sha256;
62 pub use super::bundled::md4::md4;
63 pub use super::bundled::md5::md5;
64 pub use super::bundled::rc4::rc4;
65 pub use super::bundled::sha256::sha256;
66 pub use super::bundled::sha512::sha512;
67}
68
69#[cfg(feature = "handrolled")]
70pub use backend::*;
71
72#[cfg(feature = "handrolled")]
73pub(crate) mod csp_call {
74 pub fn md4(data: &[u8]) -> [u8; 16] { super::backend::md4(data) }
75 pub fn hmac_sha256(key: &[u8], data: &[u8]) -> [u8; 32] { super::backend::hmac_sha256(key, data) }
76}
77
78
79#[cfg_attr(dylint_lib = "no_magic_numbers", allow(no_magic_numbers))] pub fn nt_hash(password: &str) -> [u8; 16] {
82 let mut bytes = Vec::with_capacity(password.len() * 2);
83 for u in password.encode_utf16() {
84 bytes.extend_from_slice(&u.to_le_bytes());
85 }
86 crate::csp_call::md4(&bytes)
87}
88
89#[cfg_attr(dylint_lib = "no_magic_numbers", allow(no_magic_numbers))] pub fn kdf_counter_mode_hmac_sha256(
96 key: &[u8],
97 label: &[u8],
98 context: &[u8],
99 result_len: usize,
100) -> Vec<u8> {
101 let bitlen = (result_len as u32) * 8;
102 let mut out = Vec::with_capacity(result_len);
103 let mut counter: u32 = 1;
104 while out.len() < result_len {
105 let mut input = Vec::with_capacity(4 + label.len() + 1 + context.len() + 4);
106 input.extend_from_slice(&counter.to_be_bytes());
107 input.extend_from_slice(label);
108 input.push(0);
109 input.extend_from_slice(context);
110 input.extend_from_slice(&bitlen.to_be_bytes());
111 let tag = crate::csp_call::hmac_sha256(key, &input);
112 out.extend_from_slice(&tag);
113 counter += 1;
114 }
115 out.truncate(result_len);
116 out
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122
123 fn hex(b: &[u8]) -> String {
124 b.iter().map(|x| format!("{:02x}", x)).collect()
125 }
126
127 #[test]
132 fn nt_hash_vector() {
133 assert_eq!(hex(&nt_hash("password")), "8846f7eaee8fb117ad06bdd830b7586c");
134 }
135
136 #[test]
137 fn md4_vector() {
138 assert_eq!(hex(&md4(b"abc")), "a448017aaf21d8525fc10ae87aa6729d");
139 assert_eq!(
140 hex(&md4(b"")),
141 "31d6cfe0d16ae931b73c59d7e0c089c0"
142 );
143 }
144
145 #[test]
146 fn md5_vector() {
147 assert_eq!(hex(&md5(b"abc")), "900150983cd24fb0d6963f7d28e17f72");
148 }
149
150 #[test]
151 fn hmac_md5_rfc2202() {
152 assert_eq!(
153 hex(&hmac_md5(b"Jefe", b"what do ya want for nothing?")),
154 "750c783e6ab0b503eaa86e310a5db738"
155 );
156 }
157
158 #[test]
159 fn sha2_vectors() {
160 assert_eq!(
161 hex(&sha256(b"abc")),
162 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
163 );
164 assert_eq!(
165 hex(&sha512(b"abc")),
166 "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a\
167 2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"
168 );
169 }
170
171 #[test]
172 fn hmac_sha256_rfc4231() {
173 assert_eq!(
174 hex(&hmac_sha256(b"Jefe", b"what do ya want for nothing?")),
175 "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843"
176 );
177 }
178
179 #[test]
180 fn rc4_vector() {
181 assert_eq!(
182 hex(&rc4(&[1u8, 2, 3, 4, 5], &[0u8; 16])),
183 "b2396305f03dc027ccc3524a0a1118a8"
184 );
185 }
186
187 #[test]
188 fn ntlmv1_golden() {
189 let h21 = [7u8; 21];
192 let challenge = [3u8; 8];
193 assert_eq!(
194 hex(&ntlmv1_response(&h21, &challenge)),
195 "23f68ad3636db29e23f68ad3636db29e23f68ad3636db29e" );
197 }
198
199 #[test]
200 fn aes_block_fips197() {
201 let key: [u8; 16] = [
202 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
203 0x0e, 0x0f,
204 ];
205 let pt: [u8; 16] = [
206 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
207 0xee, 0xff,
208 ];
209 assert_eq!(
210 hex(&aes128_encrypt_block(&key, &pt)),
211 "69c4e0d86a7b0430d8cdb78070b4c55a"
212 );
213 }
214
215 #[test]
216 fn cmac_vectors() {
217 let key: [u8; 16] = [
218 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
219 0x42, 0x42,
220 ];
221 assert_eq!(hex(&aes128_cmac(&key, &[])), "565aa8245bc3cf6d60f4f3e9d52921dd");
223 let msg16: [u8; 16] = [
224 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93,
225 0x17, 0x2a,
226 ];
227 assert_eq!(
228 hex(&aes128_cmac(&key, &msg16)),
229 "de1d864d75b61033c28628c18f6048f8"
230 );
231 let rfc_key: [u8; 16] = [
234 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf,
235 0x4f, 0x3c,
236 ];
237 assert_eq!(
238 hex(&aes128_cmac(&rfc_key, &msg16)),
239 "070a16b46b4d4144f79bdd9dd04a287c"
240 );
241 }
242
243 #[test]
244 fn kdf_cross_checked() {
245 let key: [u8; 16] = [
248 0x0d, 0xd2, 0xe3, 0xd0, 0xf7, 0x5e, 0xfb, 0x08, 0xc6, 0xfc, 0x14, 0xd6, 0x15, 0x9f,
249 0x3c, 0xc4,
250 ];
251 assert_eq!(
252 hex(&kdf_counter_mode_hmac_sha256(&key, b"label", b"context", 16)),
253 "2b59530a759817720bf9ef519983621c"
254 );
255 }
256
257 #[cfg(feature = "lib")]
258 #[test]
259 fn aes256_seal_open_roundtrip() {
260 let key = [0x11u8; 32];
261 let aad = b"transform-header-aad";
262 let pt = b"AES-256 sealed SMB payload";
263
264 let g = aes256gcm_seal(&key, &[0x22u8; 12], aad, pt);
265 assert_eq!(
266 aes256gcm_open(&key, &[0x22u8; 12], aad, &g).as_deref(),
267 Some(&pt[..])
268 );
269 assert!(aes256gcm_open(&[0u8; 32], &[0x22u8; 12], aad, &g).is_none());
271
272 let c = aes256ccm_seal(&key, &[0x33u8; 11], aad, pt);
273 assert_eq!(
274 aes256ccm_open(&key, &[0x33u8; 11], aad, &c).as_deref(),
275 Some(&pt[..])
276 );
277 assert!(aes256ccm_open(&key, &[0x33u8; 11], b"other-aad", &c).is_none());
279 }
280}