nx_rsa_pkcs1_v1_5_sha256_4096_real_test.nx source
↩ module page · 116 lines · 3986 B
1// nx_rsa_pkcs1_v1_5_sha256_4096_real_test.nx -- REAL RSA-4096 verify
2// against an openssl-generated keypair + signature.
3//
4// Proves the full PKCS1v1.5-SHA256 + RSA-4096 mod-exp + u4096_load_be
5// pipeline shipped this session works end-to-end against bytes
6// produced by a real production toolchain (openssl). No TLS, no
7// X.509, no PEM parsing -- just the load-bearing math + padding.
8//
9// Test fixtures (must exist before running):
10// /tmp/rsa4096_test_n.hex -- 1024-char hex of the 4096-bit modulus
11// + trailing newline
12// /tmp/rsa4096_test_msg.txt -- 23-byte message "hello-rsa4096-substrate"
13// /tmp/rsa4096_test.sig -- 512-byte raw RSA-PKCS1v1.5-SHA256 signature
14//
15// Generated by (host-side):
16// openssl genrsa -out rsa4096_test.key 4096
17// openssl rsa -in rsa4096_test.key -modulus -noout | sed 's/Modulus=//' \
18// > rsa4096_test_n.hex
19// echo -n 'hello-rsa4096-substrate' > rsa4096_test_msg.txt
20// openssl dgst -sha256 -sign rsa4096_test.key -out rsa4096_test.sig \
21// rsa4096_test_msg.txt
22//
23// expect_exit: 0
24
25import "nx_syscalls.nx"
26import "nx_u4096.nx"
27import "nx_rsa_pkcs1_v1_5_sha256_4096.nx"
28
29// Decode one hex char (ASCII) to nibble 0..15. Returns -1 on bad.
30func _hex_nibble(c: u8) -> i64 {
31 let ci: i64 = c as i64
32 if ci >= 48 {
33 if ci <= 57 { return ci - 48 } // 0..9
34 }
35 if ci >= 65 {
36 if ci <= 70 { return ci - 65 + 10 } // A..F
37 }
38 if ci >= 97 {
39 if ci <= 102 { return ci - 97 + 10 } // a..f
40 }
41 return 0 - 1
42}
43
44// Read entire file into out (caller-sized cap). Returns bytes read or
45// -1 on open fail.
46func _read_file(path: *u8, out: *u8, cap: i64) -> i64 {
47 let fd: i64 = sys_openat_rd(path)
48 if fd < 0 { return 0 - 1 }
49 var total: i64 = 0
50 var keep: i64 = 1
51 while keep == 1 {
52 let r: i64 = sys_read(fd, (out as i64 + total) as *u8, cap - total)
53 if r <= 0 { keep = 0 }
54 else {
55 total = total + r
56 if total >= cap { keep = 0 }
57 }
58 }
59 sys_close(fd)
60 return total
61}
62
63func main() -> i64 {
64 // ---- Load n (1024 hex chars + maybe trailing \n) ----
65 let n_hex_path: *u8 = "/tmp/rsa4096_test_n.hex\x00"
66 let n_hex_buf: *u8 = sys_mmap(2048)
67 let n_hex_n: i64 = _read_file(n_hex_path, n_hex_buf, 2048)
68 if n_hex_n < 1024 { return 1 }
69
70 // Decode 1024 hex chars -> 512 raw bytes
71 let n_bytes: *u8 = sys_mmap(512)
72 var i: i64 = 0
73 while i < 512 {
74 let hi: i64 = _hex_nibble(n_hex_buf[i * 2])
75 let lo: i64 = _hex_nibble(n_hex_buf[i * 2 + 1])
76 if hi < 0 { return 2 }
77 if lo < 0 { return 3 }
78 n_bytes[i] = ((hi << 4) | lo) as u8
79 i = i + 1
80 }
81
82 let n: *i64 = u4096_alloc()
83 u4096_load_be(n, n_bytes)
84
85 // ---- Load msg ----
86 let msg_path: *u8 = "/tmp/rsa4096_test_msg.txt\x00"
87 let msg_buf: *u8 = sys_mmap(128)
88 let msg_n: i64 = _read_file(msg_path, msg_buf, 128)
89 if msg_n != 23 { return 4 }
90
91 // ---- Load signature (raw 512 bytes) ----
92 let sig_path: *u8 = "/tmp/rsa4096_test.sig\x00"
93 let sig_buf: *u8 = sys_mmap(512)
94 let sig_n: i64 = _read_file(sig_path, sig_buf, 512)
95 if sig_n != 512 { return 5 }
96
97 // ---- Verify ----
98 let v: i64 = rsa_pkcs1_v1_5_sha256_4096_verify(msg_buf, msg_n,
99 sig_buf, n, 65537)
100 if v != NX_RSA_PKCS1_V15_4096_OK {
101 // Surface the verdict so we can diagnose if it fails.
102 return 10 + v
103 }
104
105 // ---- Negative case: flip one byte of msg, must NOT verify ----
106 msg_buf[0] = (msg_buf[0] ^ 0x01) as u8
107 let v2: i64 = rsa_pkcs1_v1_5_sha256_4096_verify(msg_buf, msg_n,
108 sig_buf, n, 65537)
109 if v2 == NX_RSA_PKCS1_V15_4096_OK { return 20 } // must NOT pass
110
111 // "PASS\n"
112 let ok: *u8 = sys_mmap(8)
113 ok[0]=80; ok[1]=65; ok[2]=83; ok[3]=83; ok[4]=10
114 sys_write(1, ok, 5)
115 return 0
116}