1 use digest::{Input, BlockInput, FixedOutput, Reset};
2 use digest::generic_array::GenericArray;
3 use digest::generic_array::typenum::{U28, U32, U48, U64, U128};
4 use block_buffer::BlockBuffer;
5 use block_buffer::byteorder::{BE, ByteOrder};
6 
7 use consts::{STATE_LEN, H384, H512, H512_TRUNC_224, H512_TRUNC_256};
8 
9 #[cfg(any(not(feature = "asm"), feature = "asm-aarch64"))]
10 use sha512_utils::compress512;
11 #[cfg(all(feature = "asm", not(feature = "asm-aarch64")))]
12 use sha2_asm::compress512;
13 
14 type BlockSize = U128;
15 type Block = GenericArray<u8, BlockSize>;
16 
17 /// A structure that represents that state of a digest computation for the
18 /// SHA-2 512 family of digest functions
19 #[derive(Clone)]
20 struct Engine512State {
21     h: [u64; 8],
22 }
23 
24 impl Engine512State {
new(h: &[u64; 8]) -> Engine512State25     fn new(h: &[u64; 8]) -> Engine512State { Engine512State { h: *h } }
26 
process_block(&mut self, block: &Block)27     pub fn process_block(&mut self, block: &Block) {
28         let block = unsafe { &*(block.as_ptr() as *const [u8; 128])};
29         compress512(&mut self.h, block);
30     }
31 }
32 
33 /// A structure that keeps track of the state of the Sha-512 operation and
34 /// contains the logic necessary to perform the final calculations.
35 #[derive(Clone)]
36 struct Engine512 {
37     len: (u64, u64), // TODO: replace with u128 on MSRV bump
38     buffer: BlockBuffer<BlockSize>,
39     state: Engine512State,
40 }
41 
42 impl Engine512 {
new(h: &[u64; STATE_LEN]) -> Engine51243     fn new(h: &[u64; STATE_LEN]) -> Engine512 {
44         Engine512 {
45             len: (0, 0),
46             buffer: Default::default(),
47             state: Engine512State::new(h),
48         }
49     }
50 
input(&mut self, input: &[u8])51     fn input(&mut self, input: &[u8]) {
52         let (res, over) = self.len.1.overflowing_add((input.len() as u64) << 3);
53         self.len.1 = res;
54         if over { self.len.0 += 1; }
55         let self_state = &mut self.state;
56         self.buffer.input(input, |d| self_state.process_block(d));
57     }
58 
finish(&mut self)59     fn finish(&mut self) {
60         let self_state = &mut self.state;
61         let (hi, lo) = self.len;
62         self.buffer.len128_padding_be(hi, lo, |d| self_state.process_block(d));
63     }
64 
reset(&mut self, h: &[u64; STATE_LEN])65     fn reset(&mut self, h: &[u64; STATE_LEN]) {
66         self.len = (0, 0);
67         self.buffer.reset();
68         self.state = Engine512State::new(h);
69     }
70 }
71 
72 
73 /// The SHA-512 hash algorithm with the SHA-512 initial hash value.
74 #[derive(Clone)]
75 pub struct Sha512 {
76     engine: Engine512,
77 }
78 
79 impl Default for Sha512 {
default() -> Self80     fn default() -> Self { Sha512 { engine: Engine512::new(&H512) } }
81 }
82 
83 impl BlockInput for Sha512 {
84     type BlockSize = BlockSize;
85 }
86 
87 impl Input for Sha512 {
input<B: AsRef<[u8]>>(&mut self, input: B)88     fn input<B: AsRef<[u8]>>(&mut self, input: B) {
89         self.engine.input(input.as_ref());
90     }
91 }
92 
93 impl FixedOutput for Sha512 {
94     type OutputSize = U64;
95 
fixed_result(mut self) -> GenericArray<u8, Self::OutputSize>96     fn fixed_result(mut self) -> GenericArray<u8, Self::OutputSize> {
97         self.engine.finish();
98 
99         let mut out = GenericArray::default();
100         BE::write_u64_into(&self.engine.state.h[..], out.as_mut_slice());
101         out
102     }
103 }
104 
105 impl Reset for Sha512 {
reset(&mut self)106     fn reset(&mut self) {
107         self.engine.reset(&H512);
108     }
109 }
110 
111 /// The SHA-512 hash algorithm with the SHA-384 initial hash value. The result
112 /// is truncated to 384 bits.
113 #[derive(Clone)]
114 pub struct Sha384 {
115     engine: Engine512,
116 }
117 
118 impl Default for Sha384 {
default() -> Self119     fn default() -> Self { Sha384 { engine: Engine512::new(&H384) } }
120 }
121 
122 impl BlockInput for Sha384 {
123     type BlockSize = BlockSize;
124 }
125 
126 impl Input for Sha384 {
input<B: AsRef<[u8]>>(&mut self, input: B)127     fn input<B: AsRef<[u8]>>(&mut self, input: B) {
128         self.engine.input(input.as_ref());
129     }
130 }
131 
132 impl FixedOutput for Sha384 {
133     type OutputSize = U48;
134 
fixed_result(mut self) -> GenericArray<u8, Self::OutputSize>135     fn fixed_result(mut self) -> GenericArray<u8, Self::OutputSize> {
136         self.engine.finish();
137 
138         let mut out = GenericArray::default();
139         BE::write_u64_into(&self.engine.state.h[..6], out.as_mut_slice());
140         out
141     }
142 }
143 
144 impl Reset for Sha384 {
reset(&mut self)145     fn reset(&mut self) {
146         self.engine.reset(&H384);
147     }
148 }
149 
150 /// The SHA-512 hash algorithm with the SHA-512/256 initial hash value. The
151 /// result is truncated to 256 bits.
152 #[derive(Clone)]
153 pub struct Sha512Trunc256 {
154     engine: Engine512,
155 }
156 
157 impl Default for Sha512Trunc256 {
default() -> Self158     fn default() -> Self {
159         Sha512Trunc256 { engine: Engine512::new(&H512_TRUNC_256) }
160     }
161 }
162 
163 impl BlockInput for Sha512Trunc256 {
164     type BlockSize = BlockSize;
165 }
166 
167 impl Input for Sha512Trunc256 {
input<B: AsRef<[u8]>>(&mut self, input: B)168     fn input<B: AsRef<[u8]>>(&mut self, input: B) {
169         self.engine.input(input.as_ref());
170     }
171 }
172 
173 impl FixedOutput for Sha512Trunc256 {
174     type OutputSize = U32;
175 
fixed_result(mut self) -> GenericArray<u8, Self::OutputSize>176     fn fixed_result(mut self) -> GenericArray<u8, Self::OutputSize> {
177         self.engine.finish();
178 
179         let mut out = GenericArray::default();
180         BE::write_u64_into(&self.engine.state.h[..4], out.as_mut_slice());
181         out
182     }
183 }
184 
185 impl Reset for Sha512Trunc256 {
reset(&mut self)186     fn reset(&mut self) {
187         self.engine.reset(&H512_TRUNC_256);
188     }
189 }
190 
191 /// The SHA-512 hash algorithm with the SHA-512/224 initial hash value.
192 /// The result is truncated to 224 bits.
193 #[derive(Clone)]
194 pub struct Sha512Trunc224 {
195     engine: Engine512,
196 }
197 
198 impl Default for Sha512Trunc224 {
default() -> Self199     fn default() -> Self {
200         Sha512Trunc224 { engine: Engine512::new(&H512_TRUNC_224) }
201     }
202 }
203 
204 impl BlockInput for Sha512Trunc224 {
205     type BlockSize = BlockSize;
206 }
207 
208 impl Input for Sha512Trunc224 {
input<B: AsRef<[u8]>>(&mut self, input: B)209     fn input<B: AsRef<[u8]>>(&mut self, input: B) {
210         self.engine.input(input.as_ref());
211     }
212 }
213 
214 impl FixedOutput for Sha512Trunc224 {
215     type OutputSize = U28;
216 
fixed_result(mut self) -> GenericArray<u8, Self::OutputSize>217     fn fixed_result(mut self) -> GenericArray<u8, Self::OutputSize> {
218         self.engine.finish();
219 
220         let mut out = GenericArray::default();
221         BE::write_u64_into(&self.engine.state.h[..3], &mut out[..24]);
222         BE::write_u32(&mut out[24..28], (self.engine.state.h[3] >> 32) as u32);
223         out
224     }
225 }
226 
227 impl Reset for Sha512Trunc224 {
reset(&mut self)228     fn reset(&mut self) {
229         self.engine.reset(&H512_TRUNC_224);
230     }
231 }
232 
233 impl_opaque_debug!(Sha384);
234 impl_opaque_debug!(Sha512);
235 impl_opaque_debug!(Sha512Trunc224);
236 impl_opaque_debug!(Sha512Trunc256);
237 
238 impl_write!(Sha384);
239 impl_write!(Sha512);
240 impl_write!(Sha512Trunc224);
241 impl_write!(Sha512Trunc256);
242