code wiki / (root) / nx_mfa_gate.nx

nx_mfa_gate.nx source

↩ module page · 45 lines · 3150 B

1// nx_mfa_gate.nx -- KAT for admin MFA. Proves the TOTP-SHA1 core against the RFC 6238 Appendix B official 2// test vectors (the non-novel-standard 3rd-party proof), the base32 secret round-trip, and mfa_verify's 3// skew-window logic (accept current + adjacent step, reject wrong code / out-of-window / wrong length). 4// exit 0 = pass, N = assertion N failed. 5import "nx_mfa.nx" 6import "nx_assert.nx" 7 8func main() -> i64 { 9 let seed: *u8 = "12345678901234567890" as *u8 // RFC 6238 App.B SHA-1 seed (20 ASCII bytes) 10 11 // --- RFC 6238 Appendix B TOTP-SHA1 KAT (8 digits) -- the official 3rd-party vectors --- 12 if totp_sha1_value(seed, 20, 59, 30, 8) != 94287082 { return 1 } 13 if totp_sha1_value(seed, 20, 1111111109, 30, 8) != 7081804 { return 2 } // 07081804 14 if totp_sha1_value(seed, 20, 1111111111, 30, 8) != 14050471 { return 3 } 15 if totp_sha1_value(seed, 20, 1234567890, 30, 8) != 89005924 { return 4 } 16 if totp_sha1_value(seed, 20, 2000000000, 30, 8) != 69279037 { return 5 } 17 if totp_sha1_value(seed, 20, 20000000000, 30, 8) != 65353130 { return 6 } 18 19 // --- base32 secret round-trip (the form the authenticator + the stored credential use) --- 20 let b32: *u8 = sys_mmap(64); let b32len: i64 = base32_encode(seed, 20, b32) 21 let back: *u8 = sys_mmap(64); let backlen: i64 = base32_decode(b32, b32len, back) 22 if backlen != 20 { return 7 } 23 var i: i64 = 0; while i < 20 { if back[i] != seed[i] { return 8 } i = i + 1 } 24 25 // --- mfa_verify skew window: derive live codes, then verify --- 26 let T: i64 = 1111111111 27 let base: i64 = T / 30 28 let cur: *u8 = sys_mmap(16); totp_sha1_render(hotp_sha1_value(seed, 20, base, 6), 6, cur) 29 let m1: *u8 = sys_mmap(16); totp_sha1_render(hotp_sha1_value(seed, 20, base - 1, 6), 6, m1) 30 let m2: *u8 = sys_mmap(16); totp_sha1_render(hotp_sha1_value(seed, 20, base - 2, 6), 6, m2) 31 nx_puts_err("current code="); sys_write(2, cur, 6); nx_puts_err(" prev-step code="); sys_write(2, m1, 6); nx_puts_err("\n" as *u8) 32 33 if mfa_verify(b32, b32len, cur, 6, T, 1) != 1 { return 9 } // current step accepted 34 if mfa_verify(b32, b32len, "000000" as *u8, 6, T, 1) != 0 { return 10 } // wrong code rejected 35 if mfa_verify(b32, b32len, m1, 6, T, 1) != 1 { return 11 } // adjacent step accepted (clock skew) 36 if mfa_verify(b32, b32len, m2, 6, T, 1) != 0 { return 12 } // 2 steps away rejected (outside window) 37 if mfa_verify(b32, b32len, cur, 5, T, 1) != 0 { return 13 } // wrong length rejected 38 if mfa_enrolled(b32, b32len) != 1 { return 14 } 39 if mfa_enrolled(b32, 0) != 0 { return 15 } // no secret -> not enrolled 40 41 nx_puts_err("--- vs Google Authenticator / Authy / Duo / Microsoft Authenticator ---\n" as *u8) 42 nx_puts_err("TOTP-SHA1 second factor = PARITY (identical RFC 6238 codes, fully interoperable with every authenticator app). EXCEEDS: sovereign (no cloud/SaaS, the secret never leaves your hardware), deterministic, constant-time compare, +/-1 step skew.\n" as *u8) 43 nx_puts_err("nx_mfa_gate verdict=GREEN pass=15\n" as *u8) 44 return 0 45}