1pub fn sha1(data: &[u8]) -> [u8; 20] {
3 let mut h0: u32 = 0x67452301;
4 let mut h1: u32 = 0xEFCDAB89;
5 let mut h2: u32 = 0x98BADCFE;
6 let mut h3: u32 = 0x10325476;
7 let mut h4: u32 = 0xC3D2E1F0;
8
9 let bit_len = (data.len() as u64) * 8;
10
11 let mut padded = data.to_vec();
13 padded.push(0x80);
14 while (padded.len() % 64) != 56 {
15 padded.push(0);
16 }
17 padded.extend_from_slice(&bit_len.to_be_bytes());
18
19 for chunk in padded.chunks_exact(64) {
20 let mut w = [0u32; 80];
21 for i in 0..16 {
22 w[i] = u32::from_be_bytes([
23 chunk[i * 4],
24 chunk[i * 4 + 1],
25 chunk[i * 4 + 2],
26 chunk[i * 4 + 3],
27 ]);
28 }
29 for i in 16..80 {
30 w[i] = (w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]).rotate_left(1);
31 }
32
33 let (mut a, mut b, mut c, mut d, mut e) = (h0, h1, h2, h3, h4);
34
35 for i in 0..80 {
36 let (f, k) = match i {
37 0..=19 => ((b & c) | ((!b) & d), 0x5A827999u32),
38 20..=39 => (b ^ c ^ d, 0x6ED9EBA1u32),
39 40..=59 => ((b & c) | (b & d) | (c & d), 0x8F1BBCDCu32),
40 _ => (b ^ c ^ d, 0xCA62C1D6u32),
41 };
42 let temp = a
43 .rotate_left(5)
44 .wrapping_add(f)
45 .wrapping_add(e)
46 .wrapping_add(k)
47 .wrapping_add(w[i]);
48 e = d;
49 d = c;
50 c = b.rotate_left(30);
51 b = a;
52 a = temp;
53 }
54
55 h0 = h0.wrapping_add(a);
56 h1 = h1.wrapping_add(b);
57 h2 = h2.wrapping_add(c);
58 h3 = h3.wrapping_add(d);
59 h4 = h4.wrapping_add(e);
60 }
61
62 let mut out = [0u8; 20];
63 out[0..4].copy_from_slice(&h0.to_be_bytes());
64 out[4..8].copy_from_slice(&h1.to_be_bytes());
65 out[8..12].copy_from_slice(&h2.to_be_bytes());
66 out[12..16].copy_from_slice(&h3.to_be_bytes());
67 out[16..20].copy_from_slice(&h4.to_be_bytes());
68 out
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74 use crate::encode::to_hex;
75
76 #[test]
77 fn sha1_empty() {
78 let hash = sha1(b"");
79 assert_eq!(to_hex(&hash), "da39a3ee5e6b4b0d3255bfef95601890afd80709");
80 }
81
82 #[test]
83 fn sha1_abc() {
84 let hash = sha1(b"abc");
85 assert_eq!(to_hex(&hash), "a9993e364706816aba3e25717850c26c9cd0d89d");
86 }
87
88 #[test]
89 fn sha1_fox() {
90 let hash = sha1(b"The quick brown fox jumps over the lazy dog");
91 assert_eq!(to_hex(&hash), "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12");
92 }
93
94 #[test]
95 fn sha1_websocket_accept() {
96 let key = "dGhlIHNhbXBsZSBub25jZQ==";
98 let magic = "258EAFA5-E914-47DA-95CA-5AB5DC11D045";
99 let combined = format!("{}{}", key, magic);
100 let hash = sha1(combined.as_bytes());
101 assert_eq!(to_hex(&hash), "47255391f6ef808bbebc064b6eecf285b72b1ffd");
102 let accept = crate::encode::to_base64(&hash);
103 assert_eq!(accept, "RyVTkfbvgIu+vAZLbuzyhbcrH/0=");
104 }
105}