1#![cfg_attr(not(feature = "std"), no_std)]
32
33#[cfg(feature = "std")]
34use std as core;
35
36use core::convert;
37use core::fmt;
38use core::ops;
39
40#[cfg(feature = "std")]
41use core::io;
42
43#[derive(Clone, Copy, Eq, Hash, PartialEq)]
45pub struct Digest(pub [u8; 16]);
46
47impl convert::From<Digest> for [u8; 16] {
48 #[inline]
49 fn from(digest: Digest) -> Self {
50 digest.0
51 }
52}
53
54impl fmt::Debug for Digest {
55 #[inline]
56 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
57 fmt::LowerHex::fmt(self, formatter)
58 }
59}
60
61impl ops::Deref for Digest {
62 type Target = [u8; 16];
63
64 #[inline]
65 fn deref(&self) -> &Self::Target {
66 &self.0
67 }
68}
69
70impl ops::DerefMut for Digest {
71 #[inline]
72 fn deref_mut(&mut self) -> &mut Self::Target {
73 &mut self.0
74 }
75}
76
77macro_rules! implement {
78 ($kind:ident, $format:expr) => {
79 impl fmt::$kind for Digest {
80 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
81 for value in &self.0 {
82 write!(formatter, $format, value)?;
83 }
84 Ok(())
85 }
86 }
87 };
88}
89
90implement!(LowerHex, "{:02x}");
91implement!(UpperHex, "{:02X}");
92
93#[derive(Clone)]
95pub struct Context {
96 buffer: [u8; 64],
97 count: [u32; 2],
98 state: [u32; 4],
99}
100
101const PADDING: [u8; 64] = [
102 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
103 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
104 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
105 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
106];
107
108impl Context {
109 #[inline]
111 pub fn new() -> Context {
112 Context {
113 buffer: [0; 64],
114 count: [0, 0],
115 state: [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476],
116 }
117 }
118
119 #[cfg(target_pointer_width = "32")]
121 #[inline]
122 pub fn consume<T: AsRef<[u8]>>(&mut self, data: T) {
123 consume(self, data.as_ref());
124 }
125
126 #[cfg(target_pointer_width = "64")]
128 pub fn consume<T: AsRef<[u8]>>(&mut self, data: T) {
129 for chunk in data.as_ref().chunks(core::u32::MAX as usize) {
130 consume(self, chunk);
131 }
132 }
133
134 pub fn compute(mut self) -> Digest {
136 let mut input = [0u32; 16];
137 let k = ((self.count[0] >> 3) & 0x3f) as usize;
138 input[14] = self.count[0];
139 input[15] = self.count[1];
140 consume(
141 &mut self,
142 &PADDING[..(if k < 56 { 56 - k } else { 120 - k })],
143 );
144 let mut j = 0;
145 for i in 0..14 {
146 input[i] = ((self.buffer[j + 3] as u32) << 24) |
147 ((self.buffer[j + 2] as u32) << 16) |
148 ((self.buffer[j + 1] as u32) << 8) |
149 ((self.buffer[j ] as u32) );
150 j += 4;
151 }
152 transform(&mut self.state, &input);
153 let mut digest = [0u8; 16];
154 let mut j = 0;
155 for i in 0..4 {
156 digest[j ] = ((self.state[i] ) & 0xff) as u8;
157 digest[j + 1] = ((self.state[i] >> 8) & 0xff) as u8;
158 digest[j + 2] = ((self.state[i] >> 16) & 0xff) as u8;
159 digest[j + 3] = ((self.state[i] >> 24) & 0xff) as u8;
160 j += 4;
161 }
162 Digest(digest)
163 }
164}
165
166impl convert::From<Context> for Digest {
167 #[inline]
168 fn from(context: Context) -> Digest {
169 context.compute()
170 }
171}
172
173#[cfg(feature = "std")]
174impl io::Write for Context {
175 #[inline]
176 fn write(&mut self, data: &[u8]) -> io::Result<usize> {
177 self.consume(data);
178 Ok(data.len())
179 }
180
181 #[inline]
182 fn flush(&mut self) -> io::Result<()> {
183 Ok(())
184 }
185}
186
187#[inline]
189pub fn compute<T: AsRef<[u8]>>(data: T) -> Digest {
190 let mut context = Context::new();
191 context.consume(data);
192 context.compute()
193}
194
195fn consume(
196 Context {
197 buffer,
198 count,
199 state,
200 }: &mut Context,
201 data: &[u8],
202) {
203 let mut input = [0u32; 16];
204 let mut k = ((count[0] >> 3) & 0x3f) as usize;
205 let length = data.len() as u32;
206 count[0] = count[0].wrapping_add(length << 3);
207 if count[0] < length << 3 {
208 count[1] = count[1].wrapping_add(1);
209 }
210 count[1] = count[1].wrapping_add(length >> 29);
211 for &value in data {
212 buffer[k] = value;
213 k += 1;
214 if k == 0x40 {
215 let mut j = 0;
216 for i in 0..16 {
217 input[i] = ((buffer[j + 3] as u32) << 24) |
218 ((buffer[j + 2] as u32) << 16) |
219 ((buffer[j + 1] as u32) << 8) |
220 ((buffer[j ] as u32) );
221 j += 4;
222 }
223 transform(state, &input);
224 k = 0;
225 }
226 }
227}
228
229fn transform(state: &mut [u32; 4], input: &[u32; 16]) {
230 let (mut a, mut b, mut c, mut d) = (state[0], state[1], state[2], state[3]);
231 macro_rules! add(
232 ($a:expr, $b:expr) => ($a.wrapping_add($b));
233 );
234 macro_rules! rotate(
235 ($x:expr, $n:expr) => (($x << $n) | ($x >> (32 - $n)));
236 );
237 {
238 macro_rules! F(
239 ($x:expr, $y:expr, $z:expr) => (($x & $y) | (!$x & $z));
240 );
241 macro_rules! T(
242 ($a:expr, $b:expr, $c:expr, $d:expr, $x:expr, $s:expr, $ac:expr) => ({
243 $a = add!(add!(add!($a, F!($b, $c, $d)), $x), $ac);
244 $a = rotate!($a, $s);
245 $a = add!($a, $b);
246 });
247 );
248 const S1: u32 = 7;
249 const S2: u32 = 12;
250 const S3: u32 = 17;
251 const S4: u32 = 22;
252 T!(a, b, c, d, input[ 0], S1, 3614090360);
253 T!(d, a, b, c, input[ 1], S2, 3905402710);
254 T!(c, d, a, b, input[ 2], S3, 606105819);
255 T!(b, c, d, a, input[ 3], S4, 3250441966);
256 T!(a, b, c, d, input[ 4], S1, 4118548399);
257 T!(d, a, b, c, input[ 5], S2, 1200080426);
258 T!(c, d, a, b, input[ 6], S3, 2821735955);
259 T!(b, c, d, a, input[ 7], S4, 4249261313);
260 T!(a, b, c, d, input[ 8], S1, 1770035416);
261 T!(d, a, b, c, input[ 9], S2, 2336552879);
262 T!(c, d, a, b, input[10], S3, 4294925233);
263 T!(b, c, d, a, input[11], S4, 2304563134);
264 T!(a, b, c, d, input[12], S1, 1804603682);
265 T!(d, a, b, c, input[13], S2, 4254626195);
266 T!(c, d, a, b, input[14], S3, 2792965006);
267 T!(b, c, d, a, input[15], S4, 1236535329);
268 }
269 {
270 macro_rules! F(
271 ($x:expr, $y:expr, $z:expr) => (($x & $z) | ($y & !$z));
272 );
273 macro_rules! T(
274 ($a:expr, $b:expr, $c:expr, $d:expr, $x:expr, $s:expr, $ac:expr) => ({
275 $a = add!(add!(add!($a, F!($b, $c, $d)), $x), $ac);
276 $a = rotate!($a, $s);
277 $a = add!($a, $b);
278 });
279 );
280 const S1: u32 = 5;
281 const S2: u32 = 9;
282 const S3: u32 = 14;
283 const S4: u32 = 20;
284 T!(a, b, c, d, input[ 1], S1, 4129170786);
285 T!(d, a, b, c, input[ 6], S2, 3225465664);
286 T!(c, d, a, b, input[11], S3, 643717713);
287 T!(b, c, d, a, input[ 0], S4, 3921069994);
288 T!(a, b, c, d, input[ 5], S1, 3593408605);
289 T!(d, a, b, c, input[10], S2, 38016083);
290 T!(c, d, a, b, input[15], S3, 3634488961);
291 T!(b, c, d, a, input[ 4], S4, 3889429448);
292 T!(a, b, c, d, input[ 9], S1, 568446438);
293 T!(d, a, b, c, input[14], S2, 3275163606);
294 T!(c, d, a, b, input[ 3], S3, 4107603335);
295 T!(b, c, d, a, input[ 8], S4, 1163531501);
296 T!(a, b, c, d, input[13], S1, 2850285829);
297 T!(d, a, b, c, input[ 2], S2, 4243563512);
298 T!(c, d, a, b, input[ 7], S3, 1735328473);
299 T!(b, c, d, a, input[12], S4, 2368359562);
300 }
301 {
302 macro_rules! F(
303 ($x:expr, $y:expr, $z:expr) => ($x ^ $y ^ $z);
304 );
305 macro_rules! T(
306 ($a:expr, $b:expr, $c:expr, $d:expr, $x:expr, $s:expr, $ac:expr) => ({
307 $a = add!(add!(add!($a, F!($b, $c, $d)), $x), $ac);
308 $a = rotate!($a, $s);
309 $a = add!($a, $b);
310 });
311 );
312 const S1: u32 = 4;
313 const S2: u32 = 11;
314 const S3: u32 = 16;
315 const S4: u32 = 23;
316 T!(a, b, c, d, input[ 5], S1, 4294588738);
317 T!(d, a, b, c, input[ 8], S2, 2272392833);
318 T!(c, d, a, b, input[11], S3, 1839030562);
319 T!(b, c, d, a, input[14], S4, 4259657740);
320 T!(a, b, c, d, input[ 1], S1, 2763975236);
321 T!(d, a, b, c, input[ 4], S2, 1272893353);
322 T!(c, d, a, b, input[ 7], S3, 4139469664);
323 T!(b, c, d, a, input[10], S4, 3200236656);
324 T!(a, b, c, d, input[13], S1, 681279174);
325 T!(d, a, b, c, input[ 0], S2, 3936430074);
326 T!(c, d, a, b, input[ 3], S3, 3572445317);
327 T!(b, c, d, a, input[ 6], S4, 76029189);
328 T!(a, b, c, d, input[ 9], S1, 3654602809);
329 T!(d, a, b, c, input[12], S2, 3873151461);
330 T!(c, d, a, b, input[15], S3, 530742520);
331 T!(b, c, d, a, input[ 2], S4, 3299628645);
332 }
333 {
334 macro_rules! F(
335 ($x:expr, $y:expr, $z:expr) => ($y ^ ($x | !$z));
336 );
337 macro_rules! T(
338 ($a:expr, $b:expr, $c:expr, $d:expr, $x:expr, $s:expr, $ac:expr) => ({
339 $a = add!(add!(add!($a, F!($b, $c, $d)), $x), $ac);
340 $a = rotate!($a, $s);
341 $a = add!($a, $b);
342 });
343 );
344 const S1: u32 = 6;
345 const S2: u32 = 10;
346 const S3: u32 = 15;
347 const S4: u32 = 21;
348 T!(a, b, c, d, input[ 0], S1, 4096336452);
349 T!(d, a, b, c, input[ 7], S2, 1126891415);
350 T!(c, d, a, b, input[14], S3, 2878612391);
351 T!(b, c, d, a, input[ 5], S4, 4237533241);
352 T!(a, b, c, d, input[12], S1, 1700485571);
353 T!(d, a, b, c, input[ 3], S2, 2399980690);
354 T!(c, d, a, b, input[10], S3, 4293915773);
355 T!(b, c, d, a, input[ 1], S4, 2240044497);
356 T!(a, b, c, d, input[ 8], S1, 1873313359);
357 T!(d, a, b, c, input[15], S2, 4264355552);
358 T!(c, d, a, b, input[ 6], S3, 2734768916);
359 T!(b, c, d, a, input[13], S4, 1309151649);
360 T!(a, b, c, d, input[ 4], S1, 4149444226);
361 T!(d, a, b, c, input[11], S2, 3174756917);
362 T!(c, d, a, b, input[ 2], S3, 718787259);
363 T!(b, c, d, a, input[ 9], S4, 3951481745);
364 }
365 state[0] = add!(state[0], a);
366 state[1] = add!(state[1], b);
367 state[2] = add!(state[2], c);
368 state[3] = add!(state[3], d);
369}
370
371#[cfg(test)]
372mod tests {
373 #[test]
374 fn compute() {
375 let inputs = [
376 "",
377 "a",
378 "abc",
379 "message digest",
380 "abcdefghijklmnopqrstuvwxyz",
381 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
382 "0123456789012345678901234567890123456789012345678901234567890123",
383 "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
384 ];
385 let outputs = [
386 "d41d8cd98f00b204e9800998ecf8427e",
387 "0cc175b9c0f1b6a831c399e269772661",
388 "900150983cd24fb0d6963f7d28e17f72",
389 "f96b697d7cb7938d525a2f31aaf161d0",
390 "c3fcd3d76192e4007dfb496cca67e13b",
391 "d174ab98d277d9f5a5611c2c9f419d9f",
392 "7f7bfd348709deeaace19e3f535f8c54",
393 "57edf4a22be3c955ac49da2e2107b67a",
394 ];
395 for (input, &output) in inputs.iter().zip(outputs.iter()) {
396 assert_eq!(format!("{:x}", ::compute(input)), output);
397 }
398 }
399
400 #[test]
401 fn index() {
402 let mut digest = ::compute(b"abc");
403 assert_eq!(digest[0], 0x90);
404 assert_eq!(&digest[0], &0x90);
405 assert_eq!(&mut digest[0], &mut 0x90);
406 }
407
408 #[test]
409 fn overflow_count() {
410 use std::io::prelude::Write;
411 let data = vec![0; 8 * 1024 * 1024];
412 let mut context = ::Context::new();
413 for _ in 0..64 {
414 context.write(&data).unwrap();
415 }
416 assert_eq!(
417 format!("{:x}", context.compute()),
418 "aa559b4e3523a6c931f08f4df52d58f2"
419 );
420 }
421
422 #[test]
423 #[cfg(target_pointer_width = "64")]
424 fn overflow_length() {
425 use std::io::prelude::Write;
426 use std::u32::MAX;
427 let data = vec![0; MAX as usize + 1];
428 let mut context = ::Context::new();
429 context.write(&data).unwrap();
430 assert_eq!(
431 format!("{:x}", context.compute()),
432 "c9a5a6878d97b48cc965c1e41859f034"
433 );
434 }
435}