code wiki / (root) / nx_rsa_pkcs1_v1_5_sha256_4096.nx

nx_rsa_pkcs1_v1_5_sha256_4096.nx source

↩ module page · 123 lines · 5093 B

1// nx_rsa_pkcs1_v1_5_sha256_4096.nx -- RSA-PKCS#1 v1.5 signature verify 2// with SHA-256 hash, for RSA-4096 keys. 3// 4// Parallel to nx_rsa_pkcs1_v1_5_sha256 (the RSA-2048 variant); 5// kept as a separate module rather than parameterizing the existing 6// module so the existing 2048 callers continue to compile unchanged. 7// 8// RFC 8017 ยง8.2.2 RSASSA-PKCS1-v1_5-VERIFY (k=512 bytes for RSA-4096): 9// 1. s -> m = s^e mod n (4096-bit RSA modular exponentiation) 10// 2. Encode message into EM_test: 11// EM_test = 0x00 || 0x01 || PS (FF*458) || 0x00 || T || H 12// where T = SHA-256 DigestInfo DER prefix (19 bytes): 13// 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 14// and H = SHA-256(message) (32 bytes). 15// PS_LEN = 512 - 3 - 19 - 32 = 458 bytes of 0xFF. 16// 3. Convert m to 512-byte big-endian EM. 17// 4. Compare EM == EM_test byte-by-byte. 18// 19// API: 20// rsa_pkcs1_v1_5_sha256_4096_verify(msg, msg_len, sig_bytes, n_4096, e_i64) -> verdict 21// 22// Sealed verdict (parallel to 2048-variant; same shape so cert-chain 23// verifier can map verdicts uniformly): 24// NX_RSA_PKCS1_V15_4096_OK valid signature 25// NX_RSA_PKCS1_V15_4096_S_OUT_OF_RANGE s_int >= n 26// NX_RSA_PKCS1_V15_4096_BAD_PAD padding mismatch 27// NX_RSA_PKCS1_V15_4096_HASH_MISMATCH trailing 32 bytes != SHA-256(msg) 28// 29// Composes: 30// - sha256_digest (already shipped) 31// - u4096_load_be / u4096_store_be (stone 1) 32// - rsa4096_mod_exp (stone 3) 33// - rsa_pkcs1_sha256_di_byte (shared with 2048 variant) 34// 35// Unblocks: L11 step 2d -> 2e (LE E7 -> ISRG Root X1 chain validates; 36// nx_acme daemon can drive state machine end-to-end against LE). 37// 38// license_tier: INDEPENDENT_REDERIVE 39// genealogy_id: international-research-sources/ietf/rfc_8017 + nist/fips_180_4 40// lineage_id: nishi_rsa_pkcs1_v1_5_sha256_4096_q1 41 42import "nx_syscalls.nx" 43import "nx_sha256.nx" 44import "nx_u4096.nx" 45import "nx_rsa4096_mod_exp.nx" 46import "nx_rsa4096_mont.nx" // leak-free Montgomery-4096 (KAT-gated byte-identical, scratch freed) 47import "nx_rsa_pkcs1_v1_5_sha256.nx" // for rsa_pkcs1_sha256_di_byte 48const NX_MAGIC_4096: i64 = 4096 49 50const NX_RSA_PKCS1_V15_4096_OK: i64 = 1 51const NX_RSA_PKCS1_V15_4096_S_OUT_OF_RANGE: i64 = 2 52const NX_RSA_PKCS1_V15_4096_BAD_PAD: i64 = 3 53const NX_RSA_PKCS1_V15_4096_HASH_MISMATCH: i64 = 4 54const NX_RSA_PKCS1_V15_4096_VERDICT_N: i64 = 5 55 56func rsa_pkcs1_v1_5_4096_verdict_is_valid(v: i64) -> i64 { 57 if v < NX_RSA_PKCS1_V15_4096_OK { return 0 } 58 if v >= NX_RSA_PKCS1_V15_4096_VERDICT_N { return 0 } 59 return 1 60} 61 62// Verify RSA-PKCS#1 v1.5 signature with SHA-256 over a 4096-bit RSA key. 63// 64// msg: message bytes (TBS for X.509 outer-sig verify) 65// msg_len: msg byte length 66// sig_bytes: 512-byte big-endian signature 67// n_4096: 128-limb LE U4096 modulus 68// e_i64: public exponent (typically 65537) 69// 70// Returns NX_RSA_PKCS1_V15_4096_OK on valid, non-OK verdict otherwise. 71func rsa_pkcs1_v1_5_sha256_4096_verify(msg: *u8, msg_len: i64, 72 sig_bytes: *u8, 73 n_4096: *i64, e_i64: i64) -> i64 { 74 // Step 1: load sig as u4096, compute m = s^e mod n. 75 let s_int: *i64 = u4096_alloc() 76 u4096_load_be(s_int, sig_bytes) 77 let m_int: *i64 = u4096_alloc() 78 let rc: i64 = rsa4096_mod_exp_mont(m_int, s_int, e_i64, n_4096) // leak-free Montgomery; KAT-proven == slow path 79 if rc != NX_RSA4096_MONT_OK { return NX_RSA_PKCS1_V15_4096_S_OUT_OF_RANGE } 80 81 // Step 2: convert m to 512-byte BE EM. 82 let em: *u8 = sys_mmap(512) 83 u4096_store_be(em, m_int) 84 85 // Step 3: compute SHA-256(msg). 86 let h: *u8 = sys_mmap(32) 87 sha256_digest(msg, msg_len, h) 88 89 // Step 4: byte-by-byte structural check of EM. 90 // EM[0] == 0x00 91 // EM[1] == 0x01 92 // EM[2..2+PS_LEN) == 0xFF (PS_LEN = 512 - 3 - 19 - 32 = 458) 93 // EM[2+PS_LEN] == 0x00 94 // EM[2+PS_LEN+1 .. 2+PS_LEN+1+19) == DigestInfo prefix (19 bytes) 95 // EM[2+PS_LEN+1+19 .. 512) == SHA-256(msg) (32 bytes) 96 if (em[0] & 0xff) != 0x00 { return NX_RSA_PKCS1_V15_4096_BAD_PAD } 97 if (em[1] & 0xff) != 0x01 { return NX_RSA_PKCS1_V15_4096_BAD_PAD } 98 let ps_len: i64 = 458 99 var i: i64 = 0 100 while i < ps_len { 101 if (em[2 + i] & 0xff) != 0xff { return NX_RSA_PKCS1_V15_4096_BAD_PAD } 102 i = i + 1 103 } 104 if (em[2 + ps_len] & 0xff) != 0x00 { return NX_RSA_PKCS1_V15_4096_BAD_PAD } 105 let di_off: i64 = 2 + ps_len + 1 106 i = 0 107 while i < 19 { 108 let expected: i64 = rsa_pkcs1_sha256_di_byte(i) 109 if (em[di_off + i] & 0xff) != (expected & 0xff) { return NX_RSA_PKCS1_V15_4096_BAD_PAD } 110 i = i + 1 111 } 112 let h_off: i64 = di_off + 19 113 i = 0 114 while i < 32 { 115 if (em[h_off + i] & 0xff) != (h[i] & 0xff) { return NX_RSA_PKCS1_V15_4096_HASH_MISMATCH } 116 i = i + 1 117 } 118 return NX_RSA_PKCS1_V15_4096_OK 119} 120 121func main() -> i64 { 122 return 0 123}