aboutsummaryrefslogtreecommitdiff
path: root/hash.rs
blob: 693c82230c1b40ed112919cc2f023c0718e00575 (plain) (blame)
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
import libc::c_uint;

export hasher;
export hashtype;
export hash;
export libcrypto;

export md5, sha1, sha224, sha256, sha384, sha512;

iface hasher {
    #[doc = "Initializes this hasher"]
    fn init();

    #[doc = "Update this hasher with more input bytes"]
    fn update(~[u8]);

    #[doc = "
    Return the digest of all bytes added to this hasher since its last
    initialization
    "]
    fn final() -> ~[u8];
}

enum hashtype {
    md5,
    sha1,
    sha224,
    sha256,
    sha384,
    sha512
}

type EVP_MD_CTX = *libc::c_void;
type EVP_MD = *libc::c_void;

#[link_name = "crypto"]
#[abi = "cdecl"]
extern mod libcrypto {
    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: *u8, n: *u32);
}

fn evpmd(t: hashtype) -> (EVP_MD, uint) {
    alt 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) }
    }
}

fn hasher(ht: hashtype) -> hasher {
    type hasherstate = {
        evp: EVP_MD,
        ctx: EVP_MD_CTX,
        len: uint
    };

    impl of hasher for hasherstate {
        fn init() unsafe {
            libcrypto::EVP_DigestInit(self.ctx, self.evp);
        }

        fn update(data: ~[u8]) unsafe {
            let pdata: *u8 = vec::unsafe::to_ptr::<u8>(data);
            libcrypto::EVP_DigestUpdate(self.ctx, pdata, vec::len(data) as c_uint);
        }

        fn final() -> ~[u8] unsafe {
            let res = vec::to_mut(vec::from_elem::<u8>(self.len, 0u8));
            let pres = vec::unsafe::to_ptr::<u8>(res);
            libcrypto::EVP_DigestFinal(self.ctx, pres, ptr::null::<u32>());
            vec::from_mut::<u8>(res)
        }
    }

    let ctx = libcrypto::EVP_MD_CTX_create();
    let (evp, mdlen) = evpmd(ht);
    let st = { evp: evp, ctx: ctx, len: mdlen };
    let h = st as hasher;
    h.init();
    ret h;
}

#[doc = "
Hashes the supplied input data using hash t, returning the resulting hash value
"]
fn hash(t: hashtype, data: ~[u8]) -> ~[u8] unsafe {
    let h = hasher(t);
    h.init();
    h.update(data);
    ret h.final();
}

#[cfg(test)]
mod tests {
    // 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);
    }
}