about summary refs log tree commit diff
path: root/src/libstd/md4.rs
blob: 581beb78bdc555f2ff63479b03b3fed746ff1b02 (plain)
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
#[forbid(deprecated_mode)];

pub fn md4(msg: &[u8]) -> {a: u32, b: u32, c: u32, d: u32} {
    // subtle: if orig_len is merely uint, then the code below
    // which performs shifts by 32 bits or more has undefined
    // results.
    let orig_len: u64 = (vec::len(msg) * 8u) as u64;

    // pad message
    let mut msg = vec::append(vec::from_slice(msg), ~[0x80u8]);
    let mut bitlen = orig_len + 8u64;
    while (bitlen + 64u64) % 512u64 > 0u64 {
        msg.push(0u8);
        bitlen += 8u64;
    }

    // append length
    let mut i = 0u64;
    while i < 8u64 {
        msg.push((orig_len >> (i * 8u64)) as u8);
        i += 1u64;
    }

    let mut a = 0x67452301u32;
    let mut b = 0xefcdab89u32;
    let mut c = 0x98badcfeu32;
    let mut d = 0x10325476u32;

    fn rot(r: int, x: u32) -> u32 {
        let r = r as u32;
        (x << r) | (x >> (32u32 - r))
    }

    let mut i = 0u;
    let e = vec::len(msg);
    let x = vec::to_mut(vec::from_elem(16u, 0u32));
    while i < e {
        let aa = a, bb = b, cc = c, dd = d;

        let mut j = 0u, base = i;
        while j < 16u {
            x[j] = (msg[base] as u32) + (msg[base + 1u] as u32 << 8u32) +
                (msg[base + 2u] as u32 << 16u32) +
                (msg[base + 3u] as u32 << 24u32);
            j += 1u; base += 4u;
        }

        let mut j = 0u;
        while j < 16u {
            a = rot(3, a + ((b & c) | (!b & d)) + x[j]);
            j += 1u;
            d = rot(7, d + ((a & b) | (!a & c)) + x[j]);
            j += 1u;
            c = rot(11, c + ((d & a) | (!d & b)) + x[j]);
            j += 1u;
            b = rot(19, b + ((c & d) | (!c & a)) + x[j]);
            j += 1u;
        }

        let mut j = 0u;
        let q = 0x5a827999u32;
        while j < 4u {
            a = rot(3, a + ((b & c) | ((b & d) | (c & d))) + x[j] + q);
            d = rot(5, d + ((a & b) | ((a & c) | (b & c))) + x[j + 4u] + q);
            c = rot(9, c + ((d & a) | ((d & b) | (a & b))) + x[j + 8u] + q);
            b = rot(13, b + ((c & d) | ((c & a) | (d & a))) + x[j + 12u] + q);
            j += 1u;
        }

        let mut j = 0u;
        let q = 0x6ed9eba1u32;
        while j < 8u {
            let jj = if j > 2u { j - 3u } else { j };
            a = rot(3, a + (b ^ c ^ d) + x[jj] + q);
            d = rot(9, d + (a ^ b ^ c) + x[jj + 8u] + q);
            c = rot(11, c + (d ^ a ^ b) + x[jj + 4u] + q);
            b = rot(15, b + (c ^ d ^ a) + x[jj + 12u] + q);
            j += 2u;
        }

        a += aa; b += bb; c += cc; d += dd;
        i += 64u;
    }
    return {a: a, b: b, c: c, d: d};
}

pub fn md4_str(msg: &[u8]) -> ~str {
    let {a, b, c, d} = md4(msg);
    fn app(a: u32, b: u32, c: u32, d: u32, f: fn(u32)) {
        f(a); f(b); f(c); f(d);
    }
    let mut result = ~"";
    do app(a, b, c, d) |u| {
        let mut i = 0u32;
        while i < 4u32 {
            let byte = (u >> (i * 8u32)) as u8;
            if byte <= 16u8 { result += ~"0"; }
            result += uint::to_str(byte as uint, 16u);
            i += 1u32;
        }
    }
    result
}

pub fn md4_text(msg: &str) -> ~str { md4_str(str::to_bytes(msg)) }

#[test]
fn test_md4() {
    assert md4_text(~"") == ~"31d6cfe0d16ae931b73c59d7e0c089c0";
    assert md4_text(~"a") == ~"bde52cb31de33e46245e05fbdbd6fb24";
    assert md4_text(~"abc") == ~"a448017aaf21d8525fc10ae87aa6729d";
    assert md4_text(~"message digest") == ~"d9130a8164549fe818874806e1c7014b";
    assert md4_text(~"abcdefghijklmnopqrstuvwxyz") ==
        ~"d79e1c308aa5bbcdeea8ed63df412da9";
    assert md4_text(~"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\
                     0123456789") == ~"043f8582f241db351ce627e153e7f0e4";
    assert md4_text(~"1234567890123456789012345678901234567890123456789\
                     0123456789012345678901234567890") ==
        ~"e33b4ddc9c38f2199c3e7b164fcc0536";
}