1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
//! SHA-1  

//! https://www.cnblogs.com/mengsuenyan/p/12697811.html#toc  


use crate::sha::const_tables::{SHA1_DIGEST_WSIZE, SHA1_BLOCK_SIZE, SHA1_INIT, SHA1_DIGEST_SIZE};
use crate::Digest;

#[derive(Clone)]
pub struct SHA1 {
    pub(super) digest: [u32; SHA1_DIGEST_WSIZE],
    pub(super) buf: [u8; SHA1_BLOCK_SIZE],
    pub(super) idx: usize,
    pub(super) len: usize,
    pub(super) is_checked: bool,
}

impl SHA1 {
    pub fn new() -> SHA1 {
        SHA1 {
            digest: SHA1_INIT,
            buf: [0u8; SHA1_BLOCK_SIZE],
            idx: 0,
            len: 0,
            is_checked: false,
        }
    }
}

impl Digest for SHA1 {
    fn block_size(&self) -> Option<usize> {
        Some(64)
    }

    fn bits_len(&self) -> usize {
        SHA1_DIGEST_SIZE << 3
    }

    fn write(&mut self, data: &[u8]) {
        let mut data = data;
        self.len += data.len();

        if self.idx > 0 {
            let min = std::cmp::min(SHA1_BLOCK_SIZE - self.idx, data.len());
            let dst = &mut self.buf[self.idx..(self.idx+min)];
            let src = &data[0..min];
            dst.copy_from_slice(src);
            self.idx += min;

            if self.idx == SHA1_BLOCK_SIZE {
                self.update(None);
                self.idx = 0;
            }

            data = &data[min..];
        }

        if data.len() > SHA1_BLOCK_SIZE {
            let n = data.len() & (!(SHA1_BLOCK_SIZE - 1));
            let data_block = &data[0..n];
            self.update(Some(data_block));
            data = &data[n..];
        }

        if data.len() > 0 {
            let dst = &mut self.buf[..data.len()];
            dst.copy_from_slice(data);
            self.idx += data.len();
        }

        self.is_checked = false;
    }

    fn checksum(&mut self, digest: &mut Vec<u8>) {
        if !self.is_checked {
            let mut tmp = [0u8; SHA1_BLOCK_SIZE];
            tmp[0] = 0x80;
            let len = self.len;
            if len % SHA1_BLOCK_SIZE < 56 {
                self.write(&tmp[0..(56-(len%SHA1_BLOCK_SIZE))]);
            } else {
                self.write(&tmp[0..(64+56-(len%SHA1_BLOCK_SIZE))]);
            }

            let len = (len as u64) << 3;
            let len_bytes = len.to_be_bytes();
            self.write(&len_bytes[..]);
            self.len = 0;
            self.is_checked = true;
        }

        digest.clear();
        self.digest.iter().for_each(|&e| {
            digest.extend(e.to_be_bytes().iter());
        });
    }

    fn reset(&mut self) {
        *self = SHA1::new();
    }
}