dcrypt_algorithms/hash/sha1/
mod.rs1use crate::error::{Error, Result};
8use crate::hash::{Hash, HashAlgorithm, HashFunction};
9use crate::types::Digest;
10use byteorder::{BigEndian, ByteOrder};
11use zeroize::Zeroize;
12
13#[cfg(not(feature = "std"))]
14use alloc::vec::Vec;
15
16const SHA1_BLOCK_SIZE: usize = 64;
17const SHA1_OUTPUT_SIZE: usize = 20;
18
19const H0: [u32; 5] = [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0];
21
22pub enum Sha1Algorithm {}
24
25impl HashAlgorithm for Sha1Algorithm {
26 const OUTPUT_SIZE: usize = SHA1_OUTPUT_SIZE;
27 const BLOCK_SIZE: usize = SHA1_BLOCK_SIZE;
28 const ALGORITHM_ID: &'static str = "SHA-1";
29}
30
31#[derive(Clone, Zeroize)]
33pub struct Sha1 {
34 h: [u32; 5],
36 buffer: [u8; SHA1_BLOCK_SIZE],
38 buffer_len: usize,
40 total_len: u64,
42}
43
44impl Sha1 {
45 pub fn new() -> Self {
47 Self {
48 h: H0,
49 buffer: [0u8; SHA1_BLOCK_SIZE],
50 buffer_len: 0,
51 total_len: 0,
52 }
53 }
54
55 fn process_block(&mut self, block: &[u8; SHA1_BLOCK_SIZE]) {
57 let mut w = [0u32; 80];
58 for i in 0..16 {
60 w[i] = BigEndian::read_u32(&block[i * 4..]);
61 }
62 for i in 16..80 {
63 w[i] = (w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]).rotate_left(1);
64 }
65 let mut a = self.h[0];
67 let mut b = self.h[1];
68 let mut c = self.h[2];
69 let mut d = self.h[3];
70 let mut e = self.h[4];
71 for (i, &word) in w.iter().enumerate().take(80) {
73 let (f, k) = if i < 20 {
74 ((b & c) | ((!b) & d), 0x5A827999)
75 } else if i < 40 {
76 (b ^ c ^ d, 0x6ED9EBA1)
77 } else if i < 60 {
78 ((b & c) | (b & d) | (c & d), 0x8F1BBCDC)
79 } else {
80 (b ^ c ^ d, 0xCA62C1D6)
81 };
82 let temp = a
83 .rotate_left(5)
84 .wrapping_add(f)
85 .wrapping_add(e)
86 .wrapping_add(k)
87 .wrapping_add(word);
88 e = d;
89 d = c;
90 c = b.rotate_left(30);
91 b = a;
92 a = temp;
93 }
94 self.h[0] = self.h[0].wrapping_add(a);
96 self.h[1] = self.h[1].wrapping_add(b);
97 self.h[2] = self.h[2].wrapping_add(c);
98 self.h[3] = self.h[3].wrapping_add(d);
99 self.h[4] = self.h[4].wrapping_add(e);
100 }
101
102 fn update_internal(&mut self, data: &[u8]) -> Result<()> {
104 let mut data_idx = 0;
105
106 let new_bits = (data.len() as u64).wrapping_mul(8);
108 self.total_len = self
109 .total_len
110 .checked_add(new_bits)
111 .ok_or(Error::Processing {
112 operation: "SHA-1",
113 details: "Message length overflow",
114 })?;
115
116 if self.buffer_len > 0 {
117 let copy_len = core::cmp::min(SHA1_BLOCK_SIZE - self.buffer_len, data.len());
118 self.buffer[self.buffer_len..self.buffer_len + copy_len]
119 .copy_from_slice(&data[..copy_len]);
120 self.buffer_len += copy_len;
121 data_idx += copy_len;
122
123 if self.buffer_len == SHA1_BLOCK_SIZE {
124 let mut block = [0u8; SHA1_BLOCK_SIZE];
125 block.copy_from_slice(&self.buffer);
126 self.process_block(&block);
127 self.buffer_len = 0;
128 }
129 }
130
131 while data_idx + SHA1_BLOCK_SIZE <= data.len() {
132 let mut block = [0u8; SHA1_BLOCK_SIZE];
133 block.copy_from_slice(&data[data_idx..data_idx + SHA1_BLOCK_SIZE]);
134 self.process_block(&block);
135 data_idx += SHA1_BLOCK_SIZE;
136 }
137
138 if data_idx < data.len() {
139 let remaining = data.len() - data_idx;
140 self.buffer[..remaining].copy_from_slice(&data[data_idx..]);
141 self.buffer_len = remaining;
142 }
143
144 Ok(())
145 }
146
147 fn finalize_internal(&mut self) -> Result<Hash> {
149 let mut buffer = [0u8; SHA1_BLOCK_SIZE];
151 let mut buffer_idx = self.buffer_len;
152
153 buffer[..self.buffer_len].copy_from_slice(&self.buffer[..self.buffer_len]);
154 buffer[buffer_idx] = 0x80;
155 buffer_idx += 1;
156
157 if buffer_idx > SHA1_BLOCK_SIZE - 8 {
158 for byte in &mut buffer[buffer_idx..] {
159 *byte = 0;
160 }
161 self.process_block(&buffer);
162 buffer_idx = 0;
163 }
164
165 for byte in &mut buffer[buffer_idx..SHA1_BLOCK_SIZE - 8] {
166 *byte = 0;
167 }
168
169 BigEndian::write_u64(&mut buffer[SHA1_BLOCK_SIZE - 8..], self.total_len);
170 self.process_block(&buffer);
171
172 let mut result = Vec::with_capacity(SHA1_OUTPUT_SIZE);
173 for &word in &self.h {
174 result.extend_from_slice(&word.to_be_bytes());
175 }
176 Ok(result)
177 }
178}
179
180impl Default for Sha1 {
181 fn default() -> Self {
182 Self::new()
183 }
184}
185
186impl HashFunction for Sha1 {
187 type Algorithm = Sha1Algorithm;
188 type Output = Digest<SHA1_OUTPUT_SIZE>;
189
190 fn new() -> Self {
191 Sha1::new()
192 }
193
194 fn update(&mut self, data: &[u8]) -> Result<&mut Self> {
195 self.update_internal(data)?;
196 Ok(self)
197 }
198
199 fn finalize(&mut self) -> Result<Self::Output> {
200 let hash = self.finalize_internal()?;
201 let mut digest = [0u8; SHA1_OUTPUT_SIZE];
202 digest.copy_from_slice(&hash);
203 Ok(Digest::new(digest))
204 }
205
206 fn output_size() -> usize {
207 Self::Algorithm::OUTPUT_SIZE
208 }
209
210 fn block_size() -> usize {
211 Self::Algorithm::BLOCK_SIZE
212 }
213
214 fn name() -> String {
215 Self::Algorithm::ALGORITHM_ID.to_string()
216 }
217}
218
219#[cfg(test)]
220mod tests;