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
131
132
133
134
135
136
137
138
139
140
141
142
143
|
use std::libc::c_uint;
use std::libc;
use std::ptr;
use std::vec;
pub enum HashType {
MD5,
SHA1,
SHA224,
SHA256,
SHA384,
SHA512
}
#[allow(non_camel_case_types)]
pub type EVP_MD_CTX = *libc::c_void;
#[allow(non_camel_case_types)]
pub type EVP_MD = *libc::c_void;
mod libcrypto {
use super::*;
use std::libc::c_uint;
#[link_args = "-lcrypto"]
extern {
fn EVP_MD_CTX_create() -> EVP_MD_CTX;
fn EVP_md5() -> EVP_MD;
fn EVP_sha1() -> EVP_MD;
fn EVP_sha224() -> EVP_MD;
fn EVP_sha256() -> EVP_MD;
fn EVP_sha384() -> EVP_MD;
fn EVP_sha512() -> EVP_MD;
fn EVP_DigestInit(ctx: EVP_MD_CTX, typ: EVP_MD);
fn EVP_DigestUpdate(ctx: EVP_MD_CTX, data: *u8, n: c_uint);
fn EVP_DigestFinal(ctx: EVP_MD_CTX, res: *mut u8, n: *u32);
}
}
fn evpmd(t: HashType) -> (EVP_MD, uint) {
unsafe {
match t {
MD5 => (libcrypto::EVP_md5(), 16u),
SHA1 => (libcrypto::EVP_sha1(), 20u),
SHA224 => (libcrypto::EVP_sha224(), 28u),
SHA256 => (libcrypto::EVP_sha256(), 32u),
SHA384 => (libcrypto::EVP_sha384(), 48u),
SHA512 => (libcrypto::EVP_sha512(), 64u),
}
}
}
pub struct Hasher {
priv evp: EVP_MD,
priv ctx: EVP_MD_CTX,
priv len: uint,
}
pub fn Hasher(ht: HashType) -> Hasher {
let ctx = unsafe { libcrypto::EVP_MD_CTX_create() };
let (evp, mdlen) = evpmd(ht);
let h = Hasher { evp: evp, ctx: ctx, len: mdlen };
h.init();
h
}
impl Hasher {
/// Initializes this hasher
pub fn init(&self) {
unsafe { libcrypto::EVP_DigestInit(self.ctx, self.evp) }
}
/// Update this hasher with more input bytes
pub fn update(&self, data: &[u8]) {
do data.as_imm_buf |pdata, len| {
unsafe {
libcrypto::EVP_DigestUpdate(self.ctx, pdata, len as c_uint)
}
}
}
/**
* Return the digest of all bytes added to this hasher since its last
* initialization
*/
pub fn final(&self) -> ~[u8] {
let mut res = vec::from_elem(self.len, 0u8);
do res.as_mut_buf |pres, _len| {
unsafe {
libcrypto::EVP_DigestFinal(self.ctx, pres, ptr::null());
}
}
res
}
}
/**
* Hashes the supplied input data using hash t, returning the resulting hash
* value
*/
pub fn hash(t: HashType, data: &[u8]) -> ~[u8] {
let h = Hasher(t);
h.update(data);
h.final()
}
#[cfg(test)]
mod tests {
use super::*;
// Test vectors from http://www.nsrl.nist.gov/testdata/
#[test]
fn test_md5() {
let s0 = ~[0x61u8, 0x62u8, 0x63u8];
let d0 =
~[0x90u8, 0x01u8, 0x50u8, 0x98u8, 0x3cu8, 0xd2u8, 0x4fu8, 0xb0u8,
0xd6u8, 0x96u8, 0x3fu8, 0x7du8, 0x28u8, 0xe1u8, 0x7fu8, 0x72u8];
assert!(hash(MD5, s0) == d0);
}
#[test]
fn test_sha1() {
let s0 = ~[0x61u8, 0x62u8, 0x63u8];
let d0 =
~[0xa9u8, 0x99u8, 0x3eu8, 0x36u8, 0x47u8, 0x06u8, 0x81u8, 0x6au8,
0xbau8, 0x3eu8, 0x25u8, 0x71u8, 0x78u8, 0x50u8, 0xc2u8, 0x6cu8,
0x9cu8, 0xd0u8, 0xd8u8, 0x9du8];
assert!(hash(SHA1, s0) == d0);
}
#[test]
fn test_sha256() {
let s0 = ~[0x61u8, 0x62u8, 0x63u8];
let d0 =
~[0xbau8, 0x78u8, 0x16u8, 0xbfu8, 0x8fu8, 0x01u8, 0xcfu8, 0xeau8,
0x41u8, 0x41u8, 0x40u8, 0xdeu8, 0x5du8, 0xaeu8, 0x22u8, 0x23u8,
0xb0u8, 0x03u8, 0x61u8, 0xa3u8, 0x96u8, 0x17u8, 0x7au8, 0x9cu8,
0xb4u8, 0x10u8, 0xffu8, 0x61u8, 0xf2u8, 0x00u8, 0x15u8, 0xadu8];
assert!(hash(SHA256, s0) == d0);
}
}
|