1 //! SHA-512
2 use crate::consts::{H384, H512, H512_TRUNC_224, H512_TRUNC_256, STATE_LEN};
3 use block_buffer::BlockBuffer;
4 use core::slice::from_ref;
5 use digest::consts::{U128, U28, U32, U48, U64};
6 use digest::generic_array::GenericArray;
7 use digest::{BlockInput, FixedOutputDirty, Reset, Update};
8 
9 type BlockSize = U128;
10 
11 /// Structure that keeps state of the Sha-512 operation and
12 /// contains the logic necessary to perform the final calculations.
13 #[derive(Clone)]
14 struct Engine512 {
15     len: u128,
16     buffer: BlockBuffer<BlockSize>,
17     state: [u64; 8],
18 }
19 
20 impl Engine512 {
new(h: &[u64; STATE_LEN]) -> Engine51221     fn new(h: &[u64; STATE_LEN]) -> Engine512 {
22         Engine512 {
23             len: 0,
24             buffer: Default::default(),
25             state: *h,
26         }
27     }
28 
update(&mut self, input: &[u8])29     fn update(&mut self, input: &[u8]) {
30         self.len += (input.len() as u128) << 3;
31         let s = &mut self.state;
32         self.buffer.input_blocks(input, |b| compress512(s, b));
33     }
34 
finish(&mut self)35     fn finish(&mut self) {
36         let s = &mut self.state;
37         self.buffer
38             .len128_padding_be(self.len, |d| compress512(s, from_ref(d)));
39     }
40 
reset(&mut self, h: &[u64; STATE_LEN])41     fn reset(&mut self, h: &[u64; STATE_LEN]) {
42         self.len = 0;
43         self.buffer.reset();
44         self.state = *h;
45     }
46 }
47 
48 /// The SHA-512 hash algorithm with the SHA-512 initial hash value.
49 #[derive(Clone)]
50 pub struct Sha512 {
51     engine: Engine512,
52 }
53 
54 impl Default for Sha512 {
default() -> Self55     fn default() -> Self {
56         Sha512 {
57             engine: Engine512::new(&H512),
58         }
59     }
60 }
61 
62 impl BlockInput for Sha512 {
63     type BlockSize = BlockSize;
64 }
65 
66 impl Update for Sha512 {
update(&mut self, input: impl AsRef<[u8]>)67     fn update(&mut self, input: impl AsRef<[u8]>) {
68         self.engine.update(input.as_ref());
69     }
70 }
71 
72 impl FixedOutputDirty for Sha512 {
73     type OutputSize = U64;
74 
finalize_into_dirty(&mut self, out: &mut digest::Output<Self>)75     fn finalize_into_dirty(&mut self, out: &mut digest::Output<Self>) {
76         self.engine.finish();
77         let s = self.engine.state;
78         for (chunk, v) in out.chunks_exact_mut(8).zip(s.iter()) {
79             chunk.copy_from_slice(&v.to_be_bytes());
80         }
81     }
82 }
83 
84 impl Reset for Sha512 {
reset(&mut self)85     fn reset(&mut self) {
86         self.engine.reset(&H512);
87     }
88 }
89 
90 /// The SHA-512 hash algorithm with the SHA-384 initial hash value. The result
91 /// is truncated to 384 bits.
92 #[derive(Clone)]
93 pub struct Sha384 {
94     engine: Engine512,
95 }
96 
97 impl Default for Sha384 {
default() -> Self98     fn default() -> Self {
99         Sha384 {
100             engine: Engine512::new(&H384),
101         }
102     }
103 }
104 
105 impl BlockInput for Sha384 {
106     type BlockSize = BlockSize;
107 }
108 
109 impl Update for Sha384 {
update(&mut self, input: impl AsRef<[u8]>)110     fn update(&mut self, input: impl AsRef<[u8]>) {
111         self.engine.update(input.as_ref());
112     }
113 }
114 
115 impl FixedOutputDirty for Sha384 {
116     type OutputSize = U48;
117 
finalize_into_dirty(&mut self, out: &mut digest::Output<Self>)118     fn finalize_into_dirty(&mut self, out: &mut digest::Output<Self>) {
119         self.engine.finish();
120         let s = &self.engine.state[..6];
121         for (chunk, v) in out.chunks_exact_mut(8).zip(s.iter()) {
122             chunk.copy_from_slice(&v.to_be_bytes());
123         }
124     }
125 }
126 
127 impl Reset for Sha384 {
reset(&mut self)128     fn reset(&mut self) {
129         self.engine.reset(&H384);
130     }
131 }
132 
133 /// The SHA-512 hash algorithm with the SHA-512/256 initial hash value. The
134 /// result is truncated to 256 bits.
135 #[derive(Clone)]
136 pub struct Sha512Trunc256 {
137     engine: Engine512,
138 }
139 
140 impl Default for Sha512Trunc256 {
default() -> Self141     fn default() -> Self {
142         Sha512Trunc256 {
143             engine: Engine512::new(&H512_TRUNC_256),
144         }
145     }
146 }
147 
148 impl BlockInput for Sha512Trunc256 {
149     type BlockSize = BlockSize;
150 }
151 
152 impl Update for Sha512Trunc256 {
update(&mut self, input: impl AsRef<[u8]>)153     fn update(&mut self, input: impl AsRef<[u8]>) {
154         self.engine.update(input.as_ref());
155     }
156 }
157 
158 impl FixedOutputDirty for Sha512Trunc256 {
159     type OutputSize = U32;
160 
finalize_into_dirty(&mut self, out: &mut digest::Output<Self>)161     fn finalize_into_dirty(&mut self, out: &mut digest::Output<Self>) {
162         self.engine.finish();
163         let s = &self.engine.state[..4];
164         for (chunk, v) in out.chunks_exact_mut(8).zip(s.iter()) {
165             chunk.copy_from_slice(&v.to_be_bytes());
166         }
167     }
168 }
169 
170 impl Reset for Sha512Trunc256 {
reset(&mut self)171     fn reset(&mut self) {
172         self.engine.reset(&H512_TRUNC_256);
173     }
174 }
175 
176 /// The SHA-512 hash algorithm with the SHA-512/224 initial hash value.
177 /// The result is truncated to 224 bits.
178 #[derive(Clone)]
179 pub struct Sha512Trunc224 {
180     engine: Engine512,
181 }
182 
183 impl Default for Sha512Trunc224 {
default() -> Self184     fn default() -> Self {
185         Sha512Trunc224 {
186             engine: Engine512::new(&H512_TRUNC_224),
187         }
188     }
189 }
190 
191 impl BlockInput for Sha512Trunc224 {
192     type BlockSize = BlockSize;
193 }
194 
195 impl Update for Sha512Trunc224 {
update(&mut self, input: impl AsRef<[u8]>)196     fn update(&mut self, input: impl AsRef<[u8]>) {
197         self.engine.update(input.as_ref());
198     }
199 }
200 
201 impl FixedOutputDirty for Sha512Trunc224 {
202     type OutputSize = U28;
203 
finalize_into_dirty(&mut self, out: &mut digest::Output<Self>)204     fn finalize_into_dirty(&mut self, out: &mut digest::Output<Self>) {
205         self.engine.finish();
206         let s = &self.engine.state;
207         for (chunk, v) in out.chunks_exact_mut(8).zip(s[..3].iter()) {
208             chunk.copy_from_slice(&v.to_be_bytes());
209         }
210         out[24..28].copy_from_slice(&s[3].to_be_bytes()[..4]);
211     }
212 }
213 
214 impl Reset for Sha512Trunc224 {
reset(&mut self)215     fn reset(&mut self) {
216         self.engine.reset(&H512_TRUNC_224);
217     }
218 }
219 
220 opaque_debug::implement!(Sha384);
221 opaque_debug::implement!(Sha512);
222 opaque_debug::implement!(Sha512Trunc224);
223 opaque_debug::implement!(Sha512Trunc256);
224 
225 digest::impl_write!(Sha384);
226 digest::impl_write!(Sha512);
227 digest::impl_write!(Sha512Trunc224);
228 digest::impl_write!(Sha512Trunc256);
229 
230 cfg_if::cfg_if! {
231     if #[cfg(feature = "force-soft")] {
232         mod soft;
233         use soft::compress;
234     } else if #[cfg(all(feature = "asm", any(target_arch = "x86", target_arch = "x86_64")))] {
235         fn compress(state: &mut [u64; 8], blocks: &[[u8; 128]]) {
236             sha2_asm::compress512(state, blocks);
237         }
238     } else {
239         mod soft;
240         use soft::compress;
241     }
242 }
243 
244 /// Raw SHA-512 compression function.
245 ///
246 /// This is a low-level "hazmat" API which provides direct access to the core
247 /// functionality of SHA-512.
248 #[cfg_attr(docsrs, doc(cfg(feature = "compress")))]
compress512(state: &mut [u64; 8], blocks: &[GenericArray<u8, U128>])249 pub fn compress512(state: &mut [u64; 8], blocks: &[GenericArray<u8, U128>]) {
250     // SAFETY: GenericArray<u8, U128> and [u8; 128] have
251     // exactly the same memory layout
252     #[allow(unsafe_code)]
253     let blocks: &[[u8; 128]] = unsafe { &*(blocks as *const _ as *const [[u8; 128]]) };
254     compress(state, blocks)
255 }
256