physis/
sha1.rs

1// SPDX-FileCopyrightText: Armin Ronacher, Koka El Kiwi
2// SPDX-License-Identifier: BSD-3-Clause
3// SPDX-FileNotice: Modified sha1-smol crate (https://github.com/mitsuhiko/sha1-smol) revised for vendored use in physis
4// TODO: remove some extra bits, since we usually only consume digests once
5
6//! A minimal implementation of SHA1 for rust.
7//!
8//! This implementation supports no_std.
9//!
10//! The sha1 object can be updated multiple times.
11
12#![deny(missing_docs)]
13#![allow(deprecated)]
14#![allow(clippy::double_parens)]
15#![allow(clippy::identity_op)]
16#![allow(dead_code)]
17
18use core::cmp;
19use core::fmt;
20use core::hash;
21use core::str;
22
23pub use self::fake::*;
24
25pub trait SimdExt {
26    fn simd_eq(self, rhs: Self) -> Self;
27}
28
29impl SimdExt for u32x4 {
30    fn simd_eq(self, rhs: Self) -> Self {
31        if self == rhs {
32            u32x4(0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff)
33        } else {
34            u32x4(0, 0, 0, 0)
35        }
36    }
37}
38
39mod fake {
40    use core::ops::{Add, BitAnd, BitOr, BitXor, Shl, Shr, Sub};
41
42    #[derive(Clone, Copy, PartialEq, Eq)]
43    #[allow(non_camel_case_types)]
44    pub struct u32x4(pub u32, pub u32, pub u32, pub u32);
45
46    impl Add for u32x4 {
47        type Output = u32x4;
48
49        fn add(self, rhs: u32x4) -> u32x4 {
50            u32x4(
51                self.0.wrapping_add(rhs.0),
52                self.1.wrapping_add(rhs.1),
53                self.2.wrapping_add(rhs.2),
54                self.3.wrapping_add(rhs.3),
55            )
56        }
57    }
58
59    impl Sub for u32x4 {
60        type Output = u32x4;
61
62        fn sub(self, rhs: u32x4) -> u32x4 {
63            u32x4(
64                self.0.wrapping_sub(rhs.0),
65                self.1.wrapping_sub(rhs.1),
66                self.2.wrapping_sub(rhs.2),
67                self.3.wrapping_sub(rhs.3),
68            )
69        }
70    }
71
72    impl BitAnd for u32x4 {
73        type Output = u32x4;
74
75        fn bitand(self, rhs: u32x4) -> u32x4 {
76            u32x4(
77                self.0 & rhs.0,
78                self.1 & rhs.1,
79                self.2 & rhs.2,
80                self.3 & rhs.3,
81            )
82        }
83    }
84
85    impl BitOr for u32x4 {
86        type Output = u32x4;
87
88        fn bitor(self, rhs: u32x4) -> u32x4 {
89            u32x4(
90                self.0 | rhs.0,
91                self.1 | rhs.1,
92                self.2 | rhs.2,
93                self.3 | rhs.3,
94            )
95        }
96    }
97
98    impl BitXor for u32x4 {
99        type Output = u32x4;
100
101        fn bitxor(self, rhs: u32x4) -> u32x4 {
102            u32x4(
103                self.0 ^ rhs.0,
104                self.1 ^ rhs.1,
105                self.2 ^ rhs.2,
106                self.3 ^ rhs.3,
107            )
108        }
109    }
110
111    impl Shl<usize> for u32x4 {
112        type Output = u32x4;
113
114        fn shl(self, amt: usize) -> u32x4 {
115            u32x4(self.0 << amt, self.1 << amt, self.2 << amt, self.3 << amt)
116        }
117    }
118
119    impl Shl<u32x4> for u32x4 {
120        type Output = u32x4;
121
122        fn shl(self, rhs: u32x4) -> u32x4 {
123            u32x4(
124                self.0 << rhs.0,
125                self.1 << rhs.1,
126                self.2 << rhs.2,
127                self.3 << rhs.3,
128            )
129        }
130    }
131
132    impl Shr<usize> for u32x4 {
133        type Output = u32x4;
134
135        fn shr(self, amt: usize) -> u32x4 {
136            u32x4(self.0 >> amt, self.1 >> amt, self.2 >> amt, self.3 >> amt)
137        }
138    }
139
140    impl Shr<u32x4> for u32x4 {
141        type Output = u32x4;
142
143        fn shr(self, rhs: u32x4) -> u32x4 {
144            u32x4(
145                self.0 >> rhs.0,
146                self.1 >> rhs.1,
147                self.2 >> rhs.2,
148                self.3 >> rhs.3,
149            )
150        }
151    }
152
153    #[derive(Clone, Copy)]
154    #[allow(non_camel_case_types)]
155    pub struct u64x2(pub u64, pub u64);
156
157    impl Add for u64x2 {
158        type Output = u64x2;
159
160        fn add(self, rhs: u64x2) -> u64x2 {
161            u64x2(self.0.wrapping_add(rhs.0), self.1.wrapping_add(rhs.1))
162        }
163    }
164}
165
166/// The length of a SHA1 digest in bytes
167pub const DIGEST_LENGTH: usize = 20;
168
169/// Represents a Sha1 hash object in memory.
170#[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
171pub struct Sha1 {
172    state: Sha1State,
173    blocks: Blocks,
174    len: u64,
175}
176
177struct Blocks {
178    len: u32,
179    block: [u8; 64],
180}
181
182#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Default)]
183struct Sha1State {
184    state: [u32; 5],
185}
186
187/// Digest generated from a `Sha1` instance.
188///
189/// A digest can be formatted to view the digest as a hex string, or the bytes
190/// can be extracted for later processing.
191///
192/// To retrieve a hex string result call `to_string` on it (requires that std
193/// is available).
194///
195/// If the `serde` feature is enabled a digest can also be serialized and
196/// deserialized.  Likewise a digest can be parsed from a hex string.
197#[derive(PartialOrd, Ord, PartialEq, Eq, Hash, Clone, Copy, Default)]
198pub struct Digest {
199    data: Sha1State,
200}
201
202const DEFAULT_STATE: Sha1State = Sha1State {
203    state: [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0],
204};
205
206#[inline(always)]
207fn as_block(input: &[u8]) -> &[u8; 64] {
208    unsafe {
209        assert_eq!(input.len(), 64);
210        let arr: &[u8; 64] = &*(input.as_ptr() as *const [u8; 64]);
211        arr
212    }
213}
214
215impl Default for Sha1 {
216    fn default() -> Sha1 {
217        Sha1::new()
218    }
219}
220
221impl Sha1 {
222    /// Creates an fresh sha1 hash object.
223    ///
224    /// This is equivalent to creating a hash with `Default::default`.
225    pub fn new() -> Sha1 {
226        Sha1 {
227            state: DEFAULT_STATE,
228            len: 0,
229            blocks: Blocks {
230                len: 0,
231                block: [0; 64],
232            },
233        }
234    }
235
236    /// Shortcut to create a sha1 from some bytes.
237    ///
238    /// This also lets you create a hash from a utf-8 string.  This is equivalent
239    /// to making a new Sha1 object and calling `update` on it once.
240    pub fn from<D: AsRef<[u8]>>(data: D) -> Sha1 {
241        let mut rv = Sha1::new();
242        rv.update(data.as_ref());
243        rv
244    }
245
246    /// Update hash with input data.
247    pub fn update(&mut self, data: &[u8]) {
248        let len = &mut self.len;
249        let state = &mut self.state;
250        self.blocks.input(data, |block| {
251            *len += block.len() as u64;
252            state.process(block);
253        })
254    }
255
256    /// Retrieve digest result.
257    pub fn digest(&self) -> Digest {
258        let mut state = self.state;
259        let bits = (self.len + (self.blocks.len as u64)) * 8;
260        let extra = [
261            (bits >> 56) as u8,
262            (bits >> 48) as u8,
263            (bits >> 40) as u8,
264            (bits >> 32) as u8,
265            (bits >> 24) as u8,
266            (bits >> 16) as u8,
267            (bits >> 8) as u8,
268            (bits >> 0) as u8,
269        ];
270        let mut last = [0; 128];
271        let blocklen = self.blocks.len as usize;
272        last[..blocklen].clone_from_slice(&self.blocks.block[..blocklen]);
273        last[blocklen] = 0x80;
274
275        if blocklen < 56 {
276            last[56..64].clone_from_slice(&extra);
277            state.process(as_block(&last[0..64]));
278        } else {
279            last[120..128].clone_from_slice(&extra);
280            state.process(as_block(&last[0..64]));
281            state.process(as_block(&last[64..128]));
282        }
283
284        Digest { data: state }
285    }
286}
287
288impl Digest {
289    /// Returns the 160 bit (20 byte) digest as a byte array.
290    pub fn bytes(&self) -> [u8; DIGEST_LENGTH] {
291        [
292            (self.data.state[0] >> 24) as u8,
293            (self.data.state[0] >> 16) as u8,
294            (self.data.state[0] >> 8) as u8,
295            (self.data.state[0] >> 0) as u8,
296            (self.data.state[1] >> 24) as u8,
297            (self.data.state[1] >> 16) as u8,
298            (self.data.state[1] >> 8) as u8,
299            (self.data.state[1] >> 0) as u8,
300            (self.data.state[2] >> 24) as u8,
301            (self.data.state[2] >> 16) as u8,
302            (self.data.state[2] >> 8) as u8,
303            (self.data.state[2] >> 0) as u8,
304            (self.data.state[3] >> 24) as u8,
305            (self.data.state[3] >> 16) as u8,
306            (self.data.state[3] >> 8) as u8,
307            (self.data.state[3] >> 0) as u8,
308            (self.data.state[4] >> 24) as u8,
309            (self.data.state[4] >> 16) as u8,
310            (self.data.state[4] >> 8) as u8,
311            (self.data.state[4] >> 0) as u8,
312        ]
313    }
314}
315
316impl Blocks {
317    fn input<F>(&mut self, mut input: &[u8], mut f: F)
318    where
319        F: FnMut(&[u8; 64]),
320    {
321        if self.len > 0 {
322            let len = self.len as usize;
323            let amt = cmp::min(input.len(), self.block.len() - len);
324            self.block[len..len + amt].clone_from_slice(&input[..amt]);
325            if len + amt == self.block.len() {
326                f(&self.block);
327                self.len = 0;
328                input = &input[amt..];
329            } else {
330                self.len += amt as u32;
331                return;
332            }
333        }
334        assert_eq!(self.len, 0);
335        for chunk in input.chunks(64) {
336            if chunk.len() == 64 {
337                f(as_block(chunk))
338            } else {
339                self.block[..chunk.len()].clone_from_slice(chunk);
340                self.len = chunk.len() as u32;
341            }
342        }
343    }
344}
345
346// Round key constants
347const K0: u32 = 0x5A827999u32;
348const K1: u32 = 0x6ED9EBA1u32;
349const K2: u32 = 0x8F1BBCDCu32;
350const K3: u32 = 0xCA62C1D6u32;
351
352/// Not an intrinsic, but gets the first element of a vector.
353#[inline]
354fn sha1_first(w0: u32x4) -> u32 {
355    w0.0
356}
357
358/// Not an intrinsic, but adds a word to the first element of a vector.
359#[inline]
360fn sha1_first_add(e: u32, w0: u32x4) -> u32x4 {
361    let u32x4(a, b, c, d) = w0;
362    u32x4(e.wrapping_add(a), b, c, d)
363}
364
365/// Emulates `llvm.x86.sha1msg1` intrinsic.
366fn sha1msg1(a: u32x4, b: u32x4) -> u32x4 {
367    let u32x4(_, _, w2, w3) = a;
368    let u32x4(w4, w5, _, _) = b;
369    a ^ u32x4(w2, w3, w4, w5)
370}
371
372/// Emulates `llvm.x86.sha1msg2` intrinsic.
373fn sha1msg2(a: u32x4, b: u32x4) -> u32x4 {
374    let u32x4(x0, x1, x2, x3) = a;
375    let u32x4(_, w13, w14, w15) = b;
376
377    let w16 = (x0 ^ w13).rotate_left(1);
378    let w17 = (x1 ^ w14).rotate_left(1);
379    let w18 = (x2 ^ w15).rotate_left(1);
380    let w19 = (x3 ^ w16).rotate_left(1);
381
382    u32x4(w16, w17, w18, w19)
383}
384
385/// Emulates `llvm.x86.sha1nexte` intrinsic.
386#[inline]
387fn sha1_first_half(abcd: u32x4, msg: u32x4) -> u32x4 {
388    sha1_first_add(sha1_first(abcd).rotate_left(30), msg)
389}
390
391/// Emulates `llvm.x86.sha1rnds4` intrinsic.
392/// Performs 4 rounds of the message block digest.
393fn sha1_digest_round_x4(abcd: u32x4, work: u32x4, i: i8) -> u32x4 {
394    const K0V: u32x4 = u32x4(K0, K0, K0, K0);
395    const K1V: u32x4 = u32x4(K1, K1, K1, K1);
396    const K2V: u32x4 = u32x4(K2, K2, K2, K2);
397    const K3V: u32x4 = u32x4(K3, K3, K3, K3);
398
399    match i {
400        0 => sha1rnds4c(abcd, work + K0V),
401        1 => sha1rnds4p(abcd, work + K1V),
402        2 => sha1rnds4m(abcd, work + K2V),
403        3 => sha1rnds4p(abcd, work + K3V),
404        _ => panic!("unknown icosaround index"),
405    }
406}
407
408/// Not an intrinsic, but helps emulate `llvm.x86.sha1rnds4` intrinsic.
409fn sha1rnds4c(abcd: u32x4, msg: u32x4) -> u32x4 {
410    let u32x4(mut a, mut b, mut c, mut d) = abcd;
411    let u32x4(t, u, v, w) = msg;
412    let mut e = 0u32;
413
414    macro_rules! bool3ary_202 {
415        ($a:expr, $b:expr, $c:expr) => {
416            ($c ^ ($a & ($b ^ $c)))
417        };
418    } // Choose, MD5F, SHA1C
419
420    e = e
421        .wrapping_add(a.rotate_left(5))
422        .wrapping_add(bool3ary_202!(b, c, d))
423        .wrapping_add(t);
424    b = b.rotate_left(30);
425
426    d = d
427        .wrapping_add(e.rotate_left(5))
428        .wrapping_add(bool3ary_202!(a, b, c))
429        .wrapping_add(u);
430    a = a.rotate_left(30);
431
432    c = c
433        .wrapping_add(d.rotate_left(5))
434        .wrapping_add(bool3ary_202!(e, a, b))
435        .wrapping_add(v);
436    e = e.rotate_left(30);
437
438    b = b
439        .wrapping_add(c.rotate_left(5))
440        .wrapping_add(bool3ary_202!(d, e, a))
441        .wrapping_add(w);
442    d = d.rotate_left(30);
443
444    u32x4(b, c, d, e)
445}
446
447/// Not an intrinsic, but helps emulate `llvm.x86.sha1rnds4` intrinsic.
448fn sha1rnds4p(abcd: u32x4, msg: u32x4) -> u32x4 {
449    let u32x4(mut a, mut b, mut c, mut d) = abcd;
450    let u32x4(t, u, v, w) = msg;
451    let mut e = 0u32;
452
453    macro_rules! bool3ary_150 {
454        ($a:expr, $b:expr, $c:expr) => {
455            ($a ^ $b ^ $c)
456        };
457    } // Parity, XOR, MD5H, SHA1P
458
459    e = e
460        .wrapping_add(a.rotate_left(5))
461        .wrapping_add(bool3ary_150!(b, c, d))
462        .wrapping_add(t);
463    b = b.rotate_left(30);
464
465    d = d
466        .wrapping_add(e.rotate_left(5))
467        .wrapping_add(bool3ary_150!(a, b, c))
468        .wrapping_add(u);
469    a = a.rotate_left(30);
470
471    c = c
472        .wrapping_add(d.rotate_left(5))
473        .wrapping_add(bool3ary_150!(e, a, b))
474        .wrapping_add(v);
475    e = e.rotate_left(30);
476
477    b = b
478        .wrapping_add(c.rotate_left(5))
479        .wrapping_add(bool3ary_150!(d, e, a))
480        .wrapping_add(w);
481    d = d.rotate_left(30);
482
483    u32x4(b, c, d, e)
484}
485
486/// Not an intrinsic, but helps emulate `llvm.x86.sha1rnds4` intrinsic.
487fn sha1rnds4m(abcd: u32x4, msg: u32x4) -> u32x4 {
488    let u32x4(mut a, mut b, mut c, mut d) = abcd;
489    let u32x4(t, u, v, w) = msg;
490    let mut e = 0u32;
491
492    macro_rules! bool3ary_232 {
493        ($a:expr, $b:expr, $c:expr) => {
494            ($a & $b) ^ ($a & $c) ^ ($b & $c)
495        };
496    } // Majority, SHA1M
497
498    e = e
499        .wrapping_add(a.rotate_left(5))
500        .wrapping_add(bool3ary_232!(b, c, d))
501        .wrapping_add(t);
502    b = b.rotate_left(30);
503
504    d = d
505        .wrapping_add(e.rotate_left(5))
506        .wrapping_add(bool3ary_232!(a, b, c))
507        .wrapping_add(u);
508    a = a.rotate_left(30);
509
510    c = c
511        .wrapping_add(d.rotate_left(5))
512        .wrapping_add(bool3ary_232!(e, a, b))
513        .wrapping_add(v);
514    e = e.rotate_left(30);
515
516    b = b
517        .wrapping_add(c.rotate_left(5))
518        .wrapping_add(bool3ary_232!(d, e, a))
519        .wrapping_add(w);
520    d = d.rotate_left(30);
521
522    u32x4(b, c, d, e)
523}
524
525impl Sha1State {
526    fn process(&mut self, block: &[u8; 64]) {
527        let mut words = [0u32; 16];
528        for (i, word) in words.iter_mut().enumerate() {
529            let off = i * 4;
530            *word = (block[off + 3] as u32)
531                | ((block[off + 2] as u32) << 8)
532                | ((block[off + 1] as u32) << 16)
533                | ((block[off] as u32) << 24);
534        }
535        macro_rules! schedule {
536            ($v0:expr, $v1:expr, $v2:expr, $v3:expr) => {
537                sha1msg2(sha1msg1($v0, $v1) ^ $v2, $v3)
538            };
539        }
540
541        macro_rules! rounds4 {
542            ($h0:ident, $h1:ident, $wk:expr, $i:expr) => {
543                sha1_digest_round_x4($h0, sha1_first_half($h1, $wk), $i)
544            };
545        }
546
547        // Rounds 0..20
548        let mut h0 = u32x4(self.state[0], self.state[1], self.state[2], self.state[3]);
549        let mut w0 = u32x4(words[0], words[1], words[2], words[3]);
550        let mut h1 = sha1_digest_round_x4(h0, sha1_first_add(self.state[4], w0), 0);
551        let mut w1 = u32x4(words[4], words[5], words[6], words[7]);
552        h0 = rounds4!(h1, h0, w1, 0);
553        let mut w2 = u32x4(words[8], words[9], words[10], words[11]);
554        h1 = rounds4!(h0, h1, w2, 0);
555        let mut w3 = u32x4(words[12], words[13], words[14], words[15]);
556        h0 = rounds4!(h1, h0, w3, 0);
557        let mut w4 = schedule!(w0, w1, w2, w3);
558        h1 = rounds4!(h0, h1, w4, 0);
559
560        // Rounds 20..40
561        w0 = schedule!(w1, w2, w3, w4);
562        h0 = rounds4!(h1, h0, w0, 1);
563        w1 = schedule!(w2, w3, w4, w0);
564        h1 = rounds4!(h0, h1, w1, 1);
565        w2 = schedule!(w3, w4, w0, w1);
566        h0 = rounds4!(h1, h0, w2, 1);
567        w3 = schedule!(w4, w0, w1, w2);
568        h1 = rounds4!(h0, h1, w3, 1);
569        w4 = schedule!(w0, w1, w2, w3);
570        h0 = rounds4!(h1, h0, w4, 1);
571
572        // Rounds 40..60
573        w0 = schedule!(w1, w2, w3, w4);
574        h1 = rounds4!(h0, h1, w0, 2);
575        w1 = schedule!(w2, w3, w4, w0);
576        h0 = rounds4!(h1, h0, w1, 2);
577        w2 = schedule!(w3, w4, w0, w1);
578        h1 = rounds4!(h0, h1, w2, 2);
579        w3 = schedule!(w4, w0, w1, w2);
580        h0 = rounds4!(h1, h0, w3, 2);
581        w4 = schedule!(w0, w1, w2, w3);
582        h1 = rounds4!(h0, h1, w4, 2);
583
584        // Rounds 60..80
585        w0 = schedule!(w1, w2, w3, w4);
586        h0 = rounds4!(h1, h0, w0, 3);
587        w1 = schedule!(w2, w3, w4, w0);
588        h1 = rounds4!(h0, h1, w1, 3);
589        w2 = schedule!(w3, w4, w0, w1);
590        h0 = rounds4!(h1, h0, w2, 3);
591        w3 = schedule!(w4, w0, w1, w2);
592        h1 = rounds4!(h0, h1, w3, 3);
593        w4 = schedule!(w0, w1, w2, w3);
594        h0 = rounds4!(h1, h0, w4, 3);
595
596        let e = sha1_first(h1).rotate_left(30);
597        let u32x4(a, b, c, d) = h0;
598
599        self.state[0] = self.state[0].wrapping_add(a);
600        self.state[1] = self.state[1].wrapping_add(b);
601        self.state[2] = self.state[2].wrapping_add(c);
602        self.state[3] = self.state[3].wrapping_add(d);
603        self.state[4] = self.state[4].wrapping_add(e);
604    }
605}
606
607impl PartialEq for Blocks {
608    fn eq(&self, other: &Blocks) -> bool {
609        (self.len, &self.block[..]).eq(&(other.len, &other.block[..]))
610    }
611}
612
613impl Ord for Blocks {
614    fn cmp(&self, other: &Blocks) -> cmp::Ordering {
615        (self.len, &self.block[..]).cmp(&(other.len, &other.block[..]))
616    }
617}
618
619impl PartialOrd for Blocks {
620    fn partial_cmp(&self, other: &Blocks) -> Option<cmp::Ordering> {
621        Some(self.cmp(other))
622    }
623}
624
625impl Eq for Blocks {}
626
627impl hash::Hash for Blocks {
628    fn hash<H: hash::Hasher>(&self, state: &mut H) {
629        self.len.hash(state);
630        self.block.hash(state);
631    }
632}
633
634impl Clone for Blocks {
635    fn clone(&self) -> Blocks {
636        Blocks { ..*self }
637    }
638}
639
640/// Indicates that a digest couldn't be parsed.
641#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug)]
642pub struct DigestParseError(());
643
644impl fmt::Display for DigestParseError {
645    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
646        write!(f, "not a valid sha1 hash")
647    }
648}
649
650impl str::FromStr for Digest {
651    type Err = DigestParseError;
652
653    fn from_str(s: &str) -> Result<Digest, DigestParseError> {
654        if s.len() != 40 {
655            return Err(DigestParseError(()));
656        }
657        let mut rv: Digest = Default::default();
658        for idx in 0..5 {
659            rv.data.state[idx] = u32::from_str_radix(&s[idx * 8..idx * 8 + 8], 16)
660                .map_err(|_| DigestParseError(()))?;
661        }
662        Ok(rv)
663    }
664}
665
666impl fmt::Display for Digest {
667    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
668        for i in self.data.state.iter() {
669            write!(f, "{:08x}", i)?;
670        }
671        Ok(())
672    }
673}
674
675impl fmt::Debug for Digest {
676    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
677        write!(f, "Digest {{ \"{}\" }}", self)
678    }
679}