Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
crypto.hpp
Go to the documentation of this file.
1#pragma once
2
3// Cryptographic primitives.
4// Portable SHA-256; Mbed TLS: SHA-1, MD5, AES-CBC/GCM, HMAC.
5// TweetNaCl: Ed25519 sign/verify.
6
7#include <string>
8#include <string_view>
9#include <vector>
10#include <cstddef>
11#include <cstdint>
12#include <filesystem>
13#include <optional>
14
15namespace pulp::runtime {
16
17// ── Secure random bytes ─────────────────────────────────────────────────
18
21std::optional<std::vector<uint8_t>> secure_random_bytes(size_t size);
22
25void secure_zero_memory(void* data, size_t size) noexcept;
26
27// ── Encoding ────────────────────────────────────────────────────────────
28
32inline std::string hex_encode(const uint8_t* data, size_t size) {
33 static const char* d = "0123456789abcdef";
34 std::string out;
35 out.reserve(size * 2);
36 for (size_t i = 0; i < size; ++i) {
37 out.push_back(d[data[i] >> 4]);
38 out.push_back(d[data[i] & 0xF]);
39 }
40 return out;
41}
42inline std::string hex_encode(const std::vector<uint8_t>& bytes) {
43 return hex_encode(bytes.data(), bytes.size());
44}
45
46// ── Hashing ─────────────────────────────────────────────────────────────
47
54std::vector<uint8_t> sha256(const uint8_t* data, size_t size);
55std::vector<uint8_t> sha256(std::string_view data);
56
58std::string sha256_hex(const uint8_t* data, size_t size);
59std::string sha256_hex(std::string_view data);
60
63std::optional<std::string> sha256_file_hex(const std::filesystem::path& path,
64 std::uint64_t max_bytes);
65
68std::vector<uint8_t> sha1(const uint8_t* data, size_t size);
69std::vector<uint8_t> sha1(std::string_view data);
70
72std::vector<uint8_t> md5(const uint8_t* data, size_t size);
73std::vector<uint8_t> md5(std::string_view data);
74
76std::string md5_hex(std::string_view data);
77
78// ── AES ─────────────────────────────────────────────────────────────────
79
82std::optional<std::vector<uint8_t>> aes_encrypt(
83 const uint8_t* plaintext, size_t size,
84 const uint8_t* key_32, const uint8_t* iv_16);
85
87std::optional<std::vector<uint8_t>> aes_decrypt(
88 const uint8_t* ciphertext, size_t size,
89 const uint8_t* key_32, const uint8_t* iv_16);
90
91// ── HMAC (RFC 2104 / RFC 2202 / RFC 4231) ───────────────────────────────
92
97std::optional<std::vector<uint8_t>> hmac_sha256(
98 const uint8_t* key, size_t key_size,
99 const uint8_t* data, size_t data_size);
100std::optional<std::vector<uint8_t>> hmac_sha256(std::string_view key,
101 std::string_view data);
102
107std::optional<std::vector<uint8_t>> hmac_sha1(
108 const uint8_t* key, size_t key_size,
109 const uint8_t* data, size_t data_size);
110
111// ── AES-GCM (AEAD, NIST SP 800-38D) ─────────────────────────────────────
112
114struct GcmOutput {
115 std::vector<uint8_t> ciphertext;
116 std::vector<uint8_t> tag;
117};
118
123std::optional<GcmOutput> aes_gcm_encrypt(
124 const uint8_t* plaintext, size_t plaintext_size,
125 const uint8_t* key_32,
126 const uint8_t* iv_12, size_t iv_size,
127 const uint8_t* aad, size_t aad_size);
128
134std::optional<std::vector<uint8_t>> aes_gcm_decrypt(
135 const uint8_t* ciphertext, size_t ciphertext_size,
136 const uint8_t* key_32,
137 const uint8_t* iv_12, size_t iv_size,
138 const uint8_t* aad, size_t aad_size,
139 const uint8_t* tag_16);
140
141// ── Constant-time comparison ────────────────────────────────────────────
142
146bool constant_time_equal(const uint8_t* a, const uint8_t* b, size_t size);
147
148// ── Ed25519 (RFC 8032) ──────────────────────────────────────────────────
149//
150// Detached EdDSA signing over the Ed25519 curve. Used by:
151// - Sparkle appcast `edSignature` (macOS auto-update)
152//
153// Implementation: vendored TweetNaCl reference (public domain, RFC 8032
154// compliant). TweetNaCl exposes a combined sign-and-message API; the
155// wrappers here expose a detached 64-byte signature for direct
156// interoperability with Sparkle and most ecosystem tools.
157
159inline constexpr size_t ed25519_public_key_size = 32;
160inline constexpr size_t ed25519_private_key_size = 64; // seed (32) + public key (32)
161inline constexpr size_t ed25519_seed_size = 32;
162inline constexpr size_t ed25519_signature_size = 64;
163
166 std::vector<uint8_t> public_key;
167 std::vector<uint8_t> private_key;
168};
169
173std::optional<Ed25519KeyPair> ed25519_keypair_generate();
174
177std::optional<Ed25519KeyPair> ed25519_keypair_from_seed(
178 const uint8_t* seed_32, size_t seed_size);
179
183std::optional<std::vector<uint8_t>> ed25519_sign(
184 const uint8_t* private_key_64, size_t private_key_size,
185 const uint8_t* message, size_t message_size);
186
191 const uint8_t* public_key_32, size_t public_key_size,
192 const uint8_t* signature_64, size_t signature_size,
193 const uint8_t* message, size_t message_size);
194
195// ── X25519 (RFC 7748) ───────────────────────────────────────────────────
196//
197// Elliptic-curve Diffie-Hellman over Curve25519. Used by:
198// - Forge private-backup capsules, to wrap a content key to the
199// creator's identity key and to a recovery key
200//
201// Implementation: the same vendored TweetNaCl reference that backs
202// Ed25519 above. `crypto_scalarmult` performs RFC 7748 scalar decoding
203// (clamping) on its own private copy, so a private key here is 32
204// arbitrary bytes and callers must not pre-clamp.
205//
206// Ed25519 keys cannot stand in for these. Ed25519 signs; it carries no
207// key-agreement operation, which is the whole reason this section exists.
208
210inline constexpr size_t x25519_public_key_size = 32;
211inline constexpr size_t x25519_private_key_size = 32;
212inline constexpr size_t x25519_shared_secret_size = 32;
213
217 std::vector<uint8_t> public_key;
218 std::vector<uint8_t> private_key;
219};
220
224std::optional<X25519KeyPair> x25519_keypair_generate();
225
229std::optional<X25519KeyPair> x25519_keypair_from_private_key(
230 const uint8_t* private_key_32, size_t private_key_size);
231
242std::optional<std::vector<uint8_t>> x25519_shared_secret(
243 const uint8_t* private_key_32, size_t private_key_size,
244 const uint8_t* peer_public_key_32, size_t peer_public_key_size);
245
246// ── Machine ID ──────────────────────────────────────────────────────────
247
250std::string machine_id();
251
252} // namespace pulp::runtime
Definition generated_event_source.hpp:33
constexpr size_t x25519_shared_secret_size
Definition crypto.hpp:212
std::vector< uint8_t > md5(const uint8_t *data, size_t size)
Compute MD5 hash. Returns 16-byte digest. (Legacy use only.).
std::optional< X25519KeyPair > x25519_keypair_generate()
Generate a fresh X25519 keypair using mbedTLS CTR-DRBG for entropy.
constexpr size_t x25519_public_key_size
X25519 key and output sizes (RFC 7748 §5).
Definition crypto.hpp:210
std::optional< std::vector< uint8_t > > ed25519_sign(const uint8_t *private_key_64, size_t private_key_size, const uint8_t *message, size_t message_size)
Sign a message with an Ed25519 private key (64-byte NaCl-form).
std::optional< std::vector< uint8_t > > hmac_sha1(const uint8_t *key, size_t key_size, const uint8_t *data, size_t data_size)
Compute HMAC-SHA1(key, data).
std::string sha256_hex(const uint8_t *data, size_t size)
Compute SHA-256 hash as hex string (64 chars).
std::optional< std::vector< uint8_t > > aes_decrypt(const uint8_t *ciphertext, size_t size, const uint8_t *key_32, const uint8_t *iv_16)
AES-256-CBC decrypt. Returns plaintext (PKCS7 unpadded).
std::string hex_encode(const uint8_t *data, size_t size)
Lowercase-hex encode raw bytes.
Definition crypto.hpp:32
bool constant_time_equal(const uint8_t *a, const uint8_t *b, size_t size)
Constant-time byte comparison.
std::optional< Ed25519KeyPair > ed25519_keypair_generate()
Generate a fresh Ed25519 keypair using mbedTLS CTR-DRBG for entropy.
std::optional< std::vector< uint8_t > > hmac_sha256(const uint8_t *key, size_t key_size, const uint8_t *data, size_t data_size)
Compute HMAC-SHA256(key, data).
std::optional< std::vector< uint8_t > > aes_gcm_decrypt(const uint8_t *ciphertext, size_t ciphertext_size, const uint8_t *key_32, const uint8_t *iv_12, size_t iv_size, const uint8_t *aad, size_t aad_size, const uint8_t *tag_16)
AES-256-GCM decrypt + verify the 16-byte tag.
std::optional< std::vector< uint8_t > > aes_encrypt(const uint8_t *plaintext, size_t size, const uint8_t *key_32, const uint8_t *iv_16)
AES-256-CBC encrypt.
constexpr size_t ed25519_seed_size
Definition crypto.hpp:161
void secure_zero_memory(void *data, size_t size) noexcept
Overwrite sensitive bytes through volatile stores so the wipe is not removed as a dead store when the...
std::string machine_id()
Generate a machine-specific fingerprint (deterministic per machine).
std::vector< uint8_t > sha1(const uint8_t *data, size_t size)
Compute SHA-1 hash.
constexpr size_t ed25519_private_key_size
Definition crypto.hpp:160
bool ed25519_verify(const uint8_t *public_key_32, size_t public_key_size, const uint8_t *signature_64, size_t signature_size, const uint8_t *message, size_t message_size)
Verify a 64-byte detached signature against a message + 32-byte public key.
constexpr size_t ed25519_public_key_size
Ed25519 key sizes (RFC 8032 §5.1).
Definition crypto.hpp:159
std::string md5_hex(std::string_view data)
Compute MD5 hash as hex string (32 chars).
std::vector< uint8_t > sha256(const uint8_t *data, size_t size)
Compute SHA-256 hash.
constexpr size_t ed25519_signature_size
Definition crypto.hpp:162
constexpr size_t x25519_private_key_size
Definition crypto.hpp:211
std::optional< std::vector< uint8_t > > secure_random_bytes(size_t size)
Generate bytes from the runtime's entropy-seeded CTR-DRBG.
std::optional< GcmOutput > aes_gcm_encrypt(const uint8_t *plaintext, size_t plaintext_size, const uint8_t *key_32, const uint8_t *iv_12, size_t iv_size, const uint8_t *aad, size_t aad_size)
AES-256-GCM encrypt with optional Additional Authenticated Data (AAD).
std::optional< X25519KeyPair > x25519_keypair_from_private_key(const uint8_t *private_key_32, size_t private_key_size)
Recover the public key for an existing 32-byte private scalar.
std::optional< std::string > sha256_file_hex(const std::filesystem::path &path, std::uint64_t max_bytes)
Stream a file through SHA-256 without retaining its contents in memory.
std::optional< Ed25519KeyPair > ed25519_keypair_from_seed(const uint8_t *seed_32, size_t seed_size)
Derive a deterministic Ed25519 keypair from a 32-byte seed.
std::optional< std::vector< uint8_t > > x25519_shared_secret(const uint8_t *private_key_32, size_t private_key_size, const uint8_t *peer_public_key_32, size_t peer_public_key_size)
Compute the raw X25519 shared secret between our private key and a peer's public key.
Ed25519 keypair (NaCl convention: secret key contains seed || public key).
Definition crypto.hpp:165
std::vector< uint8_t > public_key
32 bytes
Definition crypto.hpp:166
std::vector< uint8_t > private_key
64 bytes (seed || public_key)
Definition crypto.hpp:167
Output of AES-GCM encryption: ciphertext + 16-byte authentication tag.
Definition crypto.hpp:114
std::vector< uint8_t > ciphertext
Definition crypto.hpp:115
std::vector< uint8_t > tag
16 bytes
Definition crypto.hpp:116
X25519 keypair.
Definition crypto.hpp:216
std::vector< uint8_t > private_key
32 bytes
Definition crypto.hpp:218
std::vector< uint8_t > public_key
32 bytes
Definition crypto.hpp:217