code wiki / (root) / hmac_sha384.nx

hmac_sha384.nx source

↩ module page · 85 lines · 2945 B

1// hmac_sha384.nx -- HMAC-SHA-384 (RFC 2104 / FIPS 198-1). 2// 3// Parallel to hmac.nx but keyed on SHA-384 instead of SHA-256. 4// Required for TLS 1.3 cipher suites that negotiate SHA-384 in 5// the key schedule (e.g. TLS_AES_256_GCM_SHA384). 6// 7// Differences from hmac.nx: 8// - Block size B = 128 bytes (SHA-384 / SHA-512 block), not 64. 9// - Hash output = 48 bytes (SHA-384), not 32. 10// - Key-pre-hash uses sha384_digest for oversized keys. 11// 12// Key processing (RFC 2104) remains identical in structure: 13// K' = H(K) if len(K) > B 14// K' = K || zeros if len(K) < B 15// K' = K if len(K) == B 16// ipad / opad bytes XOR'd against K' block. 17 18import "syscalls.nx" 19import "sha512.nx" 20 21const HMAC384_BLOCK: i64 = 128 22const HMAC384_HASH: i64 = 48 23const IPAD_384: i64 = 0x36 24const OPAD_384: i64 = 0x5C 25 26func hmac_sha384(key: *u8, key_len: i64, msg: *u8, msg_len: i64, 27 out: *u8) -> i64 { 28 // Step 1: derive K'. HMAC384_BLOCK-sized zero-padded buffer. 29 let kp: *u8 = sys_mmap(HMAC384_BLOCK) 30 var i: i64 = 0 31 while i < HMAC384_BLOCK { kp[i] = 0; i = i + 1 } 32 if key_len > HMAC384_BLOCK { 33 sha384_digest(key, key_len, kp) 34 } else { 35 var j: i64 = 0 36 while j < key_len { kp[j] = key[j]; j = j + 1 } 37 } 38 39 // Step 2: inner pad + hash. 40 let inner_key: *u8 = sys_mmap(HMAC384_BLOCK) 41 let ii_raw: *u8 = sys_mmap(512) 42 let ii: *Sha512 = ii_raw as *Sha512 43 sha384_init(ii) 44 var b: i64 = 0 45 while b < HMAC384_BLOCK { 46 inner_key[b] = kp[b] ^ IPAD_384 47 b = b + 1 48 } 49 sha512_update(ii, inner_key, HMAC384_BLOCK) 50 sha512_update(ii, msg, msg_len) 51 let inner_digest_full: *u8 = sys_mmap(64) 52 sha512_final(ii, inner_digest_full) 53 let inner_digest: *u8 = inner_digest_full // first 48 bytes = SHA-384 digest 54 55 // Step 3: outer pad + hash. 56 let outer_key: *u8 = sys_mmap(HMAC384_BLOCK) 57 let oi_raw: *u8 = sys_mmap(512) 58 let oi: *Sha512 = oi_raw as *Sha512 59 sha384_init(oi) 60 b = 0 61 while b < HMAC384_BLOCK { 62 outer_key[b] = kp[b] ^ OPAD_384 63 b = b + 1 64 } 65 sha512_update(oi, outer_key, HMAC384_BLOCK) 66 sha512_update(oi, inner_digest, HMAC384_HASH) 67 // Emit 64 bytes full then truncate to first 48. 68 let out_full: *u8 = sys_mmap(64) 69 sha512_final(oi, out_full) 70 var k: i64 = 0 71 while k < HMAC384_HASH { out[k] = out_full[k]; k = k + 1 } 72 return 0 73} 74 75// Compile-only smoke. RFC 4231 test case 1: key=0x0b*20, 76// data="Hi There" -> afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c7cebc59cfaea9ea9076ede7f4af152e8b2fa9cb6 77func main() -> i64 { 78 let key: *u8 = sys_mmap(20) 79 let msg: *u8 = "Hi There" 80 let tag: *u8 = sys_mmap(48) 81 var i: i64 = 0 82 while i < 20 { key[i] = 0x0B; i = i + 1 } 83 hmac_sha384(key, 20, msg, 8, tag) 84 return tag[0] as i64 85}