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 = "traits010")]
227mod digest_trait010 {
228 use core::fmt;
229
230 use digest010::{
231 block_buffer::Eager,
232 const_oid::{AssociatedOid, ObjectIdentifier},
233 consts::{U20, U64},
234 core_api::{
235 AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser, FixedOutputCore,
236 OutputSizeUser, Reset, UpdateCore,
237 },
238 HashMarker,
239 };
240
241 use super::Hash;
242
243 impl AssociatedOid for Hash {
244 const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.14.3.2.26");
245 }
246
247 impl AlgorithmName for Hash {
248 fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
249 f.write_str("Sha1")
250 }
251 }
252
253 impl HashMarker for Hash {}
254
255 impl BufferKindUser for Hash {
256 type BufferKind = Eager;
257 }
258
259 impl BlockSizeUser for Hash {
260 type BlockSize = U64;
261 }
262
263 impl OutputSizeUser for Hash {
264 type OutputSize = U20;
265 }
266
267 impl UpdateCore for Hash {
268 #[inline]
269 fn update_blocks(&mut self, blocks: &[Block<Self>]) {
270 for block in blocks {
271 self._update(block)
272 }
273 }
274 }
275
276 impl FixedOutputCore for Hash {
277 fn finalize_fixed_core(
278 &mut self,
279 buffer: &mut Buffer<Self>,
280 out: &mut digest010::Output<Self>,
281 ) {
282 self._update(buffer.get_data());
283 let h = self.finalize();
284 out.copy_from_slice(&h);
285 }
286 }
287
288 impl Reset for Hash {
289 fn reset(&mut self) {
290 *self = Self::new()
291 }
292 }
293}
294
295#[test]
296fn main() {
297 let h = Hash::hash(b"");
298 assert_eq!(
299 &h[..],
300 &[218, 57, 163, 238, 94, 107, 75, 13, 50, 85, 191, 239, 149, 96, 24, 144, 175, 216, 7, 9]
301 );
302
303 let h = Hash::hash(b"test");
304 assert_eq!(
305 &h[..],
306 &[
307 169, 74, 143, 229, 204, 177, 155, 166, 28, 76, 8, 115, 211, 145, 233, 135, 152, 47,
308 187, 211
309 ]
310 );
311
312 let h = Hash::hash(b"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
313 assert_eq!(
314 &h[..],
315 &[
316 83, 198, 188, 169, 11, 131, 194, 106, 152, 41, 132, 130, 87, 94, 225, 72, 154, 232, 71,
317 164
318 ]
319 );
320
321 let h = HMAC::mac(&[42u8; 69], &[]);
322 assert_eq!(
323 &h[..],
324 &[
325 158, 168, 84, 31, 38, 118, 164, 197, 103, 254, 207, 71, 48, 231, 13, 254, 219, 82, 96,
326 68
327 ]
328 );
329
330 let h = HMAC::mac(&[69u8; 250], &[42u8; 50]);
331 assert_eq!(
332 &h[..],
333 &[227, 229, 82, 212, 89, 36, 86, 81, 168, 126, 125, 32, 181, 28, 108, 40, 2, 213, 102, 90]
334 );
335}
336
337#[cfg(feature = "traits010")]
338#[test]
339fn main_traits() {
340 use digest010::Digest;
341 let mut h = WrappedHash::new();
342 Digest::update(&mut h, b"");
343 assert_eq!(
344 h.finalize().as_slice(),
345 &[218, 57, 163, 238, 94, 107, 75, 13, 50, 85, 191, 239, 149, 96, 24, 144, 175, 216, 7, 9]
346 );
347
348 let mut h = WrappedHash::new();
349 Digest::update(&mut h, b"test");
350 assert_eq!(
351 h.finalize().as_slice(),
352 &[
353 169, 74, 143, 229, 204, 177, 155, 166, 28, 76, 8, 115, 211, 145, 233, 135, 152, 47,
354 187, 211
355 ]
356 );
357}