1#![no_std]
5#![allow(
6 non_snake_case,
7 clippy::cast_lossless,
8 clippy::eq_op,
9 clippy::identity_op,
10 clippy::many_single_char_names,
11 clippy::unreadable_literal
12)]
13
14#[inline(always)]
15fn load_be(base: &[u8], offset: usize) -> u32 {
16 let addr = &base[offset..];
17 (addr[3] as u32) | (addr[2] as u32) << 8 | (addr[1] as u32) << 16 | (addr[0] as u32) << 24
18}
19
20#[inline(always)]
21fn store_be(base: &mut [u8], offset: usize, x: u32) {
22 let addr = &mut base[offset..];
23 addr[3] = x as u8;
24 addr[2] = (x >> 8) as u8;
25 addr[1] = (x >> 16) as u8;
26 addr[0] = (x >> 24) as u8;
27}
28
29#[derive(Copy, Clone)]
30struct State([u32; 5]);
31
32impl State {
33 fn new() -> Self {
34 State([0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0])
35 }
36
37 fn store(&self, out: &mut [u8]) {
38 for (i, &e) in self.0.iter().enumerate() {
39 store_be(out, i * 4, e);
40 }
41 }
42
43 fn blocks(&mut self, mut input: &[u8]) -> usize {
44 let mut inlen = input.len();
45 let mut w = [0u32; 80];
46 while inlen >= 64 {
47 for i in 0..16 {
48 w[i] = load_be(input, i * 4);
49 }
50 for i in 16..80 {
51 w[i] = (w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]).rotate_left(1);
52 }
53 let mut t = self.0;
54
55 for (i, wi) in w.iter().enumerate() {
56 let (f, k) = match i {
57 0..=19 => (t[1] & t[2] | !t[1] & t[3], 0x5a827999),
58 20..=39 => (t[1] ^ t[2] ^ t[3], 0x6ed9eba1),
59 40..=59 => (t[1] & t[2] | t[1] & t[3] | t[2] & t[3], 0x8f1bbcdc),
60 60..=79 => (t[1] ^ t[2] ^ t[3], 0xca62c1d6),
61 _ => unreachable!(),
62 };
63 let g = t[0]
64 .rotate_left(5)
65 .wrapping_add(f.wrapping_add(t[4].wrapping_add(wi.wrapping_add(k))));
66 t[4] = t[3];
67 t[3] = t[2];
68 t[2] = t[1].rotate_left(30);
69 t[1] = t[0];
70 t[0] = g;
71 }
72 for (i, s) in self.0.iter_mut().enumerate() {
73 *s = s.wrapping_add(t[i]);
74 }
75 input = &input[64..];
76 inlen -= 64;
77 }
78 inlen
79 }
80}
81
82#[derive(Copy, Clone)]
83pub struct Hash {
84 state: State,
85 w: [u8; 64],
86 r: usize,
87 len: usize,
88}
89
90impl Hash {
91 pub fn new() -> Hash {
92 Hash {
93 state: State::new(),
94 r: 0,
95 w: [0u8; 64],
96 len: 0,
97 }
98 }
99
100 fn _update<T: AsRef<[u8]>>(&mut self, input: T) {
101 let input = input.as_ref();
102 let mut n = input.len();
103 self.len += n;
104 let av = 64 - self.r;
105 let tc = ::core::cmp::min(n, av);
106 self.w[self.r..self.r + tc].copy_from_slice(&input[0..tc]);
107 self.r += tc;
108 n -= tc;
109 let pos = tc;
110 if self.r == 64 {
111 self.state.blocks(&self.w);
112 self.r = 0;
113 }
114 if self.r == 0 && n > 0 {
115 let rb = self.state.blocks(&input[pos..]);
116 if rb > 0 {
117 self.w[..rb].copy_from_slice(&input[pos + n - rb..]);
118 self.r = rb;
119 }
120 }
121 }
122
123 pub fn update<T: AsRef<[u8]>>(&mut self, input: T) {
125 self._update(input)
126 }
127
128 pub fn finalize(mut self) -> [u8; 20] {
130 let mut padded = [0u8; 128];
131 padded[..self.r].copy_from_slice(&self.w[..self.r]);
132 padded[self.r] = 0x80;
133 let r = if self.r < 56 { 64 } else { 128 };
134 let bits = self.len * 8;
135 for i in 0..8 {
136 padded[r - 8 + i] = (bits as u64 >> (56 - i * 8)) as u8;
137 }
138 self.state.blocks(&padded[..r]);
139 let mut out = [0u8; 20];
140 self.state.store(&mut out);
141 out
142 }
143
144 pub fn hash(input: &[u8]) -> [u8; 20] {
146 let mut h = Hash::new();
147 h.update(input);
148 h.finalize()
149 }
150}
151
152impl Default for Hash {
153 fn default() -> Self {
154 Self::new()
155 }
156}
157
158pub struct HMAC;
159
160impl HMAC {
161 pub fn mac(input: &[u8], k: &[u8]) -> [u8; 20] {
163 let mut hk = [0u8; 20];
164 let k2 = if k.len() > 64 {
165 hk.copy_from_slice(&Hash::hash(k));
166 &hk
167 } else {
168 k
169 };
170 let mut padded = [0x36; 40];
171 for (p, &k) in padded.iter_mut().zip(k2.iter()) {
172 *p ^= k;
173 }
174 let mut ih = Hash::new();
175 ih.update(&padded[..]);
176 ih.update(input);
177
178 for p in padded.iter_mut() {
179 *p ^= 0x6a;
180 }
181 let mut oh = Hash::new();
182 oh.update(&padded[..]);
183 oh.update(ih.finalize());
184 oh.finalize()
185 }
186}
187
188#[cfg(feature = "traits09")]
189mod digest_trait09 {
190 use digest09::consts::{U32, U64};
191 use digest09::{BlockInput, FixedOutputDirty, Output, Reset, Update};
192
193 use super::Hash;
194
195 impl BlockInput for Hash {
196 type BlockSize = U64;
197 }
198
199 impl Update for Hash {
200 fn update(&mut self, input: impl AsRef<[u8]>) {
201 self._update(input)
202 }
203 }
204
205 impl FixedOutputDirty for Hash {
206 type OutputSize = U32;
207
208 fn finalize_into_dirty(&mut self, out: &mut Output<Self>) {
209 let h = self.finalize();
210 out.copy_from_slice(&h);
211 }
212 }
213
214 impl Reset for Hash {
215 fn reset(&mut self) {
216 *self = Self::new()
217 }
218 }
219}
220
221#[cfg(feature = "traits010")]
223pub type WrappedHash = digest010::core_api::CoreWrapper<Hash>;
224
225#[cfg(feature = "traits010")]
226mod digest_trait010 {
227 use core::fmt;
228
229 use digest010::{
230 block_buffer::Eager,
231 const_oid::{AssociatedOid, ObjectIdentifier},
232 consts::{U20, U64},
233 core_api::{
234 AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser, FixedOutputCore,
235 OutputSizeUser, Reset, UpdateCore,
236 },
237 HashMarker,
238 };
239
240 use super::Hash;
241
242 impl AssociatedOid for Hash {
243 const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.14.3.2.26");
244 }
245
246 impl AlgorithmName for Hash {
247 fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
248 f.write_str("Sha1")
249 }
250 }
251
252 impl HashMarker for Hash {}
253
254 impl BufferKindUser for Hash {
255 type BufferKind = Eager;
256 }
257
258 impl BlockSizeUser for Hash {
259 type BlockSize = U64;
260 }
261
262 impl OutputSizeUser for Hash {
263 type OutputSize = U20;
264 }
265
266 impl UpdateCore for Hash {
267 #[inline]
268 fn update_blocks(&mut self, blocks: &[Block<Self>]) {
269 for block in blocks {
270 self._update(block)
271 }
272 }
273 }
274
275 impl FixedOutputCore for Hash {
276 fn finalize_fixed_core(
277 &mut self,
278 buffer: &mut Buffer<Self>,
279 out: &mut digest010::Output<Self>,
280 ) {
281 self._update(buffer.get_data());
282 let h = self.finalize();
283 out.copy_from_slice(&h);
284 }
285 }
286
287 impl Reset for Hash {
288 fn reset(&mut self) {
289 *self = Self::new()
290 }
291 }
292}
293
294#[test]
295fn main() {
296 let h = Hash::hash(b"");
297 assert_eq!(
298 &h[..],
299 &[218, 57, 163, 238, 94, 107, 75, 13, 50, 85, 191, 239, 149, 96, 24, 144, 175, 216, 7, 9]
300 );
301
302 let h = Hash::hash(b"test");
303 assert_eq!(
304 &h[..],
305 &[
306 169, 74, 143, 229, 204, 177, 155, 166, 28, 76, 8, 115, 211, 145, 233, 135, 152, 47,
307 187, 211
308 ]
309 );
310
311 let h = Hash::hash(b"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
312 assert_eq!(
313 &h[..],
314 &[
315 83, 198, 188, 169, 11, 131, 194, 106, 152, 41, 132, 130, 87, 94, 225, 72, 154, 232, 71,
316 164
317 ]
318 );
319
320 let h = HMAC::mac(&[42u8; 69], &[]);
321 assert_eq!(
322 &h[..],
323 &[
324 145, 126, 228, 73, 171, 107, 124, 27, 28, 215, 16, 100, 14, 136, 213, 49, 251, 121,
325 205, 27
326 ]
327 );
328
329 let h = HMAC::mac(&[69u8; 250], &[42u8; 50]);
330 assert_eq!(
331 &h[..],
332 &[44, 56, 48, 37, 170, 240, 168, 220, 81, 38, 5, 248, 34, 189, 41, 26, 218, 93, 126, 133]
333 );
334}
335
336#[cfg(feature = "traits010")]
337#[test]
338fn main_traits() {
339 use digest010::Digest;
340 let mut h = WrappedHash::new();
341 Digest::update(&mut h, b"");
342 assert_eq!(
343 h.finalize().as_slice(),
344 &[218, 57, 163, 238, 94, 107, 75, 13, 50, 85, 191, 239, 149, 96, 24, 144, 175, 216, 7, 9]
345 );
346
347 let mut h = WrappedHash::new();
348 Digest::update(&mut h, b"test");
349 assert_eq!(
350 h.finalize().as_slice(),
351 &[
352 169, 74, 143, 229, 204, 177, 155, 166, 28, 76, 8, 115, 211, 145, 233, 135, 152, 47,
353 187, 211
354 ]
355 );
356}