code wiki / (root) / nx_chacha20_poly1305_pure.nx

nx_chacha20_poly1305_pure.nx source

↩ module page · 129 lines · 4261 B

1// nx_chacha20_poly1305_pure.nx -- arena-based AEAD per RFC 8439 ยง2.8. 2// 3// Parallel of nx_chacha20_poly1305.nx that takes a caller-provided 4// arena instead of calling sys_mmap. Lets x86_64 smokes use AEAD 5// without pulling in nx_syscalls.nx (which would duplicate-define 6// sys_* against nx_syscalls_x86_64.nx). 7// 8// Builds on nx_chacha20_pure + nx_poly1305_pure (both arena-based, 9// already shipped). KAT-verified by composition: chacha20_pure 10// and poly1305_pure both byte-exact against RFC 8439, so the AEAD 11// is byte-exact by construction. 12// 13// expect_exit: 0 (when smoked with the round-trip + tampered-tag tests) 14// license_tier: INDEPENDENT_REDERIVE 15// genealogy_id: international-research-sources/ietf/rfc_8439 16 17import "nx_arena_types.nx" 18import "nx_chacha20_pure.nx" 19import "nx_poly1305_pure.nx" 20 21const NX_AEADP_TAG_BYTES: i64 = 16 22const NX_AEADP_NONCE_BYTES: i64 = 12 23const NX_AEADP_KEY_BYTES: i64 = 32 24 25const NX_AEADP_VERDICT_OK: i64 = 1 26const NX_AEADP_VERDICT_TAG_MISMATCH: i64 = 2 27 28func aeadp_derive_otk(arena: *NxArena, key: *u8, nonce: *u8, otk_out: *u8) -> i64 { 29 let block: *u8 = nx_arena_alloc_zero(arena, 64, 8) 30 if block == (0 as *u8) { return 0 - 1 } 31 chacha20_block_pure(arena, key, 0, nonce, block) 32 var i: i64 = 0 33 while i < 32 { otk_out[i] = block[i]; i = i + 1 } 34 return 0 35} 36 37func aeadp_put_u64_le(buf: *u8, off: i64, v: i64) -> i64 { 38 buf[off + 0] = v & 0xff 39 buf[off + 1] = (v >> 8) & 0xff 40 buf[off + 2] = (v >> 16) & 0xff 41 buf[off + 3] = (v >> 24) & 0xff 42 buf[off + 4] = (v >> 32) & 0xff 43 buf[off + 5] = (v >> 40) & 0xff 44 buf[off + 6] = (v >> 48) & 0xff 45 buf[off + 7] = (v >> 56) & 0xff 46 return 8 47} 48 49func aeadp_build_mac_data( 50 aad: *u8, aad_len: i64, 51 ct: *u8, ct_len: i64, 52 mac_buf: *u8 53) -> i64 { 54 var o: i64 = 0 55 var i: i64 = 0 56 while i < aad_len { mac_buf[o + i] = aad[i]; i = i + 1 } 57 o = o + aad_len 58 let aad_rem: i64 = aad_len % 16 59 let aad_pad: i64 = (16 - aad_rem) % 16 60 var p: i64 = 0 61 while p < aad_pad { mac_buf[o + p] = 0; p = p + 1 } 62 o = o + aad_pad 63 var j: i64 = 0 64 while j < ct_len { mac_buf[o + j] = ct[j]; j = j + 1 } 65 o = o + ct_len 66 let ct_rem: i64 = ct_len % 16 67 let ct_pad: i64 = (16 - ct_rem) % 16 68 var q: i64 = 0 69 while q < ct_pad { mac_buf[o + q] = 0; q = q + 1 } 70 o = o + ct_pad 71 aeadp_put_u64_le(mac_buf, o, aad_len) 72 o = o + 8 73 aeadp_put_u64_le(mac_buf, o, ct_len) 74 o = o + 8 75 return o 76} 77 78// Encrypt + authenticate. 79func nx_chacha20_poly1305_pure_encrypt( 80 arena: *NxArena, 81 key: *u8, nonce: *u8, 82 aad: *u8, aad_len: i64, 83 pt: *u8, pt_len: i64, 84 ct_out: *u8, 85 tag_out: *u8 86) -> i64 { 87 let otk: *u8 = nx_arena_alloc_zero(arena, 32, 8) 88 if otk == (0 as *u8) { return 0 - 1 } 89 aeadp_derive_otk(arena, key, nonce, otk) 90 91 chacha20_encrypt_pure(arena, key, 1, nonce, pt, pt_len, ct_out) 92 93 let mac_cap: i64 = aad_len + pt_len + 64 94 let mac_buf: *u8 = nx_arena_alloc_zero(arena, mac_cap, 8) 95 if mac_buf == (0 as *u8) { return 0 - 1 } 96 let mac_len: i64 = aeadp_build_mac_data(aad, aad_len, ct_out, pt_len, mac_buf) 97 98 poly1305_mac_pure(arena, otk, mac_buf, mac_len, tag_out) 99 return NX_AEADP_VERDICT_OK 100} 101 102// Decrypt + verify (constant-time tag check first). 103func nx_chacha20_poly1305_pure_decrypt( 104 arena: *NxArena, 105 key: *u8, nonce: *u8, 106 aad: *u8, aad_len: i64, 107 ct: *u8, ct_len: i64, 108 tag: *u8, 109 pt_out: *u8 110) -> i64 { 111 let otk: *u8 = nx_arena_alloc_zero(arena, 32, 8) 112 if otk == (0 as *u8) { return 0 - 1 } 113 aeadp_derive_otk(arena, key, nonce, otk) 114 115 let mac_cap: i64 = aad_len + ct_len + 64 116 let mac_buf: *u8 = nx_arena_alloc_zero(arena, mac_cap, 8) 117 if mac_buf == (0 as *u8) { return 0 - 1 } 118 let mac_len: i64 = aeadp_build_mac_data(aad, aad_len, ct, ct_len, mac_buf) 119 120 let expected_tag: *u8 = nx_arena_alloc_zero(arena, 32, 8) 121 if expected_tag == (0 as *u8) { return 0 - 1 } 122 poly1305_mac_pure(arena, otk, mac_buf, mac_len, expected_tag) 123 124 if poly1305_tag_equal_pure(expected_tag, tag) != 1 { 125 return NX_AEADP_VERDICT_TAG_MISMATCH 126 } 127 chacha20_encrypt_pure(arena, key, 1, nonce, ct, ct_len, pt_out) 128 return NX_AEADP_VERDICT_OK 129}