20#include <mbedtls/md.h>
21#include <mbedtls/rsa.h>
35 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
44 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
56 const uint8_t *sig,
size_t sig_len,
pc_rsa_hash hash)
63 mbedtls_rsa_context rsa;
64#if MBEDTLS_VERSION_MAJOR >= 3
65 mbedtls_rsa_init(&rsa);
67 mbedtls_rsa_init(&rsa, MBEDTLS_RSA_PKCS_V15, 0);
75 mbedtls_mpi_read_binary(&E, e_be4, 4);
77 int rc = mbedtls_rsa_import(&rsa, &N,
nullptr,
nullptr,
nullptr, &E);
80 rc = mbedtls_rsa_complete(&rsa);
84 const mbedtls_md_type_t md = sha512 ? MBEDTLS_MD_SHA512 : MBEDTLS_MD_SHA256;
97#if MBEDTLS_VERSION_MAJOR >= 3
98 rc = mbedtls_rsa_pkcs1_verify(&rsa, md, dlen, digest, sig);
100 rc = mbedtls_rsa_pkcs1_verify(&rsa,
nullptr,
nullptr, MBEDTLS_RSA_PUBLIC, md, dlen, digest, sig);
104 mbedtls_mpi_free(&N);
105 mbedtls_mpi_free(&E);
106 mbedtls_rsa_free(&rsa);
107 return rc == 0 ? 0 : -1;
119 size_t *digest_len,
const uint8_t **di,
size_t *di_len)
139static void pkcs1v15_encode(
const uint8_t *digest,
size_t digest_len,
const uint8_t *di,
size_t di_len,
142 const size_t total = di_len + digest_len;
146 memset(em + 2, 0xFF, pad_len);
147 em[2 + pad_len] = 0x00;
148 memcpy(em + 3 + pad_len, di, di_len);
149 memcpy(em + 3 + pad_len + di_len, digest, digest_len);
169 uint64_t cur = (uint64_t)p[i + j] + (uint64_t)a[i] * b[j] + carry;
170 p[i + j] = (uint32_t)cur;
179 uint64_t cur = (uint64_t)p[k] + carry;
180 p[k] = (uint32_t)cur;
196 for (
int bit = 2 *
PC_BN_LIMBS * 32 - 1; bit >= 0; bit--)
201 uint32_t nc = r[k] >> 31;
202 r[k] = (r[k] << 1) | carry;
205 r[0] |= (p[bit >> 5] >> (bit & 31)) & 1u;
225 uint64_t v = (uint64_t)r[k] - m[k] - borrow;
227 borrow = (v >> 32) & 1u;
246 prod[k] = base->
d[k];
249 bn_reduce_full(prod, n->
d, b.
d);
252 memset(r.
d, 0,
sizeof(r.
d));
256 while (top >= 0 && !((e >> top) & 1u))
260 for (
int i = top; i >= 0; i--)
262 bn_mul_full(r.
d, r.
d, prod);
263 bn_reduce_full(prod, n->
d, r.
d);
266 bn_mul_full(r.
d, b.
d, prod);
267 bn_reduce_full(prod, n->
d, r.
d);
281 prod[k] = base->
d[k];
284 bn_reduce_full(prod, n->
d, b.
d);
287 memset(r.
d, 0,
sizeof(r.
d));
291 while (top_limb >= 0 && exp->
d[top_limb] == 0)
303 while (top_bit >= 0 && !((exp->
d[top_limb] >> top_bit) & 1u))
308 for (
int limb = top_limb; limb >= 0; limb--)
310 int start = (limb == top_limb) ? top_bit : 31;
311 for (
int bit = start; bit >= 0; bit--)
313 bn_mul_full(r.
d, r.
d, prod);
314 bn_reduce_full(prod, n->
d, r.
d);
315 if ((exp->
d[limb] >> bit) & 1u)
317 bn_mul_full(r.
d, b.
d, prod);
318 bn_reduce_full(prod, n->
d, r.
d);
330 size_t digest_len = 0;
331 const uint8_t *di =
nullptr;
333 rsa_digest(msg, msg_len, hash, digest, &digest_len, &di, &di_len);
337 pkcs1v15_encode(digest, digest_len, di, di_len, em);
338 pc_secure_wipe(digest,
sizeof(digest));
348 pc_secure_wipe(em,
sizeof(em));
350 bn_modexp_full(&m_bn, &d_bn, &n_bn, &s_bn);
354 pc_secure_wipe(&n_bn,
sizeof(n_bn));
355 pc_secure_wipe(&d_bn,
sizeof(d_bn));
356 pc_secure_wipe(&m_bn,
sizeof(m_bn));
357 pc_secure_wipe(&s_bn,
sizeof(s_bn));
362 const uint8_t *sig,
size_t sig_len,
pc_rsa_hash hash)
379 uint32_t e = ((uint32_t)e_be4[0] << 24) | ((uint32_t)e_be4[1] << 16) | ((uint32_t)e_be4[2] << 8) | e_be4[3];
380 bn_modexp_pub(&s, e, &n, &m);
387 size_t digest_len = 0;
388 const uint8_t *di =
nullptr;
390 rsa_digest(msg, msg_len, hash, digest, &digest_len, &di, &di_len);
392 pkcs1v15_encode(digest, digest_len, di, di_len, expected);
void bn_to_bytes(uint8_t bytes[256], const pc_bignum *in)
Write a pc_bignum as a 256-byte big-endian array.
int bn_cmp(const pc_bignum *a, const pc_bignum *b)
Compare two pc_bignum values.
void bn_from_bytes(pc_bignum *out, const uint8_t *bytes, size_t len)
Read a big-endian byte array of len bytes into a pc_bignum.
2048-bit big-integer arithmetic for DH-group14 and RSA-2048.
#define PC_BN_LIMBS
Number of 32-bit limbs in a 2048-bit integer.
Per-translation-unit optimization override for hot, pure-integer crypto.
Constant-time comparison for secret-dependent checks.
PC_CRYPTO_HOT const uint8_t pc_pkcs1_sha256_digestinfo[PC_PKCS1_DIGESTINFO_LEN]
The DER-encoded DigestInfo wrapper for SHA-256 (prepend to the 32-byte digest).
const uint8_t pc_pkcs1_sha512_digestinfo[PC_PKCS1_SHA512_DIGESTINFO_LEN]
The DER-encoded DigestInfo wrapper for SHA-512 (prepend to the 64-byte digest).
int pc_rsa_verify(const uint8_t n_be[PC_RSA_KEY_BYTES], const uint8_t e_be4[4], const uint8_t *msg, size_t msg_len, const uint8_t *sig, size_t sig_len, pc_rsa_hash hash)
Verify an RSA-2048 PKCS#1 v1.5 signature over msg.
RSA-2048 PKCS#1 v1.5 signature primitive (RFC 8017) - verify + software sign.
pc_rsa_hash
Hash algorithm selecting the RSA signature scheme (RFC 8017 §9.2).
@ SHA512
RSASSA-PKCS1-v1.5 with SHA-512.
#define PC_PKCS1_DIGESTINFO_LEN
Length of the DER DigestInfo wrapper for SHA-256 (RFC 8017 / RFC 5754).
#define PC_RSA_SIG_BYTES
PKCS#1 v1.5 signature size for RSA-2048 in bytes.
#define PC_RSA_KEY_BYTES
RSA modulus / signature size in bytes (RSA-2048).
#define PC_PKCS1_SHA512_DIGESTINFO_LEN
Length of the DER DigestInfo wrapper for SHA-512.
Secure pool accessor - borrows that hold key material.
void pc_sha256(const uint8_t *data, size_t len, uint8_t digest[PC_SHA256_DIGEST_LEN])
One-shot SHA-256: hash len bytes of data into digest (32 bytes).
SHA-256 (FIPS 180-4) - streaming context and one-shot API.
#define PC_SHA256_DIGEST_LEN
SHA-256 digest length in bytes.
void pc_sha512(const uint8_t *data, size_t len, uint8_t digest[PC_SHA512_DIGEST_LEN])
One-shot SHA-512: hash len bytes of data into digest (64 bytes).
SHA-512 (FIPS 180-4) - streaming context and one-shot API.
#define PC_SHA512_DIGEST_LEN
SHA-512 digest length in bytes.
A 2048-bit unsigned integer stored as 64 little-endian 32-bit limbs.
uint32_t d[PC_BN_LIMBS]
256 bytes of magnitude, little-endian limbs.