dcrypt_algorithms/hash/sha1/
mod.rs1use crate::error::{Error, Result};
8use crate::hash::{HashAlgorithm, HashFunction};
9use crate::types::Digest;
10use dcrypt_internal::zeroing::{Zeroize, ZeroizeOnDrop, Zeroizing};
11
12#[cfg(feature = "alloc")]
13use crate::alloc_prelude::*;
14
15const SHA1_BLOCK_SIZE: usize = 64;
16const SHA1_OUTPUT_SIZE: usize = 20;
17
18const H0: [u32; 5] = [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0];
20
21pub enum Sha1Algorithm {}
23
24impl HashAlgorithm for Sha1Algorithm {
25 const OUTPUT_SIZE: usize = SHA1_OUTPUT_SIZE;
26 const BLOCK_SIZE: usize = SHA1_BLOCK_SIZE;
27 const ALGORITHM_ID: &'static str = "SHA-1";
28}
29
30#[derive(Clone)]
32pub struct Sha1 {
33 h: [u32; 5],
35 buffer: [u8; SHA1_BLOCK_SIZE],
37 buffer_len: usize,
39 total_len: u64,
41}
42
43impl Zeroize for Sha1 {
44 fn zeroize(&mut self) {
45 self.h.zeroize();
46 self.buffer.zeroize();
47 self.buffer_len.zeroize();
48 self.total_len.zeroize();
49 }
50}
51
52impl Drop for Sha1 {
53 fn drop(&mut self) {
54 self.zeroize();
55 }
56}
57
58impl ZeroizeOnDrop for Sha1 {}
59
60impl Sha1 {
61 pub fn new() -> Self {
63 Self {
64 h: H0,
65 buffer: [0u8; SHA1_BLOCK_SIZE],
66 buffer_len: 0,
67 total_len: 0,
68 }
69 }
70
71 fn process_block(&mut self, block: &[u8; SHA1_BLOCK_SIZE]) {
73 let mut w = Zeroizing::new([0u32; 80]);
74 for i in 0..16 {
76 let start = i * 4;
77 w[i] = (u32::from(block[start]) << 24)
78 | (u32::from(block[start + 1]) << 16)
79 | (u32::from(block[start + 2]) << 8)
80 | u32::from(block[start + 3]);
81 }
82 for i in 16..80 {
83 w[i] = (w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]).rotate_left(1);
84 }
85 let mut a = self.h[0];
87 let mut b = self.h[1];
88 let mut c = self.h[2];
89 let mut d = self.h[3];
90 let mut e = self.h[4];
91 for (i, &word) in w.iter().enumerate().take(80) {
93 let (f, k) = if i < 20 {
94 ((b & c) | ((!b) & d), 0x5A827999)
95 } else if i < 40 {
96 (b ^ c ^ d, 0x6ED9EBA1)
97 } else if i < 60 {
98 ((b & c) | (b & d) | (c & d), 0x8F1BBCDC)
99 } else {
100 (b ^ c ^ d, 0xCA62C1D6)
101 };
102 let temp = a
103 .rotate_left(5)
104 .wrapping_add(f)
105 .wrapping_add(e)
106 .wrapping_add(k)
107 .wrapping_add(word);
108 e = d;
109 d = c;
110 c = b.rotate_left(30);
111 b = a;
112 a = temp;
113 }
114 self.h[0] = self.h[0].wrapping_add(a);
116 self.h[1] = self.h[1].wrapping_add(b);
117 self.h[2] = self.h[2].wrapping_add(c);
118 self.h[3] = self.h[3].wrapping_add(d);
119 self.h[4] = self.h[4].wrapping_add(e);
120 a.zeroize();
121 b.zeroize();
122 c.zeroize();
123 d.zeroize();
124 e.zeroize();
125 }
126
127 fn update_internal(&mut self, data: &[u8]) -> Result<()> {
129 let mut data_idx = 0;
130
131 let new_bits = (data.len() as u64).wrapping_mul(8);
133 self.total_len = self
134 .total_len
135 .checked_add(new_bits)
136 .ok_or(Error::Processing {
137 operation: "SHA-1",
138 details: "Message length overflow",
139 })?;
140
141 if self.buffer_len > 0 {
142 let copy_len = core::cmp::min(SHA1_BLOCK_SIZE - self.buffer_len, data.len());
143 self.buffer[self.buffer_len..self.buffer_len + copy_len]
144 .copy_from_slice(&data[..copy_len]);
145 self.buffer_len += copy_len;
146 data_idx += copy_len;
147
148 if self.buffer_len == SHA1_BLOCK_SIZE {
149 let mut block = Zeroizing::new([0u8; SHA1_BLOCK_SIZE]);
150 block.copy_from_slice(&self.buffer);
151 self.process_block(&block);
152 self.buffer.zeroize();
153 self.buffer_len = 0;
154 }
155 }
156
157 while data_idx + SHA1_BLOCK_SIZE <= data.len() {
158 let mut block = Zeroizing::new([0u8; SHA1_BLOCK_SIZE]);
159 block.copy_from_slice(&data[data_idx..data_idx + SHA1_BLOCK_SIZE]);
160 self.process_block(&block);
161 data_idx += SHA1_BLOCK_SIZE;
162 }
163
164 if data_idx < data.len() {
165 let remaining = data.len() - data_idx;
166 self.buffer[..remaining].copy_from_slice(&data[data_idx..]);
167 self.buffer_len = remaining;
168 }
169
170 Ok(())
171 }
172
173 fn finalize_internal(&mut self) -> Result<Zeroizing<[u8; SHA1_OUTPUT_SIZE]>> {
175 let mut buffer = Zeroizing::new([0u8; SHA1_BLOCK_SIZE]);
177 let mut buffer_idx = self.buffer_len;
178
179 buffer[..self.buffer_len].copy_from_slice(&self.buffer[..self.buffer_len]);
180 buffer[buffer_idx] = 0x80;
181 buffer_idx += 1;
182
183 if buffer_idx > SHA1_BLOCK_SIZE - 8 {
184 for byte in &mut buffer[buffer_idx..] {
185 *byte = 0;
186 }
187 self.process_block(&buffer);
188 buffer_idx = 0;
189 }
190
191 for byte in &mut buffer[buffer_idx..SHA1_BLOCK_SIZE - 8] {
192 *byte = 0;
193 }
194
195 for (index, byte) in buffer[SHA1_BLOCK_SIZE - 8..].iter_mut().enumerate() {
196 *byte = (self.total_len >> (56 - index * 8)) as u8;
197 }
198 self.process_block(&buffer);
199
200 let mut result = Zeroizing::new([0u8; SHA1_OUTPUT_SIZE]);
201 for (word_index, &word) in self.h.iter().enumerate() {
202 for byte in 0..4 {
203 result[word_index * 4 + byte] = (word >> (24 - byte * 8)) as u8;
204 }
205 }
206 self.zeroize();
207 Ok(result)
208 }
209}
210
211impl Default for Sha1 {
212 fn default() -> Self {
213 Self::new()
214 }
215}
216
217impl HashFunction for Sha1 {
218 type Algorithm = Sha1Algorithm;
219 type Output = Digest<SHA1_OUTPUT_SIZE>;
220
221 fn new() -> Self {
222 Sha1::new()
223 }
224
225 fn update(&mut self, data: &[u8]) -> Result<&mut Self> {
226 self.update_internal(data)?;
227 Ok(self)
228 }
229
230 fn finalize(&mut self) -> Result<Self::Output> {
231 let hash = self.finalize_internal()?;
232 let mut digest = Digest::<SHA1_OUTPUT_SIZE>::zeroed();
233 digest.as_mut().copy_from_slice(&hash[..]);
234 Ok(digest)
235 }
236
237 fn output_size() -> usize {
238 Self::Algorithm::OUTPUT_SIZE
239 }
240
241 fn block_size() -> usize {
242 Self::Algorithm::BLOCK_SIZE
243 }
244
245 fn name() -> String {
246 Self::Algorithm::ALGORITHM_ID.to_string()
247 }
248}
249
250#[cfg(test)]
251mod tests;