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
128
129
130
#![no_std]
#![doc(html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")]
#![deny(unsafe_code)]
#![warn(missing_docs, rust_2018_idioms)]
#[cfg(feature = "std")]
extern crate std;
pub use digest::{self, Digest};
use block_buffer::{block_padding::Pkcs7, BlockBuffer};
use digest::{consts::U16, generic_array::GenericArray};
use digest::{BlockInput, FixedOutputDirty, Reset, Update};
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 Update for Md2 {
fn update(&mut self, input: impl AsRef<[u8]>) {
let input = input.as_ref();
let s = &mut self.state;
self.buffer.input_block(input, |d| s.process_block(d));
}
}
impl FixedOutputDirty for Md2 {
type OutputSize = U16;
fn finalize_into_dirty(&mut self, out: &mut digest::Output<Self>) {
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);
out.copy_from_slice(&self.state.x[0..16]);
}
}
impl Reset for Md2 {
fn reset(&mut self) {
self.state = Default::default();
self.buffer.reset();
}
}
opaque_debug::implement!(Md2);
digest::impl_write!(Md2);