Skip to main content

bouncycastle_sha2/
sha256.rs

1use crate::SHA2Params;
2use bouncycastle_core::errors::{HashError, SuspendableError};
3use bouncycastle_core::suspendable_state::{add_lib_ver, check_lib_ver};
4use bouncycastle_core::traits::{Algorithm, Hash, SecurityStrength, Suspendable};
5use bouncycastle_utils::{min, secret::Secret};
6use core::slice;
7
8const SHA256_K: [u32; 64] = [
9    0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
10    0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
11    0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
12    0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
13    0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
14    0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
15    0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
16    0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2,
17];
18
19#[inline]
20fn ch(x: u32, y: u32, z: u32) -> u32 {
21    (x & y) ^ (!x & z)
22}
23
24#[inline]
25fn maj(x: u32, y: u32, z: u32) -> u32 {
26    (x & y) | (z & (x ^ y))
27}
28
29#[inline]
30fn sum0(x: u32) -> u32 {
31    x.rotate_right(2) ^ x.rotate_right(13) ^ x.rotate_right(22)
32}
33
34#[inline]
35fn sum1(x: u32) -> u32 {
36    x.rotate_right(6) ^ x.rotate_right(11) ^ x.rotate_right(25)
37}
38
39#[inline]
40fn theta0(x: u32) -> u32 {
41    x.rotate_right(7) ^ x.rotate_right(18) ^ (x >> 3)
42}
43
44#[inline]
45fn theta1(x: u32) -> u32 {
46    x.rotate_right(17) ^ x.rotate_right(19) ^ (x >> 10)
47}
48
49#[derive(Clone)]
50pub(crate) struct Sha256State<PARAMS: SHA2Params> {
51    _params: core::marker::PhantomData<PARAMS>,
52    h: Secret<[u32; 8]>,
53}
54
55impl<PARAMS: SHA2Params> Sha256State<PARAMS> {
56    pub(crate) fn new() -> Self {
57        let mut h = Secret::<[u32; 8]>::new();
58        match PARAMS::OUTPUT_LEN * 8 {
59            224 => {
60                h.copy_from_slice(&[
61                    0xC1059ED8, 0x367CD507, 0x3070DD17, 0xF70E5939, 0xFFC00B31, 0x68581511,
62                    0x64F98FA7, 0xBEFA4FA4,
63                ]);
64                Self { _params: core::marker::PhantomData, h }
65            }
66            256 => {
67                h.copy_from_slice(&[
68                    0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C,
69                    0x1F83D9AB, 0x5BE0CD19,
70                ]);
71                Self { _params: std::marker::PhantomData, h }
72            }
73            _ => panic!("Invalid SHA-2 bit size: {}", PARAMS::OUTPUT_LEN),
74        }
75    }
76
77    fn compress(&mut self, blocks: &[[u8; 64]]) {
78        let mut x = [0u32; 64];
79
80        // infallible; just unwrapping the [u32; 8] and re-casting to itself.
81        let s = &mut *self.h;
82        let &mut [mut a, mut b, mut c, mut d, mut e, mut f, mut g, mut h] = s;
83
84        for block in blocks {
85            let (chunks, _remainder) = block.as_chunks::<4>();
86            for (i, w) in x[..16].iter_mut().zip(chunks) {
87                *i = u32::from_be_bytes(*w);
88            }
89
90            for i in 16..64 {
91                x[i] = theta1(x[i - 2])
92                    .wrapping_add(x[i - 7])
93                    .wrapping_add(theta0(x[i - 15]))
94                    .wrapping_add(x[i - 16]);
95            }
96
97            macro_rules! sha256_round {
98                ($a:ident,$b:ident,$c:ident,$d:ident,$e:ident,$f:ident,$g:ident,$h:ident,$t:ident,$K:ident,$x:ident) => {
99                    $h = $h
100                        .wrapping_add(sum1($e))
101                        .wrapping_add(ch($e, $f, $g))
102                        .wrapping_add($K[$t])
103                        .wrapping_add($x[$t]);
104                    $d = $d.wrapping_add($h);
105                    $h = $h.wrapping_add(sum0($a)).wrapping_add(maj($a, $b, $c));
106                    $t += 1;
107                };
108            }
109
110            let mut t: usize = 0;
111            for _ in 0..8 {
112                sha256_round!(a, b, c, d, e, f, g, h, t, SHA256_K, x);
113                sha256_round!(h, a, b, c, d, e, f, g, t, SHA256_K, x);
114                sha256_round!(g, h, a, b, c, d, e, f, t, SHA256_K, x);
115                sha256_round!(f, g, h, a, b, c, d, e, t, SHA256_K, x);
116                sha256_round!(e, f, g, h, a, b, c, d, t, SHA256_K, x);
117                sha256_round!(d, e, f, g, h, a, b, c, t, SHA256_K, x);
118                sha256_round!(c, d, e, f, g, h, a, b, t, SHA256_K, x);
119                sha256_round!(b, c, d, e, f, g, h, a, t, SHA256_K, x);
120            }
121
122            a = a.wrapping_add(s[0]);
123            b = b.wrapping_add(s[1]);
124            c = c.wrapping_add(s[2]);
125            d = d.wrapping_add(s[3]);
126            e = e.wrapping_add(s[4]);
127            f = f.wrapping_add(s[5]);
128            g = g.wrapping_add(s[6]);
129            h = h.wrapping_add(s[7]);
130
131            s[0] = a;
132            s[1] = b;
133            s[2] = c;
134            s[3] = d;
135            s[4] = e;
136            s[5] = f;
137            s[6] = g;
138            s[7] = h;
139        }
140    }
141}
142
143/// Internal struct for SHA256.
144/// This uses a private bound so that you cannot instantiate it directly and have to use the
145/// provided and NIST-approved parameters.
146#[derive(Clone)]
147pub struct SHA256Internal<PARAMS: SHA2Params> {
148    _params: core::marker::PhantomData<PARAMS>,
149    state: Sha256State<PARAMS>,
150    byte_count: u64,
151    x_buf: Secret<[u8; 64]>,
152    x_buf_off: usize,
153    // TODO: Investigate whether maximum message size (according to FIPS 180-4) should be added 
154    // (2^64 for SHA256 and 2^128 for SHA512)
155}
156
157impl<PARAMS: SHA2Params> SHA256Internal<PARAMS> {
158    /// Creates a new SHA256 instance, ready for use.
159    pub fn new() -> Self {
160        Self {
161            _params: core::marker::PhantomData,
162            state: Sha256State::<PARAMS>::new(),
163            byte_count: 0,
164            x_buf: Secret::new(),
165            x_buf_off: 0,
166        }
167    }
168}
169
170impl<PARAMS: SHA2Params> Default for SHA256Internal<PARAMS> {
171    fn default() -> Self {
172        Self::new()
173    }
174}
175
176impl<PARAMS: SHA2Params> Algorithm for SHA256Internal<PARAMS> {
177    const ALG_NAME: &'static str = PARAMS::ALG_NAME;
178    const MAX_SECURITY_STRENGTH: SecurityStrength = PARAMS::MAX_SECURITY_STRENGTH;
179}
180
181impl<PARAMS: SHA2Params> Hash for SHA256Internal<PARAMS> {
182    /// As per FIPS 180-4 Figure 1
183    fn block_bitlen(&self) -> usize {
184        512
185    }
186
187    fn output_len(&self) -> usize {
188        PARAMS::OUTPUT_LEN
189    }
190
191    fn hash(self, data: &[u8]) -> Vec<u8> {
192        let mut output = vec![0u8; PARAMS::OUTPUT_LEN];
193        self.hash_out(data, &mut output);
194        output
195    }
196
197    fn hash_out(mut self, data: &[u8], output: &mut [u8]) -> usize {
198        output.fill(0);
199
200        self.do_update(data);
201        self.do_final_out(output)
202    }
203
204    fn do_update(&mut self, block: &[u8]) {
205        let len = block.len();
206
207        // TODO: Check there is enough space left in 'byte_count' to allow this operation,
208        // TODO: although overflowing a u64 is unlikely to happen in practice, and rust will throw an error anyway.
209        self.byte_count += len as u64;
210
211        let available = 64 - self.x_buf_off;
212
213        // TODO: mutants thinks you can replace < with <= without changing behaviour
214        if len < available {
215            self.x_buf[self.x_buf_off..self.x_buf_off + len].copy_from_slice(block);
216            self.x_buf_off += len;
217            return;
218        }
219
220        let mut block = block;
221        if self.x_buf_off != 0 {
222            self.x_buf[self.x_buf_off..].copy_from_slice(&block[..available]);
223            block = &block[available..];
224
225            self.state.compress(slice::from_ref(&self.x_buf));
226        }
227
228        let (chunks, remainder) = block.as_chunks::<64>();
229
230        self.state.compress(chunks);
231
232        let remaining = remainder.len();
233        self.x_buf[..remaining].copy_from_slice(remainder);
234        self.x_buf_off = remaining;
235    }
236
237    fn do_final(self) -> Vec<u8> {
238        let mut output = vec![0u8; PARAMS::OUTPUT_LEN];
239        self.do_final_out(&mut output);
240        output
241    }
242
243    fn do_final_out(mut self, output: &mut [u8]) -> usize {
244        output.fill(0);
245
246        let n = *min(&output.len(), &PARAMS::OUTPUT_LEN);
247
248        let bit_len: u64 = self.byte_count << 3;
249
250        self.x_buf[self.x_buf_off] = 0x80;
251        self.x_buf_off += 1;
252
253        if self.x_buf_off > 56 {
254            self.x_buf[self.x_buf_off..].fill(0x00);
255            self.state.compress(slice::from_ref(&self.x_buf));
256            self.x_buf_off = 0;
257        }
258
259        self.x_buf[self.x_buf_off..56].fill(0x00);
260        self.x_buf[56..64].copy_from_slice(&bit_len.to_be_bytes());
261        self.state.compress(slice::from_ref(&self.x_buf));
262
263        let h = &self.state.h;
264
265        // let n = output.len();
266        for i in 0..(n / 4) {
267            output[i * 4..i * 4 + 4].copy_from_slice(&h[i].to_be_bytes());
268        }
269        if !n.is_multiple_of(4) {
270            output[((n / 4) * 4)..((n / 4) * 4) + (n % 4)]
271                .copy_from_slice(&h[n / 4].to_be_bytes()[0..(n % 4)]);
272        }
273
274        n
275    }
276
277    /// TODO: This is defined in FIPS 180-4 s. 5.1.2
278    /// TODO: <https://pages.nist.gov/ACVP/draft-celi-acvp-sha.html>
279    /// TODO: It can be implemented if required
280    #[allow(unused)]
281    fn do_final_partial_bits(
282        self,
283        partial_byte: u8,
284        num_partial_bits: usize,
285    ) -> Result<Vec<u8>, HashError> {
286        unimplemented!()
287    }
288
289    /// TODO: This is defined in FIPS 180-4 s. 5.1.2
290    /// TODO: <https://pages.nist.gov/ACVP/draft-celi-acvp-sha.html>
291    /// TODO: It can be implemented if required
292    #[allow(unused)]
293    fn do_final_partial_bits_out(
294        self,
295        partial_byte: u8,
296        num_partial_bits: usize,
297        output: &mut [u8],
298    ) -> Result<usize, HashError> {
299        unimplemented!()
300    }
301
302    fn max_security_strength(&self) -> SecurityStrength {
303        SecurityStrength::from_bytes(PARAMS::OUTPUT_LEN / 2)
304    }
305}
306
307/// Length in bytes of the serialized state of SHA224 and SHA256.
308pub const SUSPENDED_SHA256_STATE_LEN: usize = 108;
309
310impl<PARAMS: SHA2Params> Suspendable<SUSPENDED_SHA256_STATE_LEN> for SHA256Internal<PARAMS> {
311    fn suspend(self) -> [u8; SUSPENDED_SHA256_STATE_LEN] {
312        debug_assert_eq!(SUSPENDED_SHA256_STATE_LEN, 108);
313
314        let mut out_to_return = [0u8; SUSPENDED_SHA256_STATE_LEN];
315
316        // insert the version tag
317        // infallible: add_lib_ver returns a slice of exactly SUSPENDED_SHA256_STATE_LEN - 3 = 105 bytes.
318        let out: &mut [u8; 105] = add_lib_ver(&mut out_to_return).try_into().unwrap();
319
320        // state.h: [u32; 8]
321        // 4 * 8 = 32
322        for i in 0..8 {
323            out[i * 4..(i * 4) + 4].copy_from_slice(&self.state.h[i].to_le_bytes());
324        }
325
326        // byte_count: u64
327        out[32..40].copy_from_slice(&self.byte_count.to_le_bytes());
328
329        // x_buf: [u8; 64]
330        out[40..104].copy_from_slice(&*self.x_buf);
331
332        // x_buf_off: usize
333        // in general, a usize should be serialized into a u64, but in this case, it can't ever be larger than 64
334        debug_assert!(self.x_buf_off < 64);
335        out[104] = self.x_buf_off as u8;
336
337        out_to_return
338    }
339
340    fn from_suspended(
341        serialized_state: [u8; SUSPENDED_SHA256_STATE_LEN],
342    ) -> Result<Self, SuspendableError> {
343        debug_assert_eq!(SUSPENDED_SHA256_STATE_LEN, 108);
344
345        // check the version tag
346        // At the moment, we have no not_before version to specify.
347        // infallible: check_lib_ver returns a slice of exactly SUSPENDED_SHA256_STATE_LEN - 3 = 105 bytes.
348        let input: &[u8; 105] = check_lib_ver(&serialized_state, None)?.try_into().unwrap();
349
350        // state.h: [u32; 8]
351        // 4 * 8 = 32
352        let mut h = Secret::<[u32; 8]>::new();
353        for i in 0..8 {
354            h[i] = u32::from_le_bytes(input[i * 4..(i * 4) + 4].try_into().unwrap());
355        }
356
357        // byte_count: u64
358        let byte_count: u64 = u64::from_le_bytes(input[32..40].try_into().unwrap());
359
360        // x_buf: [u8; 64]
361        let mut x_buf = Secret::<[u8; 64]>::new();
362        x_buf.copy_from_slice(&input[40..104]);
363
364        // x_buf_off: usize
365        // in general, a usize should be serialized into a u64, but in this case, it can't ever be larger than 64
366        let x_buf_off: usize = input[104] as usize;
367        if x_buf_off >= 64 {
368            return Err(SuspendableError::InvalidData);
369        }
370
371        // Construct the object
372        let state = Sha256State { _params: core::marker::PhantomData, h };
373        Ok(SHA256Internal {
374            _params: core::marker::PhantomData,
375            state,
376            byte_count,
377            x_buf,
378            x_buf_off,
379        })
380    }
381}