crypto_async_rs/
sha256.rs

1use futures::io::{AsyncRead, AsyncReadExt};
2
3const K: [u32; 64] = [
4    0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
5    0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
6    0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
7    0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
8    0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
9    0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
10    0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
11    0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
12];
13
14const H: [u32; 8] = [
15    0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
16];
17
18const ZERO_BUFFER: [u8; 64] = [0; 64];
19
20pub fn encode(bytes: &[u8]) -> [u8; 32] {
21    let h: [u32; 8] = encode_core(bytes, H);
22    let mut hh: [u8; 32] = [0; 32];
23    for i in 0..8 {
24        let start_index = i << 2;
25        hh[start_index..start_index + 4].copy_from_slice(&h[i].to_be_bytes());
26    }
27
28    hh
29}
30
31pub async fn encode_async<R>(mut reader: R) -> Result<[u8; 32], std::io::Error>
32where
33    R: AsyncRead + Unpin,
34{
35    let mut h = H;
36    let mut buffer = [0u8; 64];
37    let mut buffer_len = 0;
38    let mut total_length = 0;
39
40    loop {
41        let bytes_read = reader.read(&mut buffer[buffer_len..]).await?;
42        if bytes_read == 0 {
43            break;
44        }
45        
46        buffer_len += bytes_read;
47        total_length += bytes_read;
48
49        if buffer_len == 64 {
50            let result = process_chunk(&buffer[..64], &h);
51            for i in 0..8 {
52                h[i] = h[i].wrapping_add(result[i]);
53            }
54            buffer_len = 0;
55        }
56    }
57
58    let final_chunk2 = 
59        get_final_chunks_sha(&mut buffer, total_length, buffer_len);
60    let result = process_chunk(&buffer, &h);
61    for i in 0..8 {
62        h[i] = h[i].wrapping_add(result[i]);
63    }
64    if let Some(chunk2) = final_chunk2 {
65        let result = process_chunk(&chunk2, &h);
66        for i in 0..8 {
67            h[i] = h[i].wrapping_add(result[i]);
68        }
69    }
70
71    let mut hh: [u8; 32] = [0; 32];
72    for i in 0..8 {
73        let start_index = i << 2;
74        hh[start_index..start_index + 4].copy_from_slice(&h[i].to_be_bytes());
75    }
76
77    Ok(hh)
78}
79
80
81pub(crate) fn encode_core(bytes: &[u8], mut h: [u32; 8]) -> [u32; 8] {
82    let bytes = get_normalized_message_bytes(bytes);
83    //break message into 512 - bit chunks (64 bytes = 2^6)
84    for chunk_num in 0..(bytes.len() >> 6) {
85        //break chunk into sixteen 32 - bit big - endian words
86        let chunk_start_index = chunk_num << 6;
87        let chunk: &[u8] = &bytes[chunk_start_index..chunk_start_index + 64];
88
89        let result = process_chunk(chunk, &h);
90        for i in 0..8 {
91            h[i] = h[i].wrapping_add(result[i]);
92        }
93    }
94    h
95}
96
97///begin with the original message of length L bits
98///append a single '1' bit
99///append K '0' bits, where K is the minimum number >= 0 such that L + 1 + K + 64 is a multiple of 512
100///append L as a 64-bit big-endian integer, making the total post-processed length a multiple of 512 bits
101fn get_normalized_message_bytes(bytes: &[u8]) -> Vec<u8> {
102    let message_length: u64 = bytes.len() as u64;
103    let message_bit_length: u64 = message_length << 3;
104    let zero_bytes_len = (message_length + 9) % 64;
105    let mut bytes: Vec<u8> = bytes.to_vec();
106    bytes.push(0x80);
107
108    if zero_bytes_len > 0 {
109        for _ in 0..64 - zero_bytes_len {
110            bytes.push(0);
111        }
112    }
113
114    bytes.extend_from_slice(&message_bit_length.to_be_bytes());
115    bytes
116}
117
118pub(crate) fn process_chunk(chunk: &[u8], vars: &[u32]) -> [u32; 8] {
119    let mut chunk_u32 = [0u32; 16];
120    for (i, chunk_bytes) in chunk.chunks_exact(4).enumerate() {
121            let chunk: [u8; 4] = chunk_bytes.try_into().unwrap();
122            chunk_u32[i] = u32::from_be_bytes(chunk);
123    }
124    
125    let mut a: u32 = vars[0];
126    let mut b: u32 = vars[1];
127    let mut c: u32 = vars[2];
128    let mut d: u32 = vars[3];
129    let mut e: u32 = vars[4];
130    let mut f: u32 = vars[5];
131    let mut g: u32 = vars[6];
132    let mut h: u32 = vars[7];
133
134    let mut w: [u32; 64] = [0; 64];
135    w[0..16].copy_from_slice(&chunk_u32);
136    for num in 16..64 {
137        let s0 = w[num - 15];
138        let s1 = w[num - 2];
139        let sigma0 = s0.rotate_right(7) ^ s0.rotate_right(18) ^ (s0 >> 3);
140        let sigma1 = s1.rotate_right(17) ^ s1.rotate_right(19) ^ (s1 >> 10);
141
142        w[num] = w[num - 16]
143            .wrapping_add(sigma0)
144            .wrapping_add(w[num - 7])
145            .wrapping_add(sigma1);
146    }
147
148    for num in 0..64 {
149        let ch = g ^ (e & (f ^ g));
150        let sigma1 = e.rotate_right(6) ^ e.rotate_right(11) ^ e.rotate_right(25);
151        let temp1 = h.wrapping_add(sigma1).wrapping_add(ch).wrapping_add(K[num]).wrapping_add(w[num]);
152        let maj = (a & b) ^ (c & (a ^ b));
153        let sigma0 = a.rotate_right(2) ^ a.rotate_right(13) ^ a.rotate_right(22);
154        let temp2 = sigma0.wrapping_add(maj);
155
156        h = g;
157        g = f;
158        f = e;
159        e = d.wrapping_add(temp1);
160        d = c;
161        c = b;
162        b = a;
163        a = temp1.wrapping_add(temp2);
164    }
165
166    [a, b, c, d, e, f, g, h]
167}
168
169pub(crate) fn get_final_chunks_sha(chunk1: &mut [u8; 64], total_len: usize, partial_data_len: usize) -> Option<[u8; 64]> {
170    let total= total_len << 3;
171    let mut full_padded_length = total + 1 + 64;
172    full_padded_length += 512 - (full_padded_length % 512);
173    chunk1[partial_data_len] = 0x80;
174    chunk1[partial_data_len + 1..].copy_from_slice(&ZERO_BUFFER[..64 - partial_data_len - 1]);
175    let two_chunks = full_padded_length - total > 512;
176    if two_chunks {
177        let mut chunk2 = [0u8; 64];
178        chunk2[56..].copy_from_slice(&(total as u64).to_be_bytes());
179        Some(chunk2)
180    } else {
181        chunk1[56..].copy_from_slice(&(total as u64).to_be_bytes());
182        None
183    }
184}
185
186#[cfg(test)]
187mod tests {
188    use super::*;
189
190    #[tokio::test]
191    async fn test_encode_empty_string() {
192        let result = encode_async("".as_bytes()).await.unwrap();
193        assert_eq!(
194            result,
195            [
196                0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f,
197                0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b,
198                0x78, 0x52, 0xb8, 0x55
199            ]
200        );
201    }
202
203    #[tokio::test]
204    async fn test_encode_abc() {
205        let result = encode_async("abc".as_bytes()).await.unwrap();
206        assert_eq!(
207            result,
208            [
209                0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae,
210                0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61,
211                0xf2, 0x00, 0x15, 0xad
212            ]
213        );
214    }
215
216    #[tokio::test]
217    async fn test_encode_message_digest() {
218        let result = encode_async("message digest".as_bytes()).await.unwrap();
219        assert_eq!(
220            result,
221            [
222                0xf7, 0x84, 0x6f, 0x55, 0xcf, 0x23, 0xe1, 0x4e, 0xeb, 0xea, 0xb5, 0xb4, 0xe1, 0x55,
223                0x0c, 0xad, 0x5b, 0x50, 0x9e, 0x33, 0x48, 0xfb, 0xc4, 0xef, 0xa3, 0xa1, 0x41, 0x3d,
224                0x39, 0x3c, 0xb6, 0x50
225            ]
226        );
227    }
228
229    #[tokio::test]
230    async fn test_encode_abcdefghijklmnopqrstuvwxyz() {
231        let result = encode_async("abcdefghijklmnopqrstuvwxyz".as_bytes()).await.unwrap();
232        assert_eq!(
233            result,
234            [
235                0x71, 0xc4, 0x80, 0xdf, 0x93, 0xd6, 0xae, 0x2f, 0x1e, 0xfa, 0xd1, 0x44, 0x7c, 0x66,
236                0xc9, 0x52, 0x5e, 0x31, 0x62, 0x18, 0xcf, 0x51, 0xfc, 0x8d, 0x9e, 0xd8, 0x32, 0xf2,
237                0xda, 0xf1, 0x8b, 0x73
238            ]
239        );
240    }
241
242    #[tokio::test]
243    async fn test_encode_alphanumeric_string() {
244        let result = encode_async("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".as_bytes()).await.unwrap();
245        assert_eq!(
246            result,
247            [
248                0xdb, 0x4b, 0xfc, 0xbd, 0x4d, 0xa0, 0xcd, 0x85, 0xa6, 0x0c, 0x3c, 0x37, 0xd3, 0xfb,
249                0xd8, 0x80, 0x5c, 0x77, 0xf1, 0x5f, 0xc6, 0xb1, 0xfd, 0xfe, 0x61, 0x4e, 0xe0, 0xa7,
250                0xc8, 0xfd, 0xb4, 0xc0
251            ]
252        );
253    }
254
255    #[tokio::test]
256    async fn test_encode_12345() {
257        let result = encode_async("12345".as_bytes()).await.unwrap();
258        assert_eq!(
259            result,
260            [
261                0x59, 0x94, 0x47, 0x1a, 0xbb, 0x01, 0x11, 0x2a, 0xfc, 0xc1, 0x81, 0x59, 0xf6, 0xcc,
262                0x74, 0xb4, 0xf5, 0x11, 0xb9, 0x98, 0x06, 0xda, 0x59, 0xb3, 0xca, 0xf5, 0xa9, 0xc1,
263                0x73, 0xca, 0xcf, 0xc5
264            ]
265        );
266    }
267
268    #[tokio::test]
269    async fn test_encode_2() {
270        let text: &[u8] = &[
271            0xcd, 0xa9, 0xfe, 0x30, 0xbf, 0x85, 0x93, 0xe6, 0x1a, 0x05, 0x12, 0x0d, 0xc0, 0xac,
272            0x2d, 0x2d, 0x16, 0x46, 0x63, 0xbe, 0x91, 0xa2, 0x06, 0x7c, 0x58, 0x47, 0x16, 0x23,
273            0x68, 0xe9, 0x22, 0xac, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
274            0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
275            0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x20, 0x12, 0x74, 0x6c, 0x73,
276            0x31, 0x33, 0x20, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31,
277            0x32, 0x20, 0xda, 0x75, 0xce, 0x11, 0x39, 0xac, 0x80, 0xda, 0xe4, 0x04, 0x4d, 0xa9,
278            0x32, 0x35, 0x0c, 0xf6, 0x5c, 0x97, 0xcc, 0xc9, 0xe3, 0x3f, 0x1e, 0x6f, 0x7d, 0x2d,
279            0x4b, 0x18, 0xb7, 0x36, 0xff, 0xd5, 0x01,
280        ];
281        let expected: &[u8] = &[
282            0x60, 0x68, 0x8e, 0xe8, 0x0c, 0x78, 0x8c, 0x98, 0xb5, 0xb7, 0x95, 0x6b, 0x93, 0x19,
283            0x8e, 0x9d, 0x8a, 0x40, 0xa9, 0x66, 0xea, 0x70, 0xd3, 0x71, 0x98, 0x0e, 0xb3, 0x3b,
284            0x3f, 0x79, 0x2f, 0xa7,
285        ];
286        let result = encode_async(text).await.unwrap();
287        assert_eq!(&result, expected);
288    }
289
290
291}