-
Notifications
You must be signed in to change notification settings - Fork 0
/
sha0.rs
117 lines (95 loc) · 3.11 KB
/
sha0.rs
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
use crate::hash::{Digest, Endianness, Message};
const H0: u32 = 0x67452301;
const H1: u32 = 0xEFCDAB89;
const H2: u32 = 0x98BADCFE;
const H3: u32 = 0x10325476;
const H4: u32 = 0xC3D2E1F0;
fn pad(input: &Vec<u8>) -> Vec<u32> {
let input_length: u64 = input.len() as u64;
let input_length_in_bits: u64 = input_length * 8;
let length_be_bytes: [u8; 8] = input_length_in_bits.to_be_bytes();
let input_length_mod_64: u64 = input_length % 64;
let padding_length: u64 = match input_length_mod_64 {
56 => 64,
_ => (56 + 64 - input_length_mod_64) % 64,
};
let total_length = (input_length + padding_length + 8) as usize;
let mut buffer: Vec<u8> = Vec::with_capacity(total_length);
buffer.extend_from_slice(input);
buffer.push(0x80);
buffer.resize((input_length + padding_length) as usize, 0x00);
buffer.extend_from_slice(&length_be_bytes);
let mut words: Vec<u32> = Vec::new();
for chunk in buffer.chunks_exact(4) {
let word = u32::from_be_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
words.push(word);
}
words
}
fn transform(t: u32, b: u32, c: u32, d: u32) -> u32 {
match t {
0..=19 => (b & c) | (!b & d),
20..=39 => b ^ c ^ d,
40..=59 => (b & c) | (b & d) | (c & d),
_ => b ^ c ^ d,
}
}
fn k(t: u32) -> u32 {
match t {
0..=19 => 0x5A827999,
20..=39 => 0x6ED9EBA1,
40..=59 => 0x8F1BBCDC,
_ => 0xCA62C1D6,
}
}
pub struct SHA0;
impl SHA0 {
pub fn hash(&self, input: &Message) -> Digest {
let input: Vec<u32> = pad(&input.buffer);
let mut h: Vec<u32> = vec![H0, H1, H2, H3, H4];
for block in input.chunks(16) {
let mut w: Vec<u32> = block.to_vec();
for t in 16..80 {
w.push(w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16]);
}
let mut a = h.clone();
for t in 0..80 {
let temp = a[0]
.rotate_left(5)
.wrapping_add(transform(t, a[1], a[2], a[3]))
.wrapping_add(a[4])
.wrapping_add(w[t as usize])
.wrapping_add(k(t));
a[4] = a[3];
a[3] = a[2];
a[2] = a[1].rotate_left(30);
a[1] = a[0];
a[0] = temp;
}
h[0] = h[0].wrapping_add(a[0]);
h[1] = h[1].wrapping_add(a[1]);
h[2] = h[2].wrapping_add(a[2]);
h[3] = h[3].wrapping_add(a[3]);
h[4] = h[4].wrapping_add(a[4]);
}
Digest::from_u32(&h, Endianness::Big)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sha0() {
let hasher = SHA0;
let i1 = Message::from_string("abc");
let i2 = Message::from_string("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq");
assert_eq!(
hasher.hash(&i1).to_hex(),
"0164b8a914cd2a5e74c4f7ff082c4d97f1edf880"
);
assert_eq!(
hasher.hash(&i2).to_hex(),
"d2516ee1acfa5baf33dfc1c471e438449ef134c8"
);
}
}