code wiki / (root) / nx_rsa_pkcs1_v1_5_sha256.nx

nx_rsa_pkcs1_v1_5_sha256.nx source

↩ module page · 142 lines · 5052 B

1// nx_rsa_pkcs1_v1_5_sha256.nx -- RSA-PKCS#1 v1.5 signature verify 2// with SHA-256 hash, for RSA-2048 keys. 3// 4// RFC 8017 ยง8.2.2 RSASSA-PKCS1-v1_5-VERIFY (k=256 bytes for RSA-2048): 5// 1. s -> m = s^e mod n (RSA modular exponentiation) 6// 2. Encode message into EM_test: 7// EM_test = 0x00 || 0x01 || PS (FF*202) || 0x00 || T || H 8// where T = SHA-256 DigestInfo DER prefix (19 bytes): 9// 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 10// and H = SHA-256(message) (32 bytes). 11// 3. Convert m to 256-byte big-endian EM. 12// 4. Compare EM == EM_test byte-by-byte. 13// 14// API: 15// rsa_pkcs1_v1_5_sha256_verify(msg, msg_len, sig_bytes, n_2048, e_i64) -> verdict 16// 17// Sealed verdict: 18// NX_RSA_PKCS1_V15_OK valid signature 19// NX_RSA_PKCS1_V15_S_OUT_OF_RANGE s_int >= n 20// NX_RSA_PKCS1_V15_BAD_PAD padding (PS / leading bytes / T) mismatch 21// NX_RSA_PKCS1_V15_HASH_MISMATCH trailing 32 bytes != SHA-256(msg) 22// 23// Composes: 24// - sha256_digest 25// - u2048_load_be / u2048_store_be 26// - rsa2048_mod_exp 27// 28// license_tier: INDEPENDENT_REDERIVE 29// genealogy_id: international-research-sources/ietf/rfc_8017 + nist/fips_180_4 30// lineage_id: nishi_rsa_pkcs1_v1_5_sha256_q10 31 32// nx_safety_envelope: 33// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 34// sil_target: SIL2 35// evidence: [bulk_applied_2026-05-20, rsa2048-pkcs1v15-sha256-verify] 36// verdict: NOT_YET_EVALUATED 37 38import "nx_syscalls.nx" 39import "nx_sha256.nx" 40import "nx_u2048.nx" 41import "nx_rsa2048_mod_exp.nx" 42import "nx_rsa2048_mont.nx" 43 44const NX_RSA_PKCS1_V15_OK: i64 = 1 45const NX_RSA_PKCS1_V15_S_OUT_OF_RANGE: i64 = 2 46const NX_RSA_PKCS1_V15_BAD_PAD: i64 = 3 47const NX_RSA_PKCS1_V15_HASH_MISMATCH: i64 = 4 48const NX_RSA_PKCS1_V15_VERDICT_N: i64 = 5 49 50func rsa_pkcs1_v1_5_verdict_is_valid(v: i64) -> i64 { 51 if v < NX_RSA_PKCS1_V15_OK { return 0 } 52 if v >= NX_RSA_PKCS1_V15_VERDICT_N { return 0 } 53 return 1 54} 55 56// Returns 1 if byte b matches expected SHA-256 DigestInfo prefix byte 57// at position i (0..18), else 0. 58func rsa_pkcs1_sha256_di_byte(i: i64) -> i64 { 59 if i == 0 { return 0x30 } 60 if i == 1 { return 0x31 } 61 if i == 2 { return 0x30 } 62 if i == 3 { return 0x0d } 63 if i == 4 { return 0x06 } 64 if i == 5 { return 0x09 } 65 if i == 6 { return 0x60 } 66 if i == 7 { return 0x86 } 67 if i == 8 { return 0x48 } 68 if i == 9 { return 0x01 } 69 if i == 10 { return 0x65 } 70 if i == 11 { return 0x03 } 71 if i == 12 { return 0x04 } 72 if i == 13 { return 0x02 } 73 if i == 14 { return 0x01 } 74 if i == 15 { return 0x05 } 75 if i == 16 { return 0x00 } 76 if i == 17 { return 0x04 } 77 if i == 18 { return 0x20 } 78 return 0 79} 80 81// Verify RSA-PKCS#1 v1.5 signature with SHA-256. 82// 83// msg: message bytes (TBS for X.509 outer-sig verify) 84// msg_len: msg byte length 85// sig_bytes: 256-byte big-endian signature 86// n_2048: 64-limb LE U2048 modulus 87// e_i64: public exponent (typically 65537) 88// 89// Returns NX_RSA_PKCS1_V15_OK on valid, non-OK verdict otherwise. 90func rsa_pkcs1_v1_5_sha256_verify(msg: *u8, msg_len: i64, 91 sig_bytes: *u8, 92 n_2048: *i64, e_i64: i64) -> i64 { 93 // Step 1: load sig as u2048, compute m = s^e mod n. 94 let s_int: *i64 = u2048_alloc() 95 u2048_load_be(s_int, sig_bytes) 96 let m_int: *i64 = u2048_alloc() 97 let rc: i64 = rsa2048_mod_exp_mont(m_int, s_int, e_i64, n_2048) 98 if rc != NX_RSA2048_MONT_OK { return NX_RSA_PKCS1_V15_S_OUT_OF_RANGE } 99 100 // Step 2: convert m to 256-byte BE EM. 101 let em: *u8 = sys_mmap(256) 102 u2048_store_be(em, m_int) 103 104 // Step 3: compute SHA-256(msg). 105 let h: *u8 = sys_mmap(32) 106 sha256_digest(msg, msg_len, h) 107 108 // Step 4: byte-by-byte structural check of EM. 109 // EM[0] == 0x00 110 // EM[1] == 0x01 111 // EM[2..2+PS_LEN) == 0xFF (PS_LEN = 256 - 3 - 19 - 32 = 202) 112 // EM[2+PS_LEN] == 0x00 113 // EM[2+PS_LEN+1 .. 2+PS_LEN+1+19) == DigestInfo prefix (19 bytes) 114 // EM[2+PS_LEN+1+19 .. 256) == SHA-256(msg) (32 bytes) 115 if (em[0] & 0xff) != 0x00 { return NX_RSA_PKCS1_V15_BAD_PAD } 116 if (em[1] & 0xff) != 0x01 { return NX_RSA_PKCS1_V15_BAD_PAD } 117 let ps_len: i64 = 202 118 var i: i64 = 0 119 while i < ps_len { 120 if (em[2 + i] & 0xff) != 0xff { return NX_RSA_PKCS1_V15_BAD_PAD } 121 i = i + 1 122 } 123 if (em[2 + ps_len] & 0xff) != 0x00 { return NX_RSA_PKCS1_V15_BAD_PAD } 124 let di_off: i64 = 2 + ps_len + 1 125 i = 0 126 while i < 19 { 127 let expected: i64 = rsa_pkcs1_sha256_di_byte(i) 128 if (em[di_off + i] & 0xff) != (expected & 0xff) { return NX_RSA_PKCS1_V15_BAD_PAD } 129 i = i + 1 130 } 131 let h_off: i64 = di_off + 19 132 i = 0 133 while i < 32 { 134 if (em[h_off + i] & 0xff) != (h[i] & 0xff) { return NX_RSA_PKCS1_V15_HASH_MISMATCH } 135 i = i + 1 136 } 137 return NX_RSA_PKCS1_V15_OK 138} 139 140func main() -> i64 { 141 return 0 142}