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