code wiki / (root) / hmac_md5.nx

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}