dumb_crypto/
sha256.rs

1//! # SHA256
2//!
3//! Implementation of SHA256 digest according to [RFC 6234][rfc].
4//!
5//! [rfc]: https://tools.ietf.org/html/rfc6234#section-5.1
6//!
7
8/// Length of digest array
9pub const DIGEST_SIZE: usize = 32;
10
11/// Internal block size
12pub const BLOCK_SIZE: usize = 64;
13
14// See: https://tools.ietf.org/html/rfc6234#section-5.1
15const K: [u32; 64] = [
16    0x428a_2f98,
17    0x7137_4491,
18    0xb5c0_fbcf,
19    0xe9b5_dba5,
20    0x3956_c25b,
21    0x59f1_11f1,
22    0x923f_82a4,
23    0xab1c_5ed5,
24    0xd807_aa98,
25    0x1283_5b01,
26    0x2431_85be,
27    0x550c_7dc3,
28    0x72be_5d74,
29    0x80de_b1fe,
30    0x9bdc_06a7,
31    0xc19b_f174,
32    0xe49b_69c1,
33    0xefbe_4786,
34    0x0fc1_9dc6,
35    0x240c_a1cc,
36    0x2de9_2c6f,
37    0x4a74_84aa,
38    0x5cb0_a9dc,
39    0x76f9_88da,
40    0x983e_5152,
41    0xa831_c66d,
42    0xb003_27c8,
43    0xbf59_7fc7,
44    0xc6e0_0bf3,
45    0xd5a7_9147,
46    0x06ca_6351,
47    0x1429_2967,
48    0x27b7_0a85,
49    0x2e1b_2138,
50    0x4d2c_6dfc,
51    0x5338_0d13,
52    0x650a_7354,
53    0x766a_0abb,
54    0x81c2_c92e,
55    0x9272_2c85,
56    0xa2bf_e8a1,
57    0xa81a_664b,
58    0xc24b_8b70,
59    0xc76c_51a3,
60    0xd192_e819,
61    0xd699_0624,
62    0xf40e_3585,
63    0x106a_a070,
64    0x19a4_c116,
65    0x1e37_6c08,
66    0x2748_774c,
67    0x34b0_bcb5,
68    0x391c_0cb3,
69    0x4ed8_aa4a,
70    0x5b9c_ca4f,
71    0x682e_6ff3,
72    0x748f_82ee,
73    0x78a5_636f,
74    0x84c8_7814,
75    0x8cc7_0208,
76    0x90be_fffa,
77    0xa450_6ceb,
78    0xbef9_a3f7,
79    0xc671_78f2,
80];
81
82const H: [u32; 8] = [
83    0x6a09_e667,
84    0xbb67_ae85,
85    0x3c6e_f372,
86    0xa54f_f53a,
87    0x510e_527f,
88    0x9b05_688c,
89    0x1f83_d9ab,
90    0x5be0_cd19,
91];
92
93// CH( x, y, z) = (x AND y) XOR ( (NOT x) AND z)
94fn ch(x: u32, y: u32, z: u32) -> u32 {
95    (x & y) ^ ((!x) & z)
96}
97
98// MAJ( x, y, z) = (x AND y) XOR (x AND z) XOR (y AND z)
99fn maj(x: u32, y: u32, z: u32) -> u32 {
100    (x & y) ^ (x & z) ^ (y & z)
101}
102
103fn rotr(n: u32, s: u32) -> u32 {
104    (n << (32 - s)) | (n >> s)
105}
106
107// BSIG0(x) = ROTR^2(x) XOR ROTR^13(x) XOR ROTR^22(x)
108fn bsig0(x: u32) -> u32 {
109    rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22)
110}
111
112// BSIG1(x) = ROTR^6(x) XOR ROTR^11(x) XOR ROTR^25(x)
113fn bsig1(x: u32) -> u32 {
114    rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25)
115}
116
117// SSIG0(x) = ROTR^7(x) XOR ROTR^18(x) XOR SHR^3(x)
118fn ssig0(x: u32) -> u32 {
119    rotr(x, 7) ^ rotr(x, 18) ^ (x >> 3)
120}
121
122// SSIG1(x) = ROTR^17(x) XOR ROTR^19(x) XOR SHR^10(x)
123fn ssig1(x: u32) -> u32 {
124    rotr(x, 17) ^ rotr(x, 19) ^ (x >> 10)
125}
126
127fn fill_block(input: &[u8; BLOCK_SIZE], output: &mut [u32; BLOCK_SIZE / 4]) {
128    for i in 0..output.len() {
129        let i0 = u32::from(input[i * 4]);
130        let i1 = u32::from(input[i * 4 + 1]);
131        let i2 = u32::from(input[i * 4 + 2]);
132        let i3 = u32::from(input[i * 4 + 3]);
133
134        output[i] = (i0 << 24) | (i1 << 16) | (i2 << 8) | i3;
135    }
136}
137
138fn write_u64_be(data: &mut [u8], value: u64) {
139    data[0] = (value >> 56) as u8;
140    data[1] = (value >> 48) as u8;
141    data[2] = (value >> 40) as u8;
142    data[3] = (value >> 32) as u8;
143    data[4] = (value >> 24) as u8;
144    data[5] = (value >> 16) as u8;
145    data[6] = (value >> 8) as u8;
146    data[7] = (value) as u8;
147}
148
149///
150/// Main digest structure.
151///
152/// Usage:
153/// ```rust
154/// extern crate dumb_crypto;
155///
156/// use::dumb_crypto::sha256::SHA256;
157///
158/// let mut sha256 = SHA256::new();
159///
160/// sha256.update(b"hello world");
161/// assert_eq!(sha256.digest().to_vec(), vec![
162///     0xb9, 0x4d, 0x27, 0xb9, 0x93, 0x4d, 0x3e, 0x08,
163///     0xa5, 0x2e, 0x52, 0xd7, 0xda, 0x7d, 0xab, 0xfa,
164///     0xc4, 0x84, 0xef, 0xe3, 0x7a, 0x53, 0x80, 0xee,
165///     0x90, 0x88, 0xf7, 0xac, 0xe2, 0xef, 0xcd, 0xe9,
166/// ]);
167/// ```
168///
169pub struct SHA256 {
170    h: [u32; 8],
171    buffer: [u8; BLOCK_SIZE],
172    length: usize,
173}
174
175impl SHA256 {
176    ///
177    /// Create new instance of SHA256 digest.
178    ///
179    pub fn new() -> SHA256 {
180        SHA256 {
181            h: H,
182            buffer: [0; BLOCK_SIZE],
183            length: 0,
184        }
185    }
186
187    fn process_block(self: &mut SHA256, block: &[u32; 16]) {
188        //
189        //    1. Prepare the message schedule W:
190        //         For t = 0 to 15
191        //             Wt = M(i)t
192        //         For t = 16 to 63
193        //             Wt = SSIG1(W(t-2)) + W(t-7) + SSIG0(w(t-15)) + W(t-16)
194        //
195        let mut w: [u32; 64] = [0; 64];
196        let mut a: u32;
197        let mut b: u32;
198        let mut c: u32;
199        let mut d: u32;
200        let mut e: u32;
201        let mut f: u32;
202        let mut g: u32;
203        let mut h: u32;
204
205        w[..16].clone_from_slice(&block[..16]);
206
207        for t in 16..64 {
208            w[t] = wrapping_sum!(ssig1(w[t - 2]), w[t - 7], ssig0(w[t - 15]), w[t - 16]);
209        }
210
211        //
212        //    2. Initialize the working variables:
213        //         a = H(i-1)0
214        //         b = H(i-1)1
215        //         c = H(i-1)2
216        //         d = H(i-1)3
217        //         e = H(i-1)4
218        //         f = H(i-1)5
219        //         g = H(i-1)6
220        //         h = H(i-1)7
221        //
222        a = self.h[0];
223        b = self.h[1];
224        c = self.h[2];
225        d = self.h[3];
226        e = self.h[4];
227        f = self.h[5];
228        g = self.h[6];
229        h = self.h[7];
230
231        //
232        //    3. Perform the main hash computation:
233        //       For t = 0 to 63
234        //          T1 = h + BSIG1(e) + CH(e,f,g) + Kt + Wt
235        //          T2 = BSIG0(a) + MAJ(a,b,c)
236        //          h = g
237        //          g = f
238        //          f = e
239        //          e = d + T1
240        //          d = c
241        //          c = b
242        //          b = a
243        //          a = T1 + T2
244        //
245        for t in 0..64 {
246            let t1 = wrapping_sum!(h, bsig1(e), ch(e, f, g), K[t], w[t]);
247            let t2 = wrapping_sum!(bsig0(a), maj(a, b, c));
248            h = g;
249            g = f;
250            f = e;
251            e = wrapping_sum!(d, t1);
252            d = c;
253            c = b;
254            b = a;
255            a = wrapping_sum!(t1, t2);
256        }
257
258        //
259        //    4. Compute the intermediate hash value H(i)
260        //       H(i)0 = a + H(i-1)0
261        //       H(i)1 = b + H(i-1)1
262        //       H(i)2 = c + H(i-1)2
263        //       H(i)3 = d + H(i-1)3
264        //       H(i)4 = e + H(i-1)4
265        //       H(i)5 = f + H(i-1)5
266        //       H(i)6 = g + H(i-1)6
267        //       H(i)7 = h + H(i-1)7
268        //
269        self.h[0] = wrapping_sum!(self.h[0], a);
270        self.h[1] = wrapping_sum!(self.h[1], b);
271        self.h[2] = wrapping_sum!(self.h[2], c);
272        self.h[3] = wrapping_sum!(self.h[3], d);
273        self.h[4] = wrapping_sum!(self.h[4], e);
274        self.h[5] = wrapping_sum!(self.h[5], f);
275        self.h[6] = wrapping_sum!(self.h[6], g);
276        self.h[7] = wrapping_sum!(self.h[7], h);
277    }
278
279    ///
280    /// Add input `data` to the digest.
281    ///
282    pub fn update(self: &mut SHA256, data: &[u8]) {
283        let mut block: [u32; BLOCK_SIZE / 4] = [0; BLOCK_SIZE / 4];
284
285        for &b in data {
286            let off = self.length % BLOCK_SIZE;
287
288            // Fill the buffer
289            self.buffer[off] = b;
290            self.length += 1;
291
292            if self.length % BLOCK_SIZE != 0 {
293                continue;
294            }
295
296            fill_block(&self.buffer, &mut block);
297            self.process_block(&block);
298        }
299    }
300
301    ///
302    /// Generate digest array.
303    ///
304    pub fn digest(self: &mut SHA256) -> [u8; DIGEST_SIZE] {
305        // https://tools.ietf.org/html/rfc6234#section-4.1
306
307        //
308        //   Suppose a message has length L < 2^64.  Before it is input to the
309        //   hash function, the message is padded on the right as follows:
310        //
311        //   a. "1" is appended.  Example: if the original message is "01010000",
312        //      this is padded to "010100001".
313        //
314        //   b. K "0"s are appended where K is the smallest, non-negative solution
315        //      to the equation
316        //
317        //         ( L + 1 + K ) mod 512 = 448
318        //
319        //   c. Then append the 64-bit block that is L in binary representation.
320        //      After appending this block, the length of the message will be a
321        //      multiple of 512 bits.
322        //
323
324        let mut block: [u32; BLOCK_SIZE / 4] = [0; BLOCK_SIZE / 4];
325
326        // NOTE: It is simple to calculate `k`, but having it is a bit useless,
327        // since we know that this algorithm just wants to zero the rest of the
328        // block and to put the 64bit length to the end
329        let mut off = self.length % BLOCK_SIZE;
330
331        // (b)
332        for i in off..self.buffer.len() {
333            self.buffer[i] = 0;
334        }
335
336        // If the padding does not fit in a single block - append 0x80 and zeroes
337        // to the current block and flush it.
338        // Then fill the block with zeroes and append size to it, and flush it
339        // again.
340        let has_overflow = off + 9 > BLOCK_SIZE;
341        if has_overflow {
342            // (a)
343            self.buffer[off] |= 0x80;
344
345            fill_block(&self.buffer, &mut block);
346            self.process_block(&block);
347
348            off = 0;
349            self.buffer = [0; BLOCK_SIZE];
350        }
351
352        // (c)
353        let len_off = self.buffer.len() - 8;
354        write_u64_be(&mut self.buffer[len_off..], (self.length * 8) as u64);
355
356        // (a)
357        if !has_overflow {
358            self.buffer[off] |= 0x80;
359        }
360
361        fill_block(&self.buffer, &mut block);
362        self.process_block(&block);
363
364        let mut out: [u8; DIGEST_SIZE] = [0; DIGEST_SIZE];
365        for i in 0..self.h.len() {
366            out[i * 4] = (self.h[i] >> 24) as u8;
367            out[i * 4 + 1] = (self.h[i] >> 16) as u8;
368            out[i * 4 + 2] = (self.h[i] >> 8) as u8;
369            out[i * 4 + 3] = (self.h[i]) as u8;
370        }
371        out
372    }
373}
374
375impl Default for SHA256 {
376    fn default() -> SHA256 {
377        SHA256::new()
378    }
379}
380
381#[cfg(test)]
382mod tests {
383    use super::*;
384
385    fn check(inputs: &[&str], expected: [u8; DIGEST_SIZE]) {
386        let mut sha256 = SHA256::new();
387
388        for chunk in inputs {
389            sha256.update(chunk.as_bytes());
390        }
391        assert_eq!(sha256.digest(), expected);
392    }
393
394    #[test]
395    fn it_should_compute_digest_for_abc() {
396        check(
397            &["abc"],
398            [
399                0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA, 0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE,
400                0x22, 0x23, 0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C, 0xB4, 0x10, 0xFF, 0x61,
401                0xF2, 0x00, 0x15, 0xAD,
402            ],
403        );
404    }
405
406    #[test]
407    fn it_should_compute_digest_for_a_b_c() {
408        check(
409            &["a", "b", "c"],
410            [
411                0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA, 0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE,
412                0x22, 0x23, 0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C, 0xB4, 0x10, 0xFF, 0x61,
413                0xF2, 0x00, 0x15, 0xAD,
414            ],
415        );
416    }
417
418    #[test]
419    fn it_should_compute_digest_for_long_str() {
420        check(
421            &["abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"],
422            [
423                0x24, 0x8D, 0x6A, 0x61, 0xD2, 0x06, 0x38, 0xB8, 0xE5, 0xC0, 0x26, 0x93, 0x0C, 0x3E,
424                0x60, 0x39, 0xA3, 0x3C, 0xE4, 0x59, 0x64, 0xFF, 0x21, 0x67, 0xF6, 0xEC, 0xED, 0xD4,
425                0x19, 0xDB, 0x06, 0xC1,
426            ],
427        );
428    }
429
430    #[test]
431    fn it_should_compute_digest_for_long_chunked_str() {
432        check(
433            &[
434                "abcdbcdec",
435                "defdefgefg",
436                "hfghighijhi",
437                "jkijkljklmkl",
438                "mnlmnomnopnopq",
439            ],
440            [
441                0x24, 0x8D, 0x6A, 0x61, 0xD2, 0x06, 0x38, 0xB8, 0xE5, 0xC0, 0x26, 0x93, 0x0C, 0x3E,
442                0x60, 0x39, 0xA3, 0x3C, 0xE4, 0x59, 0x64, 0xFF, 0x21, 0x67, 0xF6, 0xEC, 0xED, 0xD4,
443                0x19, 0xDB, 0x06, 0xC1,
444            ],
445        );
446    }
447
448    #[test]
449    fn it_should_compute_digest_for_doubled_chunked_long_str() {
450        check(
451            &[
452                "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
453                "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
454            ],
455            [
456                0x59, 0xf1, 0x09, 0xd9, 0x53, 0x3b, 0x2b, 0x70, 0xe7, 0xc3, 0xb8, 0x14, 0xa2, 0xbd,
457                0x21, 0x8f, 0x78, 0xea, 0x5d, 0x37, 0x14, 0x45, 0x5b, 0xc6, 0x79, 0x87, 0xcf, 0x0d,
458                0x66, 0x43, 0x99, 0xcf,
459            ],
460        );
461    }
462
463    #[test]
464    fn it_should_compute_digest_for_doubled_long_str() {
465        check(
466            &[
467                "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopqabc\
468                 dbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
469            ],
470            [
471                0x59, 0xf1, 0x09, 0xd9, 0x53, 0x3b, 0x2b, 0x70, 0xe7, 0xc3, 0xb8, 0x14, 0xa2, 0xbd,
472                0x21, 0x8f, 0x78, 0xea, 0x5d, 0x37, 0x14, 0x45, 0x5b, 0xc6, 0x79, 0x87, 0xcf, 0x0d,
473                0x66, 0x43, 0x99, 0xcf,
474            ],
475        );
476    }
477}