1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#![no_std]
#![doc(html_logo_url =
"https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")]
#![cfg_attr(feature = "cargo-clippy", allow(needless_range_loop))]
#[macro_use] extern crate opaque_debug;
#[macro_use] pub extern crate digest;
extern crate block_buffer;
#[cfg(feature = "std")]
extern crate std;
pub use digest::Digest;
use digest::{Input, BlockInput, FixedOutput, Reset};
use block_buffer::BlockBuffer;
use block_buffer::block_padding::Pkcs7;
use digest::generic_array::GenericArray;
use digest::generic_array::typenum::U16;
mod consts;
type Block = GenericArray<u8, U16>;
#[derive(Clone)]
struct Md2State {
x: [u8; 48],
checksum: Block,
}
impl Default for Md2State {
fn default() -> Self {
Self { x: [0; 48], checksum: Default::default() }
}
}
#[derive(Clone, Default)]
pub struct Md2 {
buffer: BlockBuffer<U16>,
state: Md2State,
}
impl Md2State {
fn process_block(&mut self, input: &Block) {
for j in 0..16 {
self.x[16 + j] = input[j];
self.x[32 + j] = self.x[16 + j] ^ self.x[j];
}
let mut t = 0u8;
for j in 0..18u8 {
for k in 0..48 {
self.x[k] ^= consts::S[t as usize];
t = self.x[k];
}
t = t.wrapping_add(j);
}
let mut l = self.checksum[15];
for j in 0..16 {
self.checksum[j] ^= consts::S[(input[j] ^ l) as usize];
l = self.checksum[j];
}
}
}
impl BlockInput for Md2 {
type BlockSize = U16;
}
impl Input for Md2 {
fn input<B: AsRef<[u8]>>(&mut self, input: B) {
let input = input.as_ref();
let self_state = &mut self.state;
self.buffer.input(input, |d| self_state.process_block(d) );
}
}
impl FixedOutput for Md2 {
type OutputSize = U16;
fn fixed_result(mut self) -> GenericArray<u8, Self::OutputSize> {
let buf = self.buffer.pad_with::<Pkcs7>()
.expect("we never use input_lazy");
self.state.process_block(buf);
let checksum = self.state.checksum;
self.state.process_block(&checksum);
GenericArray::clone_from_slice(&self.state.x[0..16])
}
}
impl Reset for Md2 {
fn reset(&mut self) {
self.state = Default::default();
self.buffer.reset();
}
}
impl_opaque_debug!(Md2);
impl_write!(Md2);