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}