ProtoCore v0.0.1
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
rsa.h
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file rsa.h
6 * @brief RSA-2048 PKCS#1 v1.5 signature primitive (RFC 8017) - verify + software sign.
7 *
8 * The shared, protocol-agnostic RSA primitive: it takes raw big-endian key material (modulus n,
9 * exponent) and a message, and does the RSASSA-PKCS1-v1.5 math with a SHA-256 or SHA-512 digest. It
10 * knows nothing about SSH key blobs, host-key storage, or the "ssh-rsa" / "rsa-sha2-256" wire names -
11 * that layer lives in network_drivers/presentation/ssh/crypto/ssh_rsa and calls into this primitive.
12 *
13 * Verify runs on both platforms (mbedtls on Arduino/ESP32, software on native). The software sign
14 * (pc_rsa_sign_sw, raw n/d) is the native-only reference path used by the tests; on-device signing
15 * with a cached host-key context is the SSH layer's job.
16 *
17 * @author Douglas Quigg (dstroy0)
18 * @date 2026
19 */
20
21#ifndef PROTOCORE_RSA_H
22#define PROTOCORE_RSA_H
23
24#include <stddef.h>
25#include <stdint.h>
26
27/** @brief RSA modulus / signature size in bytes (RSA-2048). */
28#define PC_RSA_KEY_BYTES 256
29
30/** @brief PKCS#1 v1.5 signature size for RSA-2048 in bytes. */
31#define PC_RSA_SIG_BYTES 256
32
33/**
34 * @brief Hash algorithm selecting the RSA signature scheme (RFC 8017 §9.2).
35 *
36 * Only the message hash and its DigestInfo OID differ between the two.
37 */
38enum class pc_rsa_hash : uint8_t
39{
40 SHA256 = 0, ///< RSASSA-PKCS1-v1.5 with SHA-256
41 SHA512 = 1 ///< RSASSA-PKCS1-v1.5 with SHA-512
42};
43
44/** @brief Length of the DER DigestInfo wrapper for SHA-256 (RFC 8017 / RFC 5754). */
45#define PC_PKCS1_DIGESTINFO_LEN 19
46
47/** @brief Length of the DER DigestInfo wrapper for SHA-512. */
48#define PC_PKCS1_SHA512_DIGESTINFO_LEN 19
49
50/** @brief The DER-encoded DigestInfo wrapper for SHA-256 (prepend to the 32-byte digest). */
52
53/** @brief The DER-encoded DigestInfo wrapper for SHA-512 (prepend to the 64-byte digest). */
55
56/**
57 * @brief Verify an RSA-2048 PKCS#1 v1.5 signature over @p msg.
58 *
59 * @param n_be Modulus n, 256 bytes big-endian.
60 * @param e_be4 Public exponent e, 4 bytes big-endian (typically 65537).
61 * @param msg Message that was signed (this hashes it; do not pre-hash).
62 * @param msg_len Message length.
63 * @param sig Signature, big-endian.
64 * @param sig_len Signature length (must equal PC_RSA_KEY_BYTES).
65 * @param hash Digest algorithm (SHA-256 / SHA-512).
66 * @return 0 if the signature is valid, -1 otherwise.
67 */
68int 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,
69 const uint8_t *sig, size_t sig_len, pc_rsa_hash hash);
70
71#ifndef ARDUINO
72/**
73 * @brief Software RSA-2048 PKCS#1 v1.5 sign with a raw private key (native reference path).
74 *
75 * Full-width square-and-multiply modexp (s = pkcs1(H(msg))^d mod n). NOT constant-time - the native
76 * path is test-only; on-device signing uses the SSH layer's cached mbedtls host-key context.
77 *
78 * @param n_be Modulus n, 256 bytes big-endian.
79 * @param d_be Private exponent d, 256 bytes big-endian (SENSITIVE; caller wipes).
80 * @param msg Message to sign (this hashes it).
81 * @param msg_len Message length.
82 * @param hash Digest algorithm (SHA-256 / SHA-512).
83 * @param sig Output signature, PC_RSA_SIG_BYTES big-endian.
84 * @return 0 on success.
85 */
86int pc_rsa_sign_sw(const uint8_t n_be[PC_RSA_KEY_BYTES], const uint8_t d_be[PC_RSA_KEY_BYTES], const uint8_t *msg,
87 size_t msg_len, pc_rsa_hash hash, uint8_t sig[PC_RSA_SIG_BYTES]);
88#endif
89
90#endif // PROTOCORE_RSA_H
pc_rsa_hash
Hash algorithm selecting the RSA signature scheme (RFC 8017 §9.2).
Definition rsa.h:39
@ SHA256
RSASSA-PKCS1-v1.5 with SHA-256.
@ 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).
Definition rsa.h:45
#define PC_RSA_SIG_BYTES
PKCS#1 v1.5 signature size for RSA-2048 in bytes.
Definition rsa.h:31
#define PC_RSA_KEY_BYTES
RSA modulus / signature size in bytes (RSA-2048).
Definition rsa.h:28
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).
Definition rsa.cpp:40
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).
Definition rsa.cpp:31
#define PC_PKCS1_SHA512_DIGESTINFO_LEN
Length of the DER DigestInfo wrapper for SHA-512.
Definition rsa.h:48
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.
Definition rsa.cpp:55