hmac_md5.nx source
↩ module page · 92 lines · 2680 B
1// hmac_md5.nx -- HMAC with MD5 (RFC 2104).
2//
3// Like HMAC-SHA1: even though plain MD5 is broken for signatures,
4// HMAC-MD5 remains safe for authentication because HMAC relies
5// on pseudo-randomness of the keyed mix, not collision resistance.
6// Still on the wire in:
7// - RADIUS Access-Request Message-Authenticator (RFC 3579)
8// - CRAM-MD5 SASL auth (IMAP, POP3, SMTP legacy)
9// - Microsoft MS-CHAP-v2 password challenge
10// - NTLMv1 / NTLMv2 (the real world's Windows auth)
11//
12// Composes md5.nx with standard ipad/opad construction.
13//
14// Invariants:
15// HM1 Output = 16 bytes (MD5 tag length).
16// HM2 Matches RFC 2104 Appendix test vectors.
17
18import "syscalls.nx"
19import "nx_md5_canonical.nx"
20
21const HMAC_MD5_BLOCK: i64 = 64
22const HMAC_MD5_OUT: i64 = 16
23
24func hmac_md5(key: *u8, key_len: i64,
25 msg: *u8, msg_len: i64,
26 out: *u8) -> i64 {
27 let k_prime: *u8 = sys_mmap(HMAC_MD5_BLOCK + 16)
28 var i: i64 = 0
29 while i < HMAC_MD5_BLOCK { k_prime[i] = 0; i = i + 1 }
30
31 if key_len > HMAC_MD5_BLOCK {
32 md5(key, key_len, k_prime)
33 } else {
34 i = 0
35 while i < key_len {
36 k_prime[i] = key[i]
37 i = i + 1
38 }
39 }
40
41 // Inner: MD5(ipad || msg).
42 let inner_len: i64 = HMAC_MD5_BLOCK + msg_len
43 let inner_buf: *u8 = sys_mmap(inner_len + 16)
44 i = 0
45 while i < HMAC_MD5_BLOCK {
46 inner_buf[i] = k_prime[i] ^ 0x36
47 i = i + 1
48 }
49 i = 0
50 while i < msg_len {
51 inner_buf[HMAC_MD5_BLOCK + i] = msg[i]
52 i = i + 1
53 }
54 let inner_hash: *u8 = sys_mmap(32)
55 md5(inner_buf, inner_len, inner_hash)
56
57 // Outer: MD5(opad || inner_hash).
58 let outer_len: i64 = HMAC_MD5_BLOCK + HMAC_MD5_OUT
59 let outer_buf: *u8 = sys_mmap(outer_len + 16)
60 i = 0
61 while i < HMAC_MD5_BLOCK {
62 outer_buf[i] = k_prime[i] ^ 0x5C
63 i = i + 1
64 }
65 i = 0
66 while i < HMAC_MD5_OUT {
67 outer_buf[HMAC_MD5_BLOCK + i] = inner_hash[i]
68 i = i + 1
69 }
70 md5(outer_buf, outer_len, out)
71 return 0
72}
73
74// Compile-only smoke.
75func main() -> i64 {
76 let out: *u8 = sys_mmap(32)
77 // RFC 2104 test vector 1:
78 // key = 0x0b repeated 16 times, msg = "Hi There"
79 // HMAC-MD5 = 9294727a3638bb1c13f48ef8158bfc9d
80 let key: *u8 = sys_mmap(32)
81 var i: i64 = 0
82 while i < 16 {
83 key[i] = 0x0B
84 i = i + 1
85 }
86 hmac_md5(key, 16, "Hi There", 8, out)
87 if out[0] != 0x92 { return 1 }
88 if out[1] != 0x94 { return 2 }
89 if out[2] != 0x72 { return 3 }
90 if out[15] != 0x9D { return 4 }
91 return 0
92}