code wiki / (root) / nx_rsa_pkcs1_v1_5_sha512.nx

nx_rsa_pkcs1_v1_5_sha512.nx source

↩ module page · 133 lines · 5178 B

1// nx_rsa_pkcs1_v1_5_sha512.nx -- RSA-PKCS#1 v1.5 signature verify with 2// SHA-512, for RSA-2048 AND RSA-4096 keys. 3// 4// Parallel to nx_rsa_pkcs1_v1_5_sha256{,_4096} and nx_rsa_pkcs1_v1_5_sha384; 5// authored 2026-07-25 because publicreporting.cftc.gov signs its TLS-1.2 6// ServerKeyExchange with sha512WithRSAEncryption (signature_algorithms 7// hash=6 sig=1) and our TLS-1.2 client REFUSED it by name -- the last thing 8// blocking CFTC Commitments-of-Traders positioning data. 9// 10// Differs from the SHA-384 variant ONLY in: hash = SHA-512 (64 bytes), the 11// DigestInfo DER prefix, and PS length. RSA mod-exp is REUSED verbatim -- no 12// new bignum or padding logic is introduced here. 13// 14// RFC 8017 8.2.2: s -> m = s^e mod n; EM = 00 01 PS(FF..) 00 T H, 15// T = SHA-512 DigestInfo prefix (19 bytes), RFC 8017 A.2.4: 16// 30 51 30 0d 06 09 60 86 48 01 65 03 04 02 03 05 00 04 40 17// (vs SHA-384's ... 04 02 02 05 00 04 30 -- the OID's final byte is 03 18// not 02, and the digest OCTET STRING length is 0x40=64 not 0x30=48) 19// H = SHA-512(message) (64 bytes). 20// PS_LEN = 256-3-19-64 = 170 (RSA-2048) / 512-3-19-64 = 426 (RSA-4096). 21// 22// license_tier: INDEPENDENT_REDERIVE 23import "nx_syscalls.nx" 24import "nx_sha512.nx" 25import "nx_u2048.nx" 26import "nx_rsa2048_mod_exp.nx" 27import "nx_rsa2048_mont.nx" 28import "nx_u4096.nx" 29import "nx_rsa4096_mod_exp.nx" 30 31const NX_RSA_PKCS1_V15_512_OK: i64 = 1 32const NX_RSA_PKCS1_V15_512_S_OUT_OF_RANGE: i64 = 2 33const NX_RSA_PKCS1_V15_512_BAD_PAD: i64 = 3 34const NX_RSA_PKCS1_V15_512_HASH_MISMATCH: i64 = 4 35const NX_RSA_PKCS1_V15_512_VERDICT_N: i64 = 5 36 37const NX_RSA512_DI_LEN: i64 = 19 38const NX_RSA512_HASH_LEN: i64 = 64 39const NX_RSA512_PS_2048: i64 = 170 40const NX_RSA512_PS_4096: i64 = 426 41 42func nx_rsa_pkcs1_v15_512_verdict_is_valid(v: i64) -> i64 { 43 if v < NX_RSA_PKCS1_V15_512_OK { return 0 } 44 if v >= NX_RSA_PKCS1_V15_512_VERDICT_N { return 0 } 45 return 1 46} 47 48// SHA-512 DigestInfo DER prefix, byte i (RFC 8017 A.2.4). 49func rsa_pkcs1_sha512_di_byte(i: i64) -> i64 { 50 if i == 0 { return 0x30 } 51 if i == 1 { return 0x51 } 52 if i == 2 { return 0x30 } 53 if i == 3 { return 0x0d } 54 if i == 4 { return 0x06 } 55 if i == 5 { return 0x09 } 56 if i == 6 { return 0x60 } 57 if i == 7 { return 0x86 } 58 if i == 8 { return 0x48 } 59 if i == 9 { return 0x01 } 60 if i == 10 { return 0x65 } 61 if i == 11 { return 0x03 } 62 if i == 12 { return 0x04 } 63 if i == 13 { return 0x02 } 64 if i == 14 { return 0x03 } 65 if i == 15 { return 0x05 } 66 if i == 16 { return 0x00 } 67 if i == 17 { return 0x04 } 68 if i == 18 { return 0x40 } 69 return 0 70} 71 72// Shared EM structural check given a recovered EM, its total byte length, 73// the precomputed SHA-512 of the message, and the PS length. 74func _rsa512_check_em(em: *u8, em_len: i64, h: *u8, ps_len: i64) -> i64 { 75 if (em[0] & 0xff) != 0x00 { return NX_RSA_PKCS1_V15_512_BAD_PAD } 76 if (em[1] & 0xff) != 0x01 { return NX_RSA_PKCS1_V15_512_BAD_PAD } 77 var i: i64 = 0 78 while i < ps_len { 79 if (em[2 + i] & 0xff) != 0xff { return NX_RSA_PKCS1_V15_512_BAD_PAD } 80 i = i + 1 81 } 82 if (em[2 + ps_len] & 0xff) != 0x00 { return NX_RSA_PKCS1_V15_512_BAD_PAD } 83 let di_off: i64 = 2 + ps_len + 1 84 i = 0 85 while i < NX_RSA512_DI_LEN { 86 let expected: i64 = rsa_pkcs1_sha512_di_byte(i) 87 if (em[di_off + i] & 0xff) != (expected & 0xff) { return NX_RSA_PKCS1_V15_512_BAD_PAD } 88 i = i + 1 89 } 90 let h_off: i64 = di_off + NX_RSA512_DI_LEN 91 i = 0 92 while i < NX_RSA512_HASH_LEN { 93 if (em[h_off + i] & 0xff) != (h[i] & 0xff) { return NX_RSA_PKCS1_V15_512_HASH_MISMATCH } 94 i = i + 1 95 } 96 return NX_RSA_PKCS1_V15_512_OK 97} 98 99// RSA-2048: sig_bytes is 256 bytes BE, n_2048 is a 64-limb LE U2048. 100func rsa_pkcs1_v1_5_sha512_verify(msg: *u8, msg_len: i64, 101 sig_bytes: *u8, 102 n_2048: *i64, e_i64: i64) -> i64 { 103 let s_int: *i64 = u2048_alloc() 104 u2048_load_be(s_int, sig_bytes) 105 let m_int: *i64 = u2048_alloc() 106 let rc: i64 = rsa2048_mod_exp_mont(m_int, s_int, e_i64, n_2048) 107 if rc != NX_RSA2048_MONT_OK { return NX_RSA_PKCS1_V15_512_S_OUT_OF_RANGE } 108 let em: *u8 = sys_mmap(256) 109 u2048_store_be(em, m_int) 110 let h: *u8 = sys_mmap(64) 111 sha512_digest(msg, msg_len, h) 112 return _rsa512_check_em(em, 256, h, NX_RSA512_PS_2048) 113} 114 115// RSA-4096: sig_bytes is 512 bytes BE, n_4096 is a 128-limb LE U4096. 116func rsa_pkcs1_v1_5_sha512_4096_verify(msg: *u8, msg_len: i64, 117 sig_bytes: *u8, 118 n_4096: *i64, e_i64: i64) -> i64 { 119 let s_int: *i64 = u4096_alloc() 120 u4096_load_be(s_int, sig_bytes) 121 let m_int: *i64 = u4096_alloc() 122 let rc: i64 = rsa4096_mod_exp(m_int, s_int, e_i64, n_4096) 123 if rc != NX_RSA4096_MOD_EXP_OK { return NX_RSA_PKCS1_V15_512_S_OUT_OF_RANGE } 124 let em: *u8 = sys_mmap(512) 125 u4096_store_be(em, m_int) 126 let h: *u8 = sys_mmap(64) 127 sha512_digest(msg, msg_len, h) 128 return _rsa512_check_em(em, 512, h, NX_RSA512_PS_4096) 129} 130 131func main() -> i64 { 132 return 0 133}