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