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