Skip to main content

dcrypt_algorithms/hash/sha2/
mod.rs

1//! SHA-2 hash function implementations with enhanced memory safety
2//!
3//! This module implements the SHA-2 family of hash functions as specified in
4//! FIPS PUB 180-4 with additional security measures for memory handling.
5
6#[cfg(feature = "alloc")]
7use crate::alloc_prelude::*;
8
9use crate::error::{validate, Error, Result};
10use crate::hash::{HashAlgorithm, HashFunction};
11use crate::types::Digest;
12use dcrypt_internal::zeroing::{Zeroize, Zeroizing};
13
14// Import security types from dcrypt-core
15use core::sync::atomic::{compiler_fence, Ordering};
16use dcrypt_common::security::{EphemeralSecret, SecureZeroingType, ZeroizeGuard};
17
18use dcrypt_params::utils::hash::{
19    SHA224_OUTPUT_SIZE, SHA256_BLOCK_SIZE, SHA256_OUTPUT_SIZE, SHA384_OUTPUT_SIZE,
20    SHA512_BLOCK_SIZE, SHA512_OUTPUT_SIZE,
21};
22
23// SHA-256 round constants
24const K256: [u32; 64] = [
25    0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
26    0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
27    0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
28    0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
29    0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
30    0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
31    0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
32    0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
33];
34
35// SHA-512 round constants
36const K512: [u64; 80] = [
37    0x428a2f98d728ae22,
38    0x7137449123ef65cd,
39    0xb5c0fbcfec4d3b2f,
40    0xe9b5dba58189dbbc,
41    0x3956c25bf348b538,
42    0x59f111f1b605d019,
43    0x923f82a4af194f9b,
44    0xab1c5ed5da6d8118,
45    0xd807aa98a3030242,
46    0x12835b0145706fbe,
47    0x243185be4ee4b28c,
48    0x550c7dc3d5ffb4e2,
49    0x72be5d74f27b896f,
50    0x80deb1fe3b1696b1,
51    0x9bdc06a725c71235,
52    0xc19bf174cf692694,
53    0xe49b69c19ef14ad2,
54    0xefbe4786384f25e3,
55    0x0fc19dc68b8cd5b5,
56    0x240ca1cc77ac9c65,
57    0x2de92c6f592b0275,
58    0x4a7484aa6ea6e483,
59    0x5cb0a9dcbd41fbd4,
60    0x76f988da831153b5,
61    0x983e5152ee66dfab,
62    0xa831c66d2db43210,
63    0xb00327c898fb213f,
64    0xbf597fc7beef0ee4,
65    0xc6e00bf33da88fc2,
66    0xd5a79147930aa725,
67    0x06ca6351e003826f,
68    0x142929670a0e6e70,
69    0x27b70a8546d22ffc,
70    0x2e1b21385c26c926,
71    0x4d2c6dfc5ac42aed,
72    0x53380d139d95b3df,
73    0x650a73548baf63de,
74    0x766a0abb3c77b2a8,
75    0x81c2c92e47edaee6,
76    0x92722c851482353b,
77    0xa2bfe8a14cf10364,
78    0xa81a664bbc423001,
79    0xc24b8b70d0f89791,
80    0xc76c51a30654be30,
81    0xd192e819d6ef5218,
82    0xd69906245565a910,
83    0xf40e35855771202a,
84    0x106aa07032bbd1b8,
85    0x19a4c116b8d2d0c8,
86    0x1e376c085141ab53,
87    0x2748774cdf8eeb99,
88    0x34b0bcb5e19b48a8,
89    0x391c0cb3c5c95a63,
90    0x4ed8aa4ae3418acb,
91    0x5b9cca4f7763e373,
92    0x682e6ff3d6b2b8a3,
93    0x748f82ee5defb2fc,
94    0x78a5636f43172f60,
95    0x84c87814a1f0ab72,
96    0x8cc702081a6439ec,
97    0x90befffa23631e28,
98    0xa4506cebde82bde9,
99    0xbef9a3f7b2c67915,
100    0xc67178f2e372532b,
101    0xca273eceea26619c,
102    0xd186b8c721c0c207,
103    0xeada7dd6cde0eb1e,
104    0xf57d4f7fee6ed178,
105    0x06f067aa72176fba,
106    0x0a637dc5a2c898a6,
107    0x113f9804bef90dae,
108    0x1b710b35131c471b,
109    0x28db77f523047d84,
110    0x32caab7b40c72493,
111    0x3c9ebe0a15c9bebc,
112    0x431d67c49c100d4c,
113    0x4cc5d4becb3e42b6,
114    0x597f299cfc657e2a,
115    0x5fcb6fab3ad6faec,
116    0x6c44198c4a475817,
117];
118
119/// Validate an MSB-first bit string and split it into whole bytes plus an
120/// optional final partial byte. FIPS 180-4 permits messages whose length is
121/// not a multiple of eight bits; the unused low bits of the final storage byte
122/// are not part of the message and must be zero.
123fn split_bit_message(data: &[u8], bit_len: usize) -> Result<(&[u8], Option<(u8, u8)>)> {
124    let expected_bytes = bit_len.div_ceil(8);
125    validate::length("SHA-2 bit string", data.len(), expected_bytes)?;
126
127    let whole_bytes = bit_len / 8;
128    let trailing_bits = (bit_len % 8) as u8;
129    if trailing_bits == 0 {
130        return Ok((data, None));
131    }
132
133    let final_byte = data[whole_bytes];
134    let unused_mask = (1u8 << (8 - trailing_bits)) - 1;
135    validate::parameter(
136        final_byte & unused_mask == 0,
137        "data",
138        "unused low bits in the final SHA-2 input byte must be zero",
139    )?;
140
141    Ok((&data[..whole_bytes], Some((final_byte, trailing_bits))))
142}
143
144// Define algorithm marker types for each hash function
145/// Marker type for SHA-256 algorithm
146pub enum Sha256Algorithm {}
147
148impl HashAlgorithm for Sha256Algorithm {
149    const OUTPUT_SIZE: usize = SHA256_OUTPUT_SIZE;
150    const BLOCK_SIZE: usize = SHA256_BLOCK_SIZE;
151    const ALGORITHM_ID: &'static str = "SHA-256";
152}
153
154/// Marker type for SHA-224 algorithm
155pub enum Sha224Algorithm {}
156
157impl HashAlgorithm for Sha224Algorithm {
158    const OUTPUT_SIZE: usize = SHA224_OUTPUT_SIZE;
159    const BLOCK_SIZE: usize = SHA256_BLOCK_SIZE;
160    const ALGORITHM_ID: &'static str = "SHA-224";
161}
162
163/// Marker type for SHA-384 algorithm
164pub enum Sha384Algorithm {}
165
166impl HashAlgorithm for Sha384Algorithm {
167    const OUTPUT_SIZE: usize = SHA384_OUTPUT_SIZE;
168    const BLOCK_SIZE: usize = SHA512_BLOCK_SIZE;
169    const ALGORITHM_ID: &'static str = "SHA-384";
170}
171
172/// Marker type for SHA-512 algorithm
173pub enum Sha512Algorithm {}
174
175impl HashAlgorithm for Sha512Algorithm {
176    const OUTPUT_SIZE: usize = SHA512_OUTPUT_SIZE;
177    const BLOCK_SIZE: usize = SHA512_BLOCK_SIZE;
178    const ALGORITHM_ID: &'static str = "SHA-512";
179}
180
181/// Marker type for SHA-512/224 algorithm
182pub enum Sha512_224Algorithm {}
183
184impl HashAlgorithm for Sha512_224Algorithm {
185    const OUTPUT_SIZE: usize = SHA224_OUTPUT_SIZE;
186    const BLOCK_SIZE: usize = SHA512_BLOCK_SIZE;
187    const ALGORITHM_ID: &'static str = "SHA-512/224";
188}
189
190/// Marker type for SHA-512/256 algorithm
191pub enum Sha512_256Algorithm {}
192
193impl HashAlgorithm for Sha512_256Algorithm {
194    const OUTPUT_SIZE: usize = SHA256_OUTPUT_SIZE;
195    const BLOCK_SIZE: usize = SHA512_BLOCK_SIZE;
196    const ALGORITHM_ID: &'static str = "SHA-512/256";
197}
198
199/// SHA-224 hash function state with enhanced memory safety
200#[derive(Clone)]
201pub struct Sha224 {
202    state: [u32; 8],
203    buffer: [u8; SHA256_BLOCK_SIZE],
204    buffer_idx: usize,
205    total_bytes: u64,
206}
207
208impl Drop for Sha224 {
209    fn drop(&mut self) {
210        self.zeroize();
211    }
212}
213
214/// SHA-256 hash function state with enhanced memory safety
215#[derive(Clone)]
216pub struct Sha256 {
217    state: [u32; 8],
218    buffer: [u8; SHA256_BLOCK_SIZE],
219    buffer_idx: usize,
220    total_bytes: u64,
221}
222
223impl Drop for Sha256 {
224    fn drop(&mut self) {
225        self.zeroize();
226    }
227}
228
229/// SHA-384 hash function state with enhanced memory safety
230#[derive(Clone)]
231pub struct Sha384 {
232    state: [u64; 8],
233    buffer: [u8; SHA512_BLOCK_SIZE],
234    buffer_idx: usize,
235    total_bytes: u128, // bits counter
236}
237
238impl Drop for Sha384 {
239    fn drop(&mut self) {
240        self.zeroize();
241    }
242}
243
244/// SHA-512 hash function state with enhanced memory safety
245#[derive(Clone)]
246pub struct Sha512 {
247    state: [u64; 8],
248    buffer: [u8; SHA512_BLOCK_SIZE],
249    buffer_idx: usize,
250    total_bytes: u128,
251}
252
253impl Drop for Sha512 {
254    fn drop(&mut self) {
255        self.zeroize();
256    }
257}
258
259/// SHA-512/224 hash function state with enhanced memory safety
260#[derive(Clone)]
261pub struct Sha512_224 {
262    state: [u64; 8],
263    buffer: [u8; SHA512_BLOCK_SIZE],
264    buffer_idx: usize,
265    total_bytes: u128,
266}
267
268impl Drop for Sha512_224 {
269    fn drop(&mut self) {
270        self.zeroize();
271    }
272}
273
274/// SHA-512/256 hash function state with enhanced memory safety
275#[derive(Clone)]
276pub struct Sha512_256 {
277    state: [u64; 8],
278    buffer: [u8; SHA512_BLOCK_SIZE],
279    buffer_idx: usize,
280    total_bytes: u128,
281}
282
283macro_rules! impl_sha2_zeroize {
284    ($name:ident) => {
285        impl Zeroize for $name {
286            fn zeroize(&mut self) {
287                self.state.zeroize();
288                self.buffer.zeroize();
289                self.buffer_idx.zeroize();
290                self.total_bytes.zeroize();
291            }
292        }
293    };
294}
295
296impl_sha2_zeroize!(Sha224);
297impl_sha2_zeroize!(Sha256);
298impl_sha2_zeroize!(Sha384);
299impl_sha2_zeroize!(Sha512);
300impl_sha2_zeroize!(Sha512_224);
301impl_sha2_zeroize!(Sha512_256);
302
303impl Drop for Sha512_256 {
304    fn drop(&mut self) {
305        self.zeroize();
306    }
307}
308
309// --- SHA-256 internal methods with enhanced security ---
310impl Sha256 {
311    fn init_state() -> [u32; 8] {
312        [
313            0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab,
314            0x5be0cd19,
315        ]
316    }
317
318    fn new() -> Self {
319        Sha256 {
320            state: Self::init_state(),
321            buffer: [0u8; SHA256_BLOCK_SIZE],
322            buffer_idx: 0,
323            total_bytes: 0,
324        }
325    }
326
327    fn compress(state: &mut [u32; 8], block: &[u8; SHA256_BLOCK_SIZE]) -> Result<()> {
328        // Use EphemeralSecret for message schedule
329        let mut w = EphemeralSecret::new([0u32; 64]);
330
331        // Memory barrier before processing
332        compiler_fence(Ordering::SeqCst);
333
334        for i in 0..16 {
335            let start = i * 4;
336            validate::max_length("SHA-256 block read", start + 4, SHA256_BLOCK_SIZE)?;
337            w[i] = (u32::from(block[start]) << 24)
338                | (u32::from(block[start + 1]) << 16)
339                | (u32::from(block[start + 2]) << 8)
340                | u32::from(block[start + 3]);
341        }
342
343        for i in 16..64 {
344            let s0 = w[i - 15].rotate_right(7) ^ w[i - 15].rotate_right(18) ^ (w[i - 15] >> 3);
345            let s1 = w[i - 2].rotate_right(17) ^ w[i - 2].rotate_right(19) ^ (w[i - 2] >> 10);
346            w[i] = w[i - 16]
347                .wrapping_add(s0)
348                .wrapping_add(w[i - 7])
349                .wrapping_add(s1);
350        }
351
352        // Use ZeroizeGuard for working variables
353        let mut working_vars = [
354            state[0], state[1], state[2], state[3], state[4], state[5], state[6], state[7],
355        ];
356        let mut guard = ZeroizeGuard::new(&mut working_vars);
357
358        // Use temporary variables instead of multiple mutable references
359        let mut a = guard[0];
360        let mut b = guard[1];
361        let mut c = guard[2];
362        let mut d = guard[3];
363        let mut e = guard[4];
364        let mut f = guard[5];
365        let mut g = guard[6];
366        let mut h = guard[7];
367
368        for i in 0..64 {
369            let s1 = e.rotate_right(6) ^ e.rotate_right(11) ^ e.rotate_right(25);
370            let ch = (e & f) ^ ((!e) & g);
371            let temp1 = h
372                .wrapping_add(s1)
373                .wrapping_add(ch)
374                .wrapping_add(K256[i])
375                .wrapping_add(w[i]);
376            let s0 = a.rotate_right(2) ^ a.rotate_right(13) ^ a.rotate_right(22);
377            let maj = (a & b) ^ (a & c) ^ (b & c);
378            let temp2 = s0.wrapping_add(maj);
379
380            h = g;
381            g = f;
382            f = e;
383            e = d.wrapping_add(temp1);
384            d = c;
385            c = b;
386            b = a;
387            a = temp1.wrapping_add(temp2);
388        }
389
390        // Write back the results
391        guard[0] = a;
392        guard[1] = b;
393        guard[2] = c;
394        guard[3] = d;
395        guard[4] = e;
396        guard[5] = f;
397        guard[6] = g;
398        guard[7] = h;
399
400        // Update state
401        state[0] = state[0].wrapping_add(guard[0]);
402        state[1] = state[1].wrapping_add(guard[1]);
403        state[2] = state[2].wrapping_add(guard[2]);
404        state[3] = state[3].wrapping_add(guard[3]);
405        state[4] = state[4].wrapping_add(guard[4]);
406        state[5] = state[5].wrapping_add(guard[5]);
407        state[6] = state[6].wrapping_add(guard[6]);
408        state[7] = state[7].wrapping_add(guard[7]);
409
410        a.zeroize();
411        b.zeroize();
412        c.zeroize();
413        d.zeroize();
414        e.zeroize();
415        f.zeroize();
416        g.zeroize();
417        h.zeroize();
418
419        // Memory barrier after processing
420        compiler_fence(Ordering::SeqCst);
421
422        Ok(())
423    }
424
425    fn update_internal(&mut self, mut input: &[u8]) -> Result<()> {
426        while !input.is_empty() {
427            let fill = core::cmp::min(input.len(), SHA256_BLOCK_SIZE - self.buffer_idx);
428            self.buffer[self.buffer_idx..self.buffer_idx + fill].copy_from_slice(&input[..fill]);
429            self.buffer_idx += fill;
430            input = &input[fill..];
431            if self.buffer_idx == SHA256_BLOCK_SIZE {
432                let mut block = Zeroizing::new([0u8; SHA256_BLOCK_SIZE]);
433                block.copy_from_slice(&self.buffer);
434                Self::compress(&mut self.state, &block)?;
435                self.total_bytes += SHA256_BLOCK_SIZE as u64;
436                self.buffer.zeroize();
437                self.buffer_idx = 0;
438            }
439        }
440        Ok(())
441    }
442
443    fn finalize_internal(&mut self) -> Result<Zeroizing<[u8; SHA256_OUTPUT_SIZE]>> {
444        self.finalize_internal_bits(None)
445    }
446
447    fn finalize_internal_bits(
448        &mut self,
449        trailing: Option<(u8, u8)>,
450    ) -> Result<Zeroizing<[u8; SHA256_OUTPUT_SIZE]>> {
451        let trailing_bits = trailing.map_or(0, |(_, bits)| bits);
452        let bit_len = self
453            .total_bytes
454            .checked_add(self.buffer_idx as u64)
455            .and_then(|bytes| bytes.checked_mul(8))
456            .and_then(|bits| bits.checked_add(u64::from(trailing_bits)))
457            .ok_or(Error::Processing {
458                operation: "SHA-256 finalization",
459                details: "message bit length overflow",
460            })?;
461
462        // Append the first padding bit immediately after the final message bit.
463        // The optional byte is already validated to have zero unused low bits.
464        let occupied = if let Some((final_byte, bits)) = trailing {
465            debug_assert!((1..=7).contains(&bits));
466            self.buffer[self.buffer_idx] = final_byte | (0x80 >> bits);
467            self.buffer_idx + 1
468        } else {
469            self.buffer[self.buffer_idx] = 0x80;
470            self.buffer_idx + 1
471        };
472        self.buffer[occupied..].zeroize();
473
474        if occupied > 56 {
475            let mut block = Zeroizing::new([0u8; SHA256_BLOCK_SIZE]);
476            block.copy_from_slice(&self.buffer);
477            Self::compress(&mut self.state, &block)?;
478            self.buffer.zeroize();
479        }
480
481        for (index, byte) in self.buffer[56..].iter_mut().enumerate() {
482            *byte = (bit_len >> (56 - 8 * index)) as u8;
483        }
484        let mut block = Zeroizing::new([0u8; SHA256_BLOCK_SIZE]);
485        block.copy_from_slice(&self.buffer);
486        Self::compress(&mut self.state, &block)?;
487
488        let mut out = Zeroizing::new([0u8; SHA256_OUTPUT_SIZE]);
489        for (word_index, &word) in self.state.iter().enumerate() {
490            for byte in 0..4 {
491                out[word_index * 4 + byte] = (word >> (24 - byte * 8)) as u8;
492            }
493        }
494        self.zeroize();
495        Ok(out)
496    }
497}
498
499// SHA-224 implementation with enhanced security
500impl Sha224 {
501    fn init_state() -> [u32; 8] {
502        [
503            0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7,
504            0xbefa4fa4,
505        ]
506    }
507
508    fn new() -> Self {
509        Sha224 {
510            state: Self::init_state(),
511            buffer: [0u8; SHA256_BLOCK_SIZE],
512            buffer_idx: 0,
513            total_bytes: 0,
514        }
515    }
516
517    /// Hash an MSB-first bit string of the exact length supplied.
518    ///
519    /// This explicit entry point exists for standards conformance inputs that
520    /// are not byte-aligned. Ordinary callers should use [`HashFunction`].
521    pub fn digest_bits(data: &[u8], bit_len: usize) -> Result<Digest<SHA224_OUTPUT_SIZE>> {
522        let full = sha256_digest_bits_with_state(data, bit_len, Self::init_state())?;
523        let mut digest = Digest::<SHA224_OUTPUT_SIZE>::zeroed();
524        digest.as_mut().copy_from_slice(&full[..SHA224_OUTPUT_SIZE]);
525        Ok(digest)
526    }
527}
528
529impl Sha256 {
530    /// Hash an MSB-first bit string of the exact length supplied.
531    pub fn digest_bits(data: &[u8], bit_len: usize) -> Result<Digest<SHA256_OUTPUT_SIZE>> {
532        let full = sha256_digest_bits_with_state(data, bit_len, Self::init_state())?;
533        let mut digest = Digest::<SHA256_OUTPUT_SIZE>::zeroed();
534        digest.as_mut().copy_from_slice(&full[..]);
535        Ok(digest)
536    }
537}
538
539// --- SHA-512 internal methods with enhanced security ---
540impl Sha512 {
541    fn init_state() -> [u64; 8] {
542        [
543            0x6a09e667f3bcc908,
544            0xbb67ae8584caa73b,
545            0x3c6ef372fe94f82b,
546            0xa54ff53a5f1d36f1,
547            0x510e527fade682d1,
548            0x9b05688c2b3e6c1f,
549            0x1f83d9abfb41bd6b,
550            0x5be0cd19137e2179,
551        ]
552    }
553
554    fn new() -> Self {
555        Sha512 {
556            state: Self::init_state(),
557            buffer: [0u8; SHA512_BLOCK_SIZE],
558            buffer_idx: 0,
559            total_bytes: 0,
560        }
561    }
562
563    fn compress(state: &mut [u64; 8], block: &[u8; SHA512_BLOCK_SIZE]) -> Result<()> {
564        // Use EphemeralSecret for message schedule
565        let mut w = EphemeralSecret::new([0u64; 80]);
566
567        // Memory barrier before processing
568        compiler_fence(Ordering::SeqCst);
569
570        for i in 0..16 {
571            let start = i * 8;
572            validate::max_length("SHA-512 block read", start + 8, SHA512_BLOCK_SIZE)?;
573            let mut word = 0u64;
574            for byte in 0..8 {
575                word |= u64::from(block[start + byte]) << (56 - byte * 8);
576            }
577            w[i] = word;
578            word.zeroize();
579        }
580
581        for i in 16..80 {
582            let s0 = w[i - 15].rotate_right(1) ^ w[i - 15].rotate_right(8) ^ (w[i - 15] >> 7);
583            let s1 = w[i - 2].rotate_right(19) ^ w[i - 2].rotate_right(61) ^ (w[i - 2] >> 6);
584            w[i] = w[i - 16]
585                .wrapping_add(s0)
586                .wrapping_add(w[i - 7])
587                .wrapping_add(s1);
588        }
589
590        // Use ZeroizeGuard for working variables
591        let mut working_vars = [
592            state[0], state[1], state[2], state[3], state[4], state[5], state[6], state[7],
593        ];
594        let mut guard = ZeroizeGuard::new(&mut working_vars);
595
596        // Use temporary variables instead of multiple mutable references
597        let mut a = guard[0];
598        let mut b = guard[1];
599        let mut c = guard[2];
600        let mut d = guard[3];
601        let mut e = guard[4];
602        let mut f = guard[5];
603        let mut g = guard[6];
604        let mut h = guard[7];
605
606        for i in 0..80 {
607            let s1 = e.rotate_right(14) ^ e.rotate_right(18) ^ e.rotate_right(41);
608            let ch = (e & f) ^ ((!e) & g);
609            let temp1 = h
610                .wrapping_add(s1)
611                .wrapping_add(ch)
612                .wrapping_add(K512[i])
613                .wrapping_add(w[i]);
614            let s0 = a.rotate_right(28) ^ a.rotate_right(34) ^ a.rotate_right(39);
615            let maj = (a & b) ^ (a & c) ^ (b & c);
616            let temp2 = s0.wrapping_add(maj);
617
618            h = g;
619            g = f;
620            f = e;
621            e = d.wrapping_add(temp1);
622            d = c;
623            c = b;
624            b = a;
625            a = temp1.wrapping_add(temp2);
626        }
627
628        // Write back the results
629        guard[0] = a;
630        guard[1] = b;
631        guard[2] = c;
632        guard[3] = d;
633        guard[4] = e;
634        guard[5] = f;
635        guard[6] = g;
636        guard[7] = h;
637
638        // Update state
639        state[0] = state[0].wrapping_add(guard[0]);
640        state[1] = state[1].wrapping_add(guard[1]);
641        state[2] = state[2].wrapping_add(guard[2]);
642        state[3] = state[3].wrapping_add(guard[3]);
643        state[4] = state[4].wrapping_add(guard[4]);
644        state[5] = state[5].wrapping_add(guard[5]);
645        state[6] = state[6].wrapping_add(guard[6]);
646        state[7] = state[7].wrapping_add(guard[7]);
647
648        a.zeroize();
649        b.zeroize();
650        c.zeroize();
651        d.zeroize();
652        e.zeroize();
653        f.zeroize();
654        g.zeroize();
655        h.zeroize();
656
657        // Memory barrier after processing
658        compiler_fence(Ordering::SeqCst);
659
660        Ok(())
661    }
662
663    fn update_internal_u128(&mut self, mut input: &[u8]) -> Result<()> {
664        while !input.is_empty() {
665            let fill = core::cmp::min(input.len(), SHA512_BLOCK_SIZE - self.buffer_idx);
666            self.buffer[self.buffer_idx..self.buffer_idx + fill].copy_from_slice(&input[..fill]);
667            self.buffer_idx += fill;
668            input = &input[fill..];
669            if self.buffer_idx == SHA512_BLOCK_SIZE {
670                let mut block = Zeroizing::new([0u8; SHA512_BLOCK_SIZE]);
671                block.copy_from_slice(&self.buffer);
672                Self::compress(&mut self.state, &block)?;
673                self.total_bytes = self.total_bytes.wrapping_add(SHA512_BLOCK_SIZE as u128);
674                self.buffer.zeroize();
675                self.buffer_idx = 0;
676            }
677        }
678        Ok(())
679    }
680
681    fn finalize_internal_u128(&mut self) -> Result<Zeroizing<[u8; SHA512_OUTPUT_SIZE]>> {
682        self.finalize_internal_bits_u128(None)
683    }
684
685    fn finalize_internal_bits_u128(
686        &mut self,
687        trailing: Option<(u8, u8)>,
688    ) -> Result<Zeroizing<[u8; SHA512_OUTPUT_SIZE]>> {
689        let trailing_bits = trailing.map_or(0, |(_, bits)| bits);
690        let bit_len = self
691            .total_bytes
692            .checked_add(self.buffer_idx as u128)
693            .and_then(|bytes| bytes.checked_mul(8))
694            .and_then(|bits| bits.checked_add(u128::from(trailing_bits)))
695            .ok_or(Error::Processing {
696                operation: "SHA-512 finalization",
697                details: "message bit length overflow",
698            })?;
699
700        let occupied = if let Some((final_byte, bits)) = trailing {
701            debug_assert!((1..=7).contains(&bits));
702            self.buffer[self.buffer_idx] = final_byte | (0x80 >> bits);
703            self.buffer_idx + 1
704        } else {
705            self.buffer[self.buffer_idx] = 0x80;
706            self.buffer_idx + 1
707        };
708        self.buffer[occupied..].zeroize();
709
710        if occupied > SHA512_BLOCK_SIZE - 16 {
711            let mut block = Zeroizing::new([0u8; SHA512_BLOCK_SIZE]);
712            block.copy_from_slice(&self.buffer);
713            Self::compress(&mut self.state, &block)?;
714            self.buffer.zeroize();
715        }
716
717        for (index, byte) in self.buffer[SHA512_BLOCK_SIZE - 16..].iter_mut().enumerate() {
718            *byte = (bit_len >> (120 - index * 8)) as u8;
719        }
720        let mut block = Zeroizing::new([0u8; SHA512_BLOCK_SIZE]);
721        block.copy_from_slice(&self.buffer);
722        Self::compress(&mut self.state, &block)?;
723
724        let mut out = Zeroizing::new([0u8; SHA512_OUTPUT_SIZE]);
725        for (word_index, &word) in self.state.iter().enumerate() {
726            for byte in 0..8 {
727                out[word_index * 8 + byte] = (word >> (56 - byte * 8)) as u8;
728            }
729        }
730        self.zeroize();
731        Ok(out)
732    }
733}
734
735// SHA-512/224 implementation
736impl Sha512_224 {
737    fn init_state() -> [u64; 8] {
738        [
739            0x8c3d37c819544da2,
740            0x73e1996689dcd4d6,
741            0x1dfab7ae32ff9c82,
742            0x679dd514582f9fcf,
743            0x0f6d2b697bd44da8,
744            0x77e36f7304c48942,
745            0x3f9d85a86a1d36c8,
746            0x1112e6ad91d692a1,
747        ]
748    }
749
750    fn new() -> Self {
751        Sha512_224 {
752            state: Self::init_state(),
753            buffer: [0u8; SHA512_BLOCK_SIZE],
754            buffer_idx: 0,
755            total_bytes: 0,
756        }
757    }
758}
759
760// SHA-512/256 implementation
761impl Sha512_256 {
762    fn init_state() -> [u64; 8] {
763        [
764            0x22312194fc2bf72c,
765            0x9f555fa3c84c64c2,
766            0x2393b86b6f53b151,
767            0x963877195940eabd,
768            0x96283ee2a88effe3,
769            0xbe5e1e2553863992,
770            0x2b0199fc2c85b8aa,
771            0x0eb72ddc81c52ca2,
772        ]
773    }
774
775    fn new() -> Self {
776        Sha512_256 {
777            state: Self::init_state(),
778            buffer: [0u8; SHA512_BLOCK_SIZE],
779            buffer_idx: 0,
780            total_bytes: 0,
781        }
782    }
783}
784
785impl Sha384 {
786    fn init_state() -> [u64; 8] {
787        [
788            0xcbbb9d5dc1059ed8,
789            0x629a292a367cd507,
790            0x9159015a3070dd17,
791            0x152fecd8f70e5939,
792            0x67332667ffc00b31,
793            0x8eb44a8768581511,
794            0xdb0c2e0d64f98fa7,
795            0x47b5481dbefa4fa4,
796        ]
797    }
798
799    /// Hash an MSB-first bit string of the exact length supplied.
800    pub fn digest_bits(data: &[u8], bit_len: usize) -> Result<Digest<SHA384_OUTPUT_SIZE>> {
801        let full = sha512_digest_bits_with_state(data, bit_len, Self::init_state())?;
802        let mut digest = Digest::<SHA384_OUTPUT_SIZE>::zeroed();
803        digest.as_mut().copy_from_slice(&full[..SHA384_OUTPUT_SIZE]);
804        Ok(digest)
805    }
806}
807
808impl Sha512 {
809    /// Hash an MSB-first bit string of the exact length supplied.
810    pub fn digest_bits(data: &[u8], bit_len: usize) -> Result<Digest<SHA512_OUTPUT_SIZE>> {
811        let full = sha512_digest_bits_with_state(data, bit_len, Self::init_state())?;
812        let mut digest = Digest::<SHA512_OUTPUT_SIZE>::zeroed();
813        digest.as_mut().copy_from_slice(&full[..]);
814        Ok(digest)
815    }
816}
817
818impl Sha512_224 {
819    /// Hash an MSB-first bit string of the exact length supplied.
820    pub fn digest_bits(data: &[u8], bit_len: usize) -> Result<Digest<SHA224_OUTPUT_SIZE>> {
821        let full = sha512_digest_bits_with_state(data, bit_len, Self::init_state())?;
822        let mut digest = Digest::<SHA224_OUTPUT_SIZE>::zeroed();
823        digest.as_mut().copy_from_slice(&full[..SHA224_OUTPUT_SIZE]);
824        Ok(digest)
825    }
826}
827
828impl Sha512_256 {
829    /// Hash an MSB-first bit string of the exact length supplied.
830    pub fn digest_bits(data: &[u8], bit_len: usize) -> Result<Digest<SHA256_OUTPUT_SIZE>> {
831        let full = sha512_digest_bits_with_state(data, bit_len, Self::init_state())?;
832        let mut digest = Digest::<SHA256_OUTPUT_SIZE>::zeroed();
833        digest.as_mut().copy_from_slice(&full[..SHA256_OUTPUT_SIZE]);
834        Ok(digest)
835    }
836}
837
838fn sha256_digest_bits_with_state(
839    data: &[u8],
840    bit_len: usize,
841    state: [u32; 8],
842) -> Result<Zeroizing<[u8; SHA256_OUTPUT_SIZE]>> {
843    let (whole_bytes, trailing) = split_bit_message(data, bit_len)?;
844    let mut hash = Sha256::new();
845    hash.state = state;
846    hash.update_internal(whole_bytes)?;
847    hash.finalize_internal_bits(trailing)
848}
849
850fn sha512_digest_bits_with_state(
851    data: &[u8],
852    bit_len: usize,
853    state: [u64; 8],
854) -> Result<Zeroizing<[u8; SHA512_OUTPUT_SIZE]>> {
855    let (whole_bytes, trailing) = split_bit_message(data, bit_len)?;
856    let mut hash = Sha512::new();
857    hash.state = state;
858    hash.update_internal_u128(whole_bytes)?;
859    hash.finalize_internal_bits_u128(trailing)
860}
861
862// --- HashFunction impls with SecureZeroingType ---
863impl SecureZeroingType for Sha256 {
864    fn zeroed() -> Self {
865        Self::new()
866    }
867}
868
869impl HashFunction for Sha256 {
870    type Algorithm = Sha256Algorithm;
871    type Output = Digest<SHA256_OUTPUT_SIZE>;
872
873    fn new() -> Self {
874        Sha256::new()
875    }
876
877    fn update(&mut self, data: &[u8]) -> Result<&mut Self> {
878        self.update_internal(data)?;
879        Ok(self)
880    }
881
882    fn finalize(&mut self) -> Result<Self::Output> {
883        let hash = self.finalize_internal()?;
884        let mut digest = Digest::<SHA256_OUTPUT_SIZE>::zeroed();
885        digest.as_mut().copy_from_slice(&hash[..]);
886        Ok(digest)
887    }
888
889    fn output_size() -> usize {
890        SHA256_OUTPUT_SIZE
891    }
892
893    fn block_size() -> usize {
894        SHA256_BLOCK_SIZE
895    }
896
897    fn name() -> String {
898        "SHA-256".to_string()
899    }
900}
901
902impl SecureZeroingType for Sha224 {
903    fn zeroed() -> Self {
904        Self::new()
905    }
906}
907
908impl HashFunction for Sha224 {
909    type Algorithm = Sha224Algorithm;
910    type Output = Digest<SHA224_OUTPUT_SIZE>;
911
912    fn new() -> Self {
913        Sha224::new()
914    }
915
916    fn update(&mut self, data: &[u8]) -> Result<&mut Self> {
917        let mut tmp = Sha256::new();
918        tmp.state = self.state;
919        tmp.buffer = self.buffer;
920        tmp.buffer_idx = self.buffer_idx;
921        tmp.total_bytes = self.total_bytes;
922        tmp.update_internal(data)?;
923        self.state = tmp.state;
924        self.buffer = tmp.buffer;
925        self.buffer_idx = tmp.buffer_idx;
926        self.total_bytes = tmp.total_bytes;
927        Ok(self)
928    }
929
930    fn finalize(&mut self) -> Result<Self::Output> {
931        let mut tmp = Sha256::new();
932        tmp.state = self.state;
933        tmp.buffer = self.buffer;
934        tmp.buffer_idx = self.buffer_idx;
935        tmp.total_bytes = self.total_bytes;
936        let full = tmp.finalize_internal()?;
937        let mut digest = Digest::<SHA224_OUTPUT_SIZE>::zeroed();
938        digest.as_mut().copy_from_slice(&full[..SHA224_OUTPUT_SIZE]);
939        Ok(digest)
940    }
941
942    fn output_size() -> usize {
943        SHA224_OUTPUT_SIZE
944    }
945
946    fn block_size() -> usize {
947        SHA256_BLOCK_SIZE
948    }
949
950    fn name() -> String {
951        "SHA-224".to_string()
952    }
953}
954
955impl SecureZeroingType for Sha384 {
956    fn zeroed() -> Self {
957        Sha384 {
958            state: Self::init_state(),
959            buffer: [0u8; SHA512_BLOCK_SIZE],
960            buffer_idx: 0,
961            total_bytes: 0,
962        }
963    }
964}
965
966impl HashFunction for Sha384 {
967    type Algorithm = Sha384Algorithm;
968    type Output = Digest<SHA384_OUTPUT_SIZE>;
969
970    fn new() -> Self {
971        SecureZeroingType::zeroed()
972    }
973
974    fn update(&mut self, data: &[u8]) -> Result<&mut Self> {
975        let mut tmp = Sha512::new();
976        tmp.state = self.state;
977        tmp.buffer = self.buffer;
978        tmp.buffer_idx = self.buffer_idx;
979        tmp.total_bytes = self.total_bytes;
980        tmp.update_internal_u128(data)?;
981        self.state = tmp.state;
982        self.buffer = tmp.buffer;
983        self.buffer_idx = tmp.buffer_idx;
984        self.total_bytes = tmp.total_bytes;
985        Ok(self)
986    }
987
988    fn finalize(&mut self) -> Result<Self::Output> {
989        let mut tmp = Sha512::new();
990        tmp.state = self.state;
991        tmp.buffer = self.buffer;
992        tmp.buffer_idx = self.buffer_idx;
993        tmp.total_bytes = self.total_bytes;
994        let full = tmp.finalize_internal_u128()?;
995        let mut digest = Digest::<SHA384_OUTPUT_SIZE>::zeroed();
996        digest.as_mut().copy_from_slice(&full[..SHA384_OUTPUT_SIZE]);
997        Ok(digest)
998    }
999
1000    fn output_size() -> usize {
1001        SHA384_OUTPUT_SIZE
1002    }
1003
1004    fn block_size() -> usize {
1005        SHA512_BLOCK_SIZE
1006    }
1007
1008    fn name() -> String {
1009        "SHA-384".to_string()
1010    }
1011}
1012
1013impl SecureZeroingType for Sha512 {
1014    fn zeroed() -> Self {
1015        Self::new()
1016    }
1017}
1018
1019impl HashFunction for Sha512 {
1020    type Algorithm = Sha512Algorithm;
1021    type Output = Digest<SHA512_OUTPUT_SIZE>;
1022
1023    fn new() -> Self {
1024        Sha512::new()
1025    }
1026
1027    fn update(&mut self, data: &[u8]) -> Result<&mut Self> {
1028        self.update_internal_u128(data)?;
1029        Ok(self)
1030    }
1031
1032    fn finalize(&mut self) -> Result<Self::Output> {
1033        let hash = self.finalize_internal_u128()?;
1034        let mut digest = Digest::<SHA512_OUTPUT_SIZE>::zeroed();
1035        digest.as_mut().copy_from_slice(&hash[..]);
1036        Ok(digest)
1037    }
1038
1039    fn output_size() -> usize {
1040        SHA512_OUTPUT_SIZE
1041    }
1042
1043    fn block_size() -> usize {
1044        SHA512_BLOCK_SIZE
1045    }
1046
1047    fn name() -> String {
1048        "SHA-512".to_string()
1049    }
1050}
1051
1052impl SecureZeroingType for Sha512_224 {
1053    fn zeroed() -> Self {
1054        Self::new()
1055    }
1056}
1057
1058impl HashFunction for Sha512_224 {
1059    type Algorithm = Sha512_224Algorithm;
1060    type Output = Digest<SHA224_OUTPUT_SIZE>;
1061
1062    fn new() -> Self {
1063        Sha512_224::new()
1064    }
1065
1066    fn update(&mut self, data: &[u8]) -> Result<&mut Self> {
1067        let mut tmp = Sha512::new();
1068        tmp.state = self.state;
1069        tmp.buffer = self.buffer;
1070        tmp.buffer_idx = self.buffer_idx;
1071        tmp.total_bytes = self.total_bytes;
1072        tmp.update_internal_u128(data)?;
1073        self.state = tmp.state;
1074        self.buffer = tmp.buffer;
1075        self.buffer_idx = tmp.buffer_idx;
1076        self.total_bytes = tmp.total_bytes;
1077        Ok(self)
1078    }
1079
1080    fn finalize(&mut self) -> Result<Self::Output> {
1081        let mut tmp = Sha512::new();
1082        tmp.state = self.state;
1083        tmp.buffer = self.buffer;
1084        tmp.buffer_idx = self.buffer_idx;
1085        tmp.total_bytes = self.total_bytes;
1086        let full = tmp.finalize_internal_u128()?;
1087        let mut digest = Digest::<SHA224_OUTPUT_SIZE>::zeroed();
1088        digest.as_mut().copy_from_slice(&full[..SHA224_OUTPUT_SIZE]);
1089        Ok(digest)
1090    }
1091
1092    fn output_size() -> usize {
1093        SHA224_OUTPUT_SIZE
1094    }
1095
1096    fn block_size() -> usize {
1097        SHA512_BLOCK_SIZE
1098    }
1099
1100    fn name() -> String {
1101        "SHA-512/224".to_string()
1102    }
1103}
1104
1105impl SecureZeroingType for Sha512_256 {
1106    fn zeroed() -> Self {
1107        Self::new()
1108    }
1109}
1110
1111impl HashFunction for Sha512_256 {
1112    type Algorithm = Sha512_256Algorithm;
1113    type Output = Digest<SHA256_OUTPUT_SIZE>;
1114
1115    fn new() -> Self {
1116        Sha512_256::new()
1117    }
1118
1119    fn update(&mut self, data: &[u8]) -> Result<&mut Self> {
1120        let mut tmp = Sha512::new();
1121        tmp.state = self.state;
1122        tmp.buffer = self.buffer;
1123        tmp.buffer_idx = self.buffer_idx;
1124        tmp.total_bytes = self.total_bytes;
1125        tmp.update_internal_u128(data)?;
1126        self.state = tmp.state;
1127        self.buffer = tmp.buffer;
1128        self.buffer_idx = tmp.buffer_idx;
1129        self.total_bytes = tmp.total_bytes;
1130        Ok(self)
1131    }
1132
1133    fn finalize(&mut self) -> Result<Self::Output> {
1134        let mut tmp = Sha512::new();
1135        tmp.state = self.state;
1136        tmp.buffer = self.buffer;
1137        tmp.buffer_idx = self.buffer_idx;
1138        tmp.total_bytes = self.total_bytes;
1139        let full = tmp.finalize_internal_u128()?;
1140        let mut digest = Digest::<SHA256_OUTPUT_SIZE>::zeroed();
1141        digest.as_mut().copy_from_slice(&full[..SHA256_OUTPUT_SIZE]);
1142        Ok(digest)
1143    }
1144
1145    fn output_size() -> usize {
1146        SHA256_OUTPUT_SIZE
1147    }
1148
1149    fn block_size() -> usize {
1150        SHA512_BLOCK_SIZE
1151    }
1152
1153    fn name() -> String {
1154        "SHA-512/256".to_string()
1155    }
1156}
1157
1158#[cfg(test)]
1159mod tests;