pq_crypto 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +1 -1
- data/CHANGELOG.md +102 -0
- data/GET_STARTED.md +16 -9
- data/README.md +117 -23
- data/SECURITY.md +72 -13
- data/ext/pqcrypto/extconf.rb +16 -11
- data/ext/pqcrypto/pq_randombytes.c +56 -0
- data/ext/pqcrypto/pqcrypto_ruby_secure.c +266 -320
- data/ext/pqcrypto/pqcrypto_secure.c +332 -607
- data/ext/pqcrypto/pqcrypto_secure.h +13 -2
- data/lib/pq_crypto/errors.rb +12 -6
- data/lib/pq_crypto/hybrid_kem.rb +2 -2
- data/lib/pq_crypto/kem.rb +16 -4
- data/lib/pq_crypto/serialization.rb +2 -2
- data/lib/pq_crypto/signature.rb +26 -18
- data/lib/pq_crypto/version.rb +1 -1
- data/lib/pq_crypto.rb +42 -73
- data/script/vendor_libs.rb +0 -1
- metadata +5 -24
- data/ext/pqcrypto/vendor/pqclean/common/keccak4x/Makefile +0 -8
- data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/Makefile +0 -19
- data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/Makefile +0 -19
|
@@ -6,18 +6,16 @@
|
|
|
6
6
|
#include <unistd.h>
|
|
7
7
|
#include <limits.h>
|
|
8
8
|
|
|
9
|
-
#if defined(__linux__)
|
|
10
|
-
#include <sys/random.h>
|
|
11
|
-
#endif
|
|
12
|
-
|
|
13
9
|
#ifndef HAVE_OPENSSL_EVP_H
|
|
14
10
|
#error \
|
|
15
11
|
"OpenSSL with EVP support is required for secure cryptographic operations. Install OpenSSL development packages."
|
|
16
12
|
#endif
|
|
17
13
|
|
|
14
|
+
#include <openssl/crypto.h>
|
|
18
15
|
#include <openssl/evp.h>
|
|
19
16
|
#include <openssl/rand.h>
|
|
20
|
-
#include <openssl/
|
|
17
|
+
#include <openssl/bio.h>
|
|
18
|
+
#include <openssl/buffer.h>
|
|
21
19
|
|
|
22
20
|
#if OPENSSL_VERSION_NUMBER < 0x30000000L
|
|
23
21
|
#error "OpenSSL 3.0 or later is required for pq_crypto"
|
|
@@ -29,11 +27,11 @@
|
|
|
29
27
|
|
|
30
28
|
#include "mlkem_api.h"
|
|
31
29
|
#include "mldsa_api.h"
|
|
32
|
-
#include "fips202.h"
|
|
33
|
-
#include "packing.h"
|
|
34
|
-
#include "params.h"
|
|
35
30
|
|
|
36
31
|
void pq_secure_wipe(void *ptr, size_t len) {
|
|
32
|
+
if (ptr == NULL) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
37
35
|
volatile uint8_t *p = ptr;
|
|
38
36
|
while (len--) {
|
|
39
37
|
*p++ = 0;
|
|
@@ -64,33 +62,6 @@ static int pq_is_pem_whitespace(char c) {
|
|
|
64
62
|
return c == '\n' || c == '\r' || c == ' ' || c == '\t';
|
|
65
63
|
}
|
|
66
64
|
|
|
67
|
-
static int pq_randombytes(uint8_t *buf, size_t len) {
|
|
68
|
-
#ifdef HAVE_OPENSSL_RAND_H
|
|
69
|
-
if (len > INT_MAX) {
|
|
70
|
-
return PQ_ERROR_BUFFER;
|
|
71
|
-
}
|
|
72
|
-
if (RAND_bytes(buf, (int)len) == 1) {
|
|
73
|
-
return 0;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
#endif
|
|
77
|
-
|
|
78
|
-
#if defined(__linux__)
|
|
79
|
-
ssize_t ret = getrandom(buf, len, 0);
|
|
80
|
-
return (ret == (ssize_t)len) ? 0 : PQ_ERROR_RANDOM;
|
|
81
|
-
#elif defined(__APPLE__)
|
|
82
|
-
arc4random_buf(buf, len);
|
|
83
|
-
return 0;
|
|
84
|
-
#else
|
|
85
|
-
FILE *f = fopen("/dev/urandom", "rb");
|
|
86
|
-
if (!f)
|
|
87
|
-
return PQ_ERROR_RANDOM;
|
|
88
|
-
size_t read = fread(buf, 1, len, f);
|
|
89
|
-
fclose(f);
|
|
90
|
-
return (read == len) ? 0 : PQ_ERROR_RANDOM;
|
|
91
|
-
#endif
|
|
92
|
-
}
|
|
93
|
-
|
|
94
65
|
static int x25519_keypair(uint8_t *pk, uint8_t *sk) {
|
|
95
66
|
EVP_PKEY_CTX *ctx = NULL;
|
|
96
67
|
EVP_PKEY *pkey = NULL;
|
|
@@ -171,201 +142,67 @@ cleanup:
|
|
|
171
142
|
return ret;
|
|
172
143
|
}
|
|
173
144
|
|
|
174
|
-
static
|
|
175
|
-
EVP_PKEY *pkey = NULL;
|
|
176
|
-
size_t pklen = X25519_PUBLICKEYBYTES;
|
|
177
|
-
int ret = PQ_ERROR_KEYPAIR;
|
|
178
|
-
|
|
179
|
-
pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_X25519, NULL, sk, X25519_SECRETKEYBYTES);
|
|
180
|
-
if (!pkey) {
|
|
181
|
-
return ret;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
if (EVP_PKEY_get_raw_public_key(pkey, pk, &pklen) <= 0 || pklen != X25519_PUBLICKEYBYTES) {
|
|
185
|
-
EVP_PKEY_free(pkey);
|
|
186
|
-
return ret;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
EVP_PKEY_free(pkey);
|
|
190
|
-
return PQ_SUCCESS;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
static int size_t_to_int_checked(size_t value, int *out) {
|
|
194
|
-
if (value > INT_MAX) {
|
|
195
|
-
return PQ_ERROR_BUFFER;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
*out = (int)value;
|
|
199
|
-
return PQ_SUCCESS;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
static int secure_hkdf(uint8_t *output, size_t output_len, const uint8_t *ikm, size_t ikm_len,
|
|
203
|
-
const uint8_t *salt, size_t salt_len, const uint8_t *info, size_t info_len) {
|
|
204
|
-
int ikm_len_i = 0;
|
|
205
|
-
int salt_len_i = 0;
|
|
206
|
-
int info_len_i = 0;
|
|
207
|
-
|
|
208
|
-
if (size_t_to_int_checked(ikm_len, &ikm_len_i) != PQ_SUCCESS)
|
|
209
|
-
return PQ_ERROR_BUFFER;
|
|
210
|
-
if (size_t_to_int_checked(salt_len, &salt_len_i) != PQ_SUCCESS)
|
|
211
|
-
return PQ_ERROR_BUFFER;
|
|
212
|
-
if (size_t_to_int_checked(info_len, &info_len_i) != PQ_SUCCESS)
|
|
213
|
-
return PQ_ERROR_BUFFER;
|
|
214
|
-
|
|
215
|
-
EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
|
|
216
|
-
if (!pctx)
|
|
217
|
-
return PQ_ERROR_OPENSSL;
|
|
218
|
-
|
|
219
|
-
if (EVP_PKEY_derive_init(pctx) <= 0) {
|
|
220
|
-
EVP_PKEY_CTX_free(pctx);
|
|
221
|
-
return PQ_ERROR_OPENSSL;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
if (EVP_PKEY_CTX_set_hkdf_md(pctx, EVP_sha256()) <= 0) {
|
|
225
|
-
EVP_PKEY_CTX_free(pctx);
|
|
226
|
-
return PQ_ERROR_OPENSSL;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
if (EVP_PKEY_CTX_set1_hkdf_key(pctx, ikm, ikm_len_i) <= 0) {
|
|
230
|
-
EVP_PKEY_CTX_free(pctx);
|
|
231
|
-
return PQ_ERROR_OPENSSL;
|
|
232
|
-
}
|
|
145
|
+
static const uint8_t XWING_LABEL[6] = {0x5c, 0x2e, 0x2f, 0x2f, 0x5e, 0x5c};
|
|
233
146
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
if (info && info_len > 0) {
|
|
242
|
-
if (EVP_PKEY_CTX_add1_hkdf_info(pctx, info, info_len_i) <= 0) {
|
|
243
|
-
EVP_PKEY_CTX_free(pctx);
|
|
244
|
-
return PQ_ERROR_OPENSSL;
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
size_t outlen = output_len;
|
|
249
|
-
if (EVP_PKEY_derive(pctx, output, &outlen) <= 0) {
|
|
250
|
-
EVP_PKEY_CTX_free(pctx);
|
|
251
|
-
return PQ_ERROR_OPENSSL;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
EVP_PKEY_CTX_free(pctx);
|
|
255
|
-
return (outlen == output_len) ? 0 : PQ_ERROR_KDF;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
static int secure_sha256(uint8_t *output, const uint8_t *input, size_t input_len) {
|
|
147
|
+
static int xwing_combiner(uint8_t shared_secret[HYBRID_SHAREDSECRETBYTES],
|
|
148
|
+
const uint8_t ss_M[MLKEM_SHAREDSECRETBYTES],
|
|
149
|
+
const uint8_t ss_X[X25519_SHAREDSECRETBYTES],
|
|
150
|
+
const uint8_t ct_X[X25519_PUBLICKEYBYTES],
|
|
151
|
+
const uint8_t pk_X[X25519_PUBLICKEYBYTES]) {
|
|
259
152
|
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
|
|
260
153
|
unsigned int out_len = 0;
|
|
154
|
+
int ret = PQ_ERROR_OPENSSL;
|
|
261
155
|
|
|
262
156
|
if (!ctx) {
|
|
263
157
|
return PQ_ERROR_OPENSSL;
|
|
264
158
|
}
|
|
265
159
|
|
|
266
|
-
if (EVP_DigestInit_ex(ctx,
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
uint8_t salt[32];
|
|
283
|
-
int ret = PQ_SUCCESS;
|
|
284
|
-
size_t transcript_len = sizeof(label) - 1 + X25519_PUBLICKEYBYTES + HYBRID_CIPHERTEXTBYTES;
|
|
285
|
-
uint8_t *transcript = malloc(transcript_len);
|
|
286
|
-
|
|
287
|
-
if (!transcript) {
|
|
288
|
-
return PQ_ERROR_NOMEM;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
memcpy(ikm, mlkem_ss, MLKEM_SHAREDSECRETBYTES);
|
|
292
|
-
memcpy(ikm + MLKEM_SHAREDSECRETBYTES, x25519_ss, X25519_SHAREDSECRETBYTES);
|
|
293
|
-
|
|
294
|
-
memcpy(transcript, label, sizeof(label) - 1);
|
|
295
|
-
memcpy(transcript + sizeof(label) - 1, recipient_x25519_pk, X25519_PUBLICKEYBYTES);
|
|
296
|
-
memcpy(transcript + sizeof(label) - 1 + X25519_PUBLICKEYBYTES, ct, HYBRID_CIPHERTEXTBYTES);
|
|
160
|
+
if (EVP_DigestInit_ex(ctx, EVP_sha3_256(), NULL) != 1)
|
|
161
|
+
goto cleanup;
|
|
162
|
+
if (EVP_DigestUpdate(ctx, XWING_LABEL, sizeof(XWING_LABEL)) != 1)
|
|
163
|
+
goto cleanup;
|
|
164
|
+
if (EVP_DigestUpdate(ctx, ss_M, MLKEM_SHAREDSECRETBYTES) != 1)
|
|
165
|
+
goto cleanup;
|
|
166
|
+
if (EVP_DigestUpdate(ctx, ss_X, X25519_SHAREDSECRETBYTES) != 1)
|
|
167
|
+
goto cleanup;
|
|
168
|
+
if (EVP_DigestUpdate(ctx, ct_X, X25519_PUBLICKEYBYTES) != 1)
|
|
169
|
+
goto cleanup;
|
|
170
|
+
if (EVP_DigestUpdate(ctx, pk_X, X25519_PUBLICKEYBYTES) != 1)
|
|
171
|
+
goto cleanup;
|
|
172
|
+
if (EVP_DigestFinal_ex(ctx, shared_secret, &out_len) != 1)
|
|
173
|
+
goto cleanup;
|
|
174
|
+
if (out_len != HYBRID_SHAREDSECRETBYTES)
|
|
175
|
+
goto cleanup;
|
|
297
176
|
|
|
298
|
-
ret =
|
|
299
|
-
if (ret == PQ_SUCCESS) {
|
|
300
|
-
ret = secure_hkdf(shared_secret, HYBRID_SHAREDSECRETBYTES, ikm, sizeof(ikm), salt,
|
|
301
|
-
sizeof(salt), transcript, transcript_len);
|
|
302
|
-
}
|
|
177
|
+
ret = PQ_SUCCESS;
|
|
303
178
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
pq_secure_wipe(transcript, transcript_len);
|
|
307
|
-
free(transcript);
|
|
179
|
+
cleanup:
|
|
180
|
+
EVP_MD_CTX_free(ctx);
|
|
308
181
|
return ret;
|
|
309
182
|
}
|
|
310
183
|
|
|
311
|
-
|
|
312
|
-
return PQCLEAN_MLKEM768_CLEAN_crypto_kem_keypair(pk, sk);
|
|
184
|
+
int pq_mlkem_keypair(uint8_t *pk, uint8_t *sk) {
|
|
185
|
+
return PQCLEAN_MLKEM768_CLEAN_crypto_kem_keypair(pk, sk) == 0 ? PQ_SUCCESS : PQ_ERROR_KEYPAIR;
|
|
313
186
|
}
|
|
314
187
|
|
|
315
|
-
|
|
316
|
-
return PQCLEAN_MLKEM768_CLEAN_crypto_kem_enc(ct, ss, pk)
|
|
188
|
+
int pq_mlkem_encapsulate(uint8_t *ct, uint8_t *ss, const uint8_t *pk) {
|
|
189
|
+
return PQCLEAN_MLKEM768_CLEAN_crypto_kem_enc(ct, ss, pk) == 0 ? PQ_SUCCESS
|
|
190
|
+
: PQ_ERROR_ENCAPSULATE;
|
|
317
191
|
}
|
|
318
192
|
|
|
319
|
-
|
|
320
|
-
return PQCLEAN_MLKEM768_CLEAN_crypto_kem_dec(ss, ct, sk)
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
static int mldsa_keypair(uint8_t *pk, uint8_t *sk) {
|
|
324
|
-
return PQCLEAN_MLDSA65_CLEAN_crypto_sign_keypair(pk, sk);
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
static int mldsa_sign(uint8_t *sig, size_t *siglen, const uint8_t *msg, size_t msglen,
|
|
328
|
-
const uint8_t *sk) {
|
|
329
|
-
return PQCLEAN_MLDSA65_CLEAN_crypto_sign_signature(sig, siglen, msg, msglen, sk);
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
static int mldsa_verify(const uint8_t *sig, size_t siglen, const uint8_t *msg, size_t msglen,
|
|
333
|
-
const uint8_t *pk) {
|
|
334
|
-
return PQCLEAN_MLDSA65_CLEAN_crypto_sign_verify(sig, siglen, msg, msglen, pk);
|
|
193
|
+
int pq_mlkem_decapsulate(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) {
|
|
194
|
+
return PQCLEAN_MLKEM768_CLEAN_crypto_kem_dec(ss, ct, sk) == 0 ? PQ_SUCCESS
|
|
195
|
+
: PQ_ERROR_DECAPSULATE;
|
|
335
196
|
}
|
|
336
197
|
|
|
337
198
|
int pq_testing_mlkem_keypair_from_seed(uint8_t *public_key, uint8_t *secret_key,
|
|
338
199
|
const uint8_t *seed, size_t seed_len) {
|
|
339
|
-
|
|
340
|
-
int ret;
|
|
341
|
-
|
|
342
|
-
if (!public_key || !secret_key || !seed) {
|
|
200
|
+
if (!public_key || !secret_key || !seed || seed_len != 64) {
|
|
343
201
|
return PQ_ERROR_BUFFER;
|
|
344
202
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
? PQ_SUCCESS
|
|
349
|
-
: PQ_ERROR_KEYPAIR;
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
if (seed_len != 32) {
|
|
353
|
-
return PQ_ERROR_BUFFER;
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
ret = secure_hkdf(expanded_seed, sizeof(expanded_seed), seed, seed_len, NULL, 0,
|
|
357
|
-
(const uint8_t *)"pqcrypto-test-mlkem-keypair", 26);
|
|
358
|
-
if (ret != PQ_SUCCESS) {
|
|
359
|
-
pq_secure_wipe(expanded_seed, sizeof(expanded_seed));
|
|
360
|
-
return ret;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
ret =
|
|
364
|
-
PQCLEAN_MLKEM768_CLEAN_crypto_kem_keypair_derand(public_key, secret_key, expanded_seed) == 0
|
|
365
|
-
? PQ_SUCCESS
|
|
366
|
-
: PQ_ERROR_KEYPAIR;
|
|
367
|
-
pq_secure_wipe(expanded_seed, sizeof(expanded_seed));
|
|
368
|
-
return ret;
|
|
203
|
+
return PQCLEAN_MLKEM768_CLEAN_crypto_kem_keypair_derand(public_key, secret_key, seed) == 0
|
|
204
|
+
? PQ_SUCCESS
|
|
205
|
+
: PQ_ERROR_KEYPAIR;
|
|
369
206
|
}
|
|
370
207
|
|
|
371
208
|
int pq_testing_mlkem_encapsulate_from_seed(uint8_t *ciphertext, uint8_t *shared_secret,
|
|
@@ -374,325 +211,214 @@ int pq_testing_mlkem_encapsulate_from_seed(uint8_t *ciphertext, uint8_t *shared_
|
|
|
374
211
|
if (!ciphertext || !shared_secret || !public_key || !seed || seed_len != 32) {
|
|
375
212
|
return PQ_ERROR_BUFFER;
|
|
376
213
|
}
|
|
377
|
-
|
|
378
214
|
return PQCLEAN_MLKEM768_CLEAN_crypto_kem_enc_derand(ciphertext, shared_secret, public_key,
|
|
379
215
|
seed) == 0
|
|
380
216
|
? PQ_SUCCESS
|
|
381
217
|
: PQ_ERROR_ENCAPSULATE;
|
|
382
218
|
}
|
|
383
219
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
const uint8_t *rho, *rhoprime, *key;
|
|
389
|
-
polyvecl mat[K];
|
|
390
|
-
polyvecl s1, s1hat;
|
|
391
|
-
polyveck s2, t1, t0;
|
|
392
|
-
|
|
393
|
-
memcpy(seedbuf, seed, SEEDBYTES);
|
|
394
|
-
seedbuf[SEEDBYTES + 0] = K;
|
|
395
|
-
seedbuf[SEEDBYTES + 1] = L;
|
|
396
|
-
shake256(seedbuf, 2 * SEEDBYTES + CRHBYTES, seedbuf, SEEDBYTES + 2);
|
|
397
|
-
rho = seedbuf;
|
|
398
|
-
rhoprime = rho + SEEDBYTES;
|
|
399
|
-
key = rhoprime + CRHBYTES;
|
|
400
|
-
|
|
401
|
-
PQCLEAN_MLDSA65_CLEAN_polyvec_matrix_expand(mat, rho);
|
|
402
|
-
PQCLEAN_MLDSA65_CLEAN_polyvecl_uniform_eta(&s1, rhoprime, 0);
|
|
403
|
-
PQCLEAN_MLDSA65_CLEAN_polyveck_uniform_eta(&s2, rhoprime, L);
|
|
404
|
-
|
|
405
|
-
s1hat = s1;
|
|
406
|
-
PQCLEAN_MLDSA65_CLEAN_polyvecl_ntt(&s1hat);
|
|
407
|
-
PQCLEAN_MLDSA65_CLEAN_polyvec_matrix_pointwise_montgomery(&t1, mat, &s1hat);
|
|
408
|
-
PQCLEAN_MLDSA65_CLEAN_polyveck_reduce(&t1);
|
|
409
|
-
PQCLEAN_MLDSA65_CLEAN_polyveck_invntt_tomont(&t1);
|
|
410
|
-
|
|
411
|
-
PQCLEAN_MLDSA65_CLEAN_polyveck_add(&t1, &t1, &s2);
|
|
412
|
-
PQCLEAN_MLDSA65_CLEAN_polyveck_caddq(&t1);
|
|
413
|
-
PQCLEAN_MLDSA65_CLEAN_polyveck_power2round(&t1, &t0, &t1);
|
|
414
|
-
PQCLEAN_MLDSA65_CLEAN_pack_pk(public_key, rho, &t1);
|
|
415
|
-
|
|
416
|
-
shake256(tr, TRBYTES, public_key, PQCLEAN_MLDSA65_CLEAN_CRYPTO_PUBLICKEYBYTES);
|
|
417
|
-
PQCLEAN_MLDSA65_CLEAN_pack_sk(secret_key, rho, tr, key, &t0, &s1, &s2);
|
|
418
|
-
|
|
419
|
-
pq_secure_wipe(seedbuf, sizeof(seedbuf));
|
|
420
|
-
pq_secure_wipe(tr, sizeof(tr));
|
|
421
|
-
pq_secure_wipe(&s1, sizeof(s1));
|
|
422
|
-
pq_secure_wipe(&s1hat, sizeof(s1hat));
|
|
423
|
-
pq_secure_wipe(&s2, sizeof(s2));
|
|
424
|
-
pq_secure_wipe(&t1, sizeof(t1));
|
|
425
|
-
pq_secure_wipe(&t0, sizeof(t0));
|
|
426
|
-
pq_secure_wipe(mat, sizeof(mat));
|
|
427
|
-
return PQ_SUCCESS;
|
|
220
|
+
int pq_sign_keypair(uint8_t *public_key, uint8_t *secret_key) {
|
|
221
|
+
return PQCLEAN_MLDSA65_CLEAN_crypto_sign_keypair(public_key, secret_key) == 0
|
|
222
|
+
? PQ_SUCCESS
|
|
223
|
+
: PQ_ERROR_KEYPAIR;
|
|
428
224
|
}
|
|
429
225
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
uint16_t nonce = 0;
|
|
438
|
-
polyvecl mat[K], s1, y, z;
|
|
439
|
-
polyveck t0, s2, w1, w0, h;
|
|
440
|
-
poly cp;
|
|
441
|
-
shake256incctx state;
|
|
442
|
-
|
|
443
|
-
rho = seedbuf;
|
|
444
|
-
tr = rho + SEEDBYTES;
|
|
445
|
-
key = tr + TRBYTES;
|
|
446
|
-
rnd = key + SEEDBYTES;
|
|
447
|
-
mu = rnd + RNDBYTES;
|
|
448
|
-
rhoprime = mu + CRHBYTES;
|
|
449
|
-
PQCLEAN_MLDSA65_CLEAN_unpack_sk(rho, tr, key, &t0, &s1, &s2, secret_key);
|
|
450
|
-
|
|
451
|
-
mu[0] = 0;
|
|
452
|
-
mu[1] = 0;
|
|
453
|
-
shake256_inc_init(&state);
|
|
454
|
-
shake256_inc_absorb(&state, tr, TRBYTES);
|
|
455
|
-
shake256_inc_absorb(&state, mu, 2);
|
|
456
|
-
shake256_inc_absorb(&state, message, message_len);
|
|
457
|
-
shake256_inc_finalize(&state);
|
|
458
|
-
shake256_inc_squeeze(mu, CRHBYTES, &state);
|
|
459
|
-
shake256_inc_ctx_release(&state);
|
|
460
|
-
|
|
461
|
-
memcpy(rnd, seed, RNDBYTES);
|
|
462
|
-
shake256(rhoprime, CRHBYTES, key, SEEDBYTES + RNDBYTES + CRHBYTES);
|
|
463
|
-
|
|
464
|
-
PQCLEAN_MLDSA65_CLEAN_polyvec_matrix_expand(mat, rho);
|
|
465
|
-
PQCLEAN_MLDSA65_CLEAN_polyvecl_ntt(&s1);
|
|
466
|
-
PQCLEAN_MLDSA65_CLEAN_polyveck_ntt(&s2);
|
|
467
|
-
PQCLEAN_MLDSA65_CLEAN_polyveck_ntt(&t0);
|
|
468
|
-
|
|
469
|
-
rej:
|
|
470
|
-
PQCLEAN_MLDSA65_CLEAN_polyvecl_uniform_gamma1(&y, rhoprime, nonce++);
|
|
471
|
-
|
|
472
|
-
z = y;
|
|
473
|
-
PQCLEAN_MLDSA65_CLEAN_polyvecl_ntt(&z);
|
|
474
|
-
PQCLEAN_MLDSA65_CLEAN_polyvec_matrix_pointwise_montgomery(&w1, mat, &z);
|
|
475
|
-
PQCLEAN_MLDSA65_CLEAN_polyveck_reduce(&w1);
|
|
476
|
-
PQCLEAN_MLDSA65_CLEAN_polyveck_invntt_tomont(&w1);
|
|
477
|
-
|
|
478
|
-
PQCLEAN_MLDSA65_CLEAN_polyveck_caddq(&w1);
|
|
479
|
-
PQCLEAN_MLDSA65_CLEAN_polyveck_decompose(&w1, &w0, &w1);
|
|
480
|
-
PQCLEAN_MLDSA65_CLEAN_polyveck_pack_w1(signature, &w1);
|
|
481
|
-
|
|
482
|
-
shake256_inc_init(&state);
|
|
483
|
-
shake256_inc_absorb(&state, mu, CRHBYTES);
|
|
484
|
-
shake256_inc_absorb(&state, signature, K * POLYW1_PACKEDBYTES);
|
|
485
|
-
shake256_inc_finalize(&state);
|
|
486
|
-
shake256_inc_squeeze(signature, CTILDEBYTES, &state);
|
|
487
|
-
shake256_inc_ctx_release(&state);
|
|
488
|
-
PQCLEAN_MLDSA65_CLEAN_poly_challenge(&cp, signature);
|
|
489
|
-
PQCLEAN_MLDSA65_CLEAN_poly_ntt(&cp);
|
|
490
|
-
|
|
491
|
-
PQCLEAN_MLDSA65_CLEAN_polyvecl_pointwise_poly_montgomery(&z, &cp, &s1);
|
|
492
|
-
PQCLEAN_MLDSA65_CLEAN_polyvecl_invntt_tomont(&z);
|
|
493
|
-
PQCLEAN_MLDSA65_CLEAN_polyvecl_add(&z, &z, &y);
|
|
494
|
-
PQCLEAN_MLDSA65_CLEAN_polyvecl_reduce(&z);
|
|
495
|
-
if (PQCLEAN_MLDSA65_CLEAN_polyvecl_chknorm(&z, GAMMA1 - BETA)) {
|
|
496
|
-
goto rej;
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
PQCLEAN_MLDSA65_CLEAN_polyveck_pointwise_poly_montgomery(&h, &cp, &s2);
|
|
500
|
-
PQCLEAN_MLDSA65_CLEAN_polyveck_invntt_tomont(&h);
|
|
501
|
-
PQCLEAN_MLDSA65_CLEAN_polyveck_sub(&w0, &w0, &h);
|
|
502
|
-
PQCLEAN_MLDSA65_CLEAN_polyveck_reduce(&w0);
|
|
503
|
-
if (PQCLEAN_MLDSA65_CLEAN_polyveck_chknorm(&w0, GAMMA2 - BETA)) {
|
|
504
|
-
goto rej;
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
PQCLEAN_MLDSA65_CLEAN_polyveck_pointwise_poly_montgomery(&h, &cp, &t0);
|
|
508
|
-
PQCLEAN_MLDSA65_CLEAN_polyveck_invntt_tomont(&h);
|
|
509
|
-
PQCLEAN_MLDSA65_CLEAN_polyveck_reduce(&h);
|
|
510
|
-
if (PQCLEAN_MLDSA65_CLEAN_polyveck_chknorm(&h, GAMMA2)) {
|
|
511
|
-
goto rej;
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
PQCLEAN_MLDSA65_CLEAN_polyveck_add(&w0, &w0, &h);
|
|
515
|
-
n = PQCLEAN_MLDSA65_CLEAN_polyveck_make_hint(&h, &w0, &w1);
|
|
516
|
-
if (n > OMEGA) {
|
|
517
|
-
goto rej;
|
|
518
|
-
}
|
|
226
|
+
int pq_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len,
|
|
227
|
+
const uint8_t *secret_key) {
|
|
228
|
+
return PQCLEAN_MLDSA65_CLEAN_crypto_sign_signature(signature, signature_len, message,
|
|
229
|
+
message_len, secret_key) == 0
|
|
230
|
+
? PQ_SUCCESS
|
|
231
|
+
: PQ_ERROR_SIGN;
|
|
232
|
+
}
|
|
519
233
|
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
pq_secure_wipe(&z, sizeof(z));
|
|
527
|
-
pq_secure_wipe(&t0, sizeof(t0));
|
|
528
|
-
pq_secure_wipe(&s2, sizeof(s2));
|
|
529
|
-
pq_secure_wipe(&w1, sizeof(w1));
|
|
530
|
-
pq_secure_wipe(&w0, sizeof(w0));
|
|
531
|
-
pq_secure_wipe(&h, sizeof(h));
|
|
532
|
-
pq_secure_wipe(&cp, sizeof(cp));
|
|
533
|
-
pq_secure_wipe(mat, sizeof(mat));
|
|
534
|
-
return PQ_SUCCESS;
|
|
234
|
+
int pq_verify(const uint8_t *signature, size_t signature_len, const uint8_t *message,
|
|
235
|
+
size_t message_len, const uint8_t *public_key) {
|
|
236
|
+
return PQCLEAN_MLDSA65_CLEAN_crypto_sign_verify(signature, signature_len, message, message_len,
|
|
237
|
+
public_key) == 0
|
|
238
|
+
? PQ_SUCCESS
|
|
239
|
+
: PQ_ERROR_VERIFY;
|
|
535
240
|
}
|
|
536
241
|
|
|
537
242
|
int pq_testing_mldsa_keypair_from_seed(uint8_t *public_key, uint8_t *secret_key,
|
|
538
243
|
const uint8_t *seed, size_t seed_len) {
|
|
539
|
-
|
|
244
|
+
int rc;
|
|
245
|
+
if (!public_key || !secret_key || !seed) {
|
|
540
246
|
return PQ_ERROR_BUFFER;
|
|
541
247
|
}
|
|
542
248
|
|
|
543
|
-
|
|
249
|
+
if (seed_len != 32) {
|
|
250
|
+
return PQ_ERROR_BUFFER;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
pq_testing_set_seed(seed, seed_len);
|
|
254
|
+
rc = PQCLEAN_MLDSA65_CLEAN_crypto_sign_keypair(public_key, secret_key);
|
|
255
|
+
pq_testing_clear_seed();
|
|
256
|
+
return rc == 0 ? PQ_SUCCESS : PQ_ERROR_KEYPAIR;
|
|
544
257
|
}
|
|
545
258
|
|
|
546
259
|
int pq_testing_mldsa_sign_from_seed(uint8_t *signature, size_t *signature_len,
|
|
547
260
|
const uint8_t *message, size_t message_len,
|
|
548
261
|
const uint8_t *secret_key, const uint8_t *seed,
|
|
549
262
|
size_t seed_len) {
|
|
550
|
-
|
|
263
|
+
int rc;
|
|
264
|
+
if (!signature || !signature_len || !secret_key || !seed) {
|
|
551
265
|
return PQ_ERROR_BUFFER;
|
|
552
266
|
}
|
|
553
267
|
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
int pq_mlkem_keypair(uint8_t *public_key, uint8_t *secret_key) {
|
|
559
|
-
return mlkem_keypair(public_key, secret_key) == 0 ? PQ_SUCCESS : PQ_ERROR_KEYPAIR;
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
int pq_mlkem_encapsulate(uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key) {
|
|
563
|
-
return mlkem_encapsulate(ciphertext, shared_secret, public_key) == 0 ? PQ_SUCCESS
|
|
564
|
-
: PQ_ERROR_ENCAPSULATE;
|
|
565
|
-
}
|
|
268
|
+
if (seed_len != 32) {
|
|
269
|
+
return PQ_ERROR_BUFFER;
|
|
270
|
+
}
|
|
566
271
|
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
272
|
+
pq_testing_set_seed(seed, seed_len);
|
|
273
|
+
rc = PQCLEAN_MLDSA65_CLEAN_crypto_sign_signature(signature, signature_len, message, message_len,
|
|
274
|
+
secret_key);
|
|
275
|
+
pq_testing_clear_seed();
|
|
276
|
+
return rc == 0 ? PQ_SUCCESS : PQ_ERROR_SIGN;
|
|
571
277
|
}
|
|
572
278
|
|
|
573
279
|
int pq_hybrid_kem_keypair(uint8_t *public_key, uint8_t *secret_key) {
|
|
574
|
-
hybrid_public_key_t
|
|
575
|
-
hybrid_secret_key_t
|
|
280
|
+
hybrid_public_key_t pk;
|
|
281
|
+
hybrid_secret_key_t sk;
|
|
282
|
+
int ret;
|
|
576
283
|
|
|
577
|
-
|
|
284
|
+
if (!public_key || !secret_key) {
|
|
285
|
+
return PQ_ERROR_BUFFER;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
memset(&pk, 0, sizeof(pk));
|
|
289
|
+
memset(&sk, 0, sizeof(sk));
|
|
578
290
|
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
291
|
+
ret = PQCLEAN_MLKEM768_CLEAN_crypto_kem_keypair(pk.mlkem_pk, sk.mlkem_sk) == 0
|
|
292
|
+
? PQ_SUCCESS
|
|
293
|
+
: PQ_ERROR_KEYPAIR;
|
|
294
|
+
if (ret != PQ_SUCCESS) {
|
|
295
|
+
goto cleanup;
|
|
582
296
|
}
|
|
583
297
|
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
298
|
+
ret = x25519_keypair(pk.x25519_pk, sk.x25519_sk);
|
|
299
|
+
if (ret != PQ_SUCCESS) {
|
|
300
|
+
goto cleanup;
|
|
587
301
|
}
|
|
588
302
|
|
|
589
|
-
|
|
303
|
+
memcpy(public_key, &pk, HYBRID_PUBLICKEYBYTES);
|
|
304
|
+
memcpy(secret_key, &sk, HYBRID_SECRETKEYBYTES);
|
|
305
|
+
|
|
306
|
+
cleanup:
|
|
307
|
+
pq_secure_wipe(&sk, sizeof(sk));
|
|
308
|
+
|
|
309
|
+
pq_secure_wipe(&pk, sizeof(pk));
|
|
310
|
+
return ret;
|
|
590
311
|
}
|
|
591
312
|
|
|
592
313
|
int pq_hybrid_kem_encapsulate(uint8_t *ciphertext, uint8_t *shared_secret,
|
|
593
314
|
const uint8_t *public_key) {
|
|
594
|
-
|
|
595
|
-
hybrid_ciphertext_t
|
|
596
|
-
|
|
315
|
+
hybrid_public_key_t pk;
|
|
316
|
+
hybrid_ciphertext_t ct;
|
|
597
317
|
uint8_t mlkem_ss[MLKEM_SHAREDSECRETBYTES];
|
|
598
318
|
uint8_t x25519_ss[X25519_SHAREDSECRETBYTES];
|
|
599
319
|
uint8_t x25519_ephemeral_sk[X25519_SECRETKEYBYTES];
|
|
600
320
|
int ret = PQ_SUCCESS;
|
|
601
321
|
|
|
322
|
+
if (!ciphertext || !shared_secret || !public_key) {
|
|
323
|
+
return PQ_ERROR_BUFFER;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
memcpy(&pk, public_key, HYBRID_PUBLICKEYBYTES);
|
|
327
|
+
memset(&ct, 0, sizeof(ct));
|
|
602
328
|
memset(mlkem_ss, 0, sizeof(mlkem_ss));
|
|
603
329
|
memset(x25519_ss, 0, sizeof(x25519_ss));
|
|
604
330
|
memset(x25519_ephemeral_sk, 0, sizeof(x25519_ephemeral_sk));
|
|
605
331
|
|
|
606
|
-
if (
|
|
332
|
+
if (PQCLEAN_MLKEM768_CLEAN_crypto_kem_enc(ct.mlkem_ct, mlkem_ss, pk.mlkem_pk) != 0) {
|
|
607
333
|
ret = PQ_ERROR_ENCAPSULATE;
|
|
608
334
|
goto cleanup;
|
|
609
335
|
}
|
|
610
336
|
|
|
611
|
-
ret = x25519_keypair(ct
|
|
337
|
+
ret = x25519_keypair(ct.x25519_ephemeral, x25519_ephemeral_sk);
|
|
612
338
|
if (ret != PQ_SUCCESS) {
|
|
613
339
|
ret = PQ_ERROR_ENCAPSULATE;
|
|
614
340
|
goto cleanup;
|
|
615
341
|
}
|
|
616
342
|
|
|
617
|
-
ret = x25519_shared_secret(x25519_ss, pk
|
|
343
|
+
ret = x25519_shared_secret(x25519_ss, pk.x25519_pk, x25519_ephemeral_sk);
|
|
618
344
|
if (ret != PQ_SUCCESS) {
|
|
619
345
|
ret = PQ_ERROR_ENCAPSULATE;
|
|
620
346
|
goto cleanup;
|
|
621
347
|
}
|
|
622
348
|
|
|
623
|
-
ret =
|
|
349
|
+
ret = xwing_combiner(shared_secret, mlkem_ss, x25519_ss, ct.x25519_ephemeral, pk.x25519_pk);
|
|
624
350
|
if (ret != PQ_SUCCESS) {
|
|
625
351
|
goto cleanup;
|
|
626
352
|
}
|
|
627
353
|
|
|
628
|
-
|
|
354
|
+
memcpy(ciphertext, &ct, HYBRID_CIPHERTEXTBYTES);
|
|
629
355
|
|
|
630
356
|
cleanup:
|
|
631
357
|
pq_secure_wipe(mlkem_ss, sizeof(mlkem_ss));
|
|
632
358
|
pq_secure_wipe(x25519_ss, sizeof(x25519_ss));
|
|
633
359
|
pq_secure_wipe(x25519_ephemeral_sk, sizeof(x25519_ephemeral_sk));
|
|
360
|
+
pq_secure_wipe(&pk, sizeof(pk));
|
|
361
|
+
pq_secure_wipe(&ct, sizeof(ct));
|
|
634
362
|
return ret;
|
|
635
363
|
}
|
|
636
364
|
|
|
637
365
|
int pq_hybrid_kem_decapsulate(uint8_t *shared_secret, const uint8_t *ciphertext,
|
|
638
366
|
const uint8_t *secret_key) {
|
|
639
|
-
|
|
367
|
+
hybrid_ciphertext_t ct;
|
|
368
|
+
hybrid_secret_key_t sk;
|
|
640
369
|
uint8_t recipient_x25519_pk[X25519_PUBLICKEYBYTES];
|
|
641
|
-
const hybrid_secret_key_t *sk = (const hybrid_secret_key_t *)secret_key;
|
|
642
|
-
|
|
643
370
|
uint8_t mlkem_ss[MLKEM_SHAREDSECRETBYTES];
|
|
644
371
|
uint8_t x25519_ss[X25519_SHAREDSECRETBYTES];
|
|
372
|
+
EVP_PKEY *pkey = NULL;
|
|
373
|
+
size_t pklen = X25519_PUBLICKEYBYTES;
|
|
645
374
|
int ret = PQ_SUCCESS;
|
|
646
375
|
|
|
376
|
+
if (!shared_secret || !ciphertext || !secret_key) {
|
|
377
|
+
return PQ_ERROR_BUFFER;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
memcpy(&ct, ciphertext, HYBRID_CIPHERTEXTBYTES);
|
|
381
|
+
memcpy(&sk, secret_key, HYBRID_SECRETKEYBYTES);
|
|
647
382
|
memset(recipient_x25519_pk, 0, sizeof(recipient_x25519_pk));
|
|
648
383
|
memset(mlkem_ss, 0, sizeof(mlkem_ss));
|
|
649
384
|
memset(x25519_ss, 0, sizeof(x25519_ss));
|
|
650
385
|
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
if (ret != PQ_SUCCESS) {
|
|
386
|
+
if (PQCLEAN_MLKEM768_CLEAN_crypto_kem_dec(mlkem_ss, ct.mlkem_ct, sk.mlkem_sk) != 0) {
|
|
387
|
+
ret = PQ_ERROR_DECAPSULATE;
|
|
654
388
|
goto cleanup;
|
|
655
389
|
}
|
|
656
390
|
|
|
657
|
-
ret = x25519_shared_secret(x25519_ss, ct
|
|
391
|
+
ret = x25519_shared_secret(x25519_ss, ct.x25519_ephemeral, sk.x25519_sk);
|
|
658
392
|
if (ret != PQ_SUCCESS) {
|
|
659
393
|
ret = PQ_ERROR_DECAPSULATE;
|
|
660
394
|
goto cleanup;
|
|
661
395
|
}
|
|
662
396
|
|
|
663
|
-
|
|
664
|
-
if (
|
|
397
|
+
pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_X25519, NULL, sk.x25519_sk, X25519_SECRETKEYBYTES);
|
|
398
|
+
if (!pkey) {
|
|
399
|
+
ret = PQ_ERROR_DECAPSULATE;
|
|
400
|
+
goto cleanup;
|
|
401
|
+
}
|
|
402
|
+
if (EVP_PKEY_get_raw_public_key(pkey, recipient_x25519_pk, &pklen) <= 0 ||
|
|
403
|
+
pklen != X25519_PUBLICKEYBYTES) {
|
|
665
404
|
ret = PQ_ERROR_DECAPSULATE;
|
|
666
405
|
goto cleanup;
|
|
667
406
|
}
|
|
668
407
|
|
|
669
|
-
ret =
|
|
408
|
+
ret = xwing_combiner(shared_secret, mlkem_ss, x25519_ss, ct.x25519_ephemeral,
|
|
409
|
+
recipient_x25519_pk);
|
|
670
410
|
|
|
671
411
|
cleanup:
|
|
412
|
+
if (pkey)
|
|
413
|
+
EVP_PKEY_free(pkey);
|
|
672
414
|
pq_secure_wipe(recipient_x25519_pk, sizeof(recipient_x25519_pk));
|
|
673
415
|
pq_secure_wipe(mlkem_ss, sizeof(mlkem_ss));
|
|
674
416
|
pq_secure_wipe(x25519_ss, sizeof(x25519_ss));
|
|
417
|
+
pq_secure_wipe(&ct, sizeof(ct));
|
|
418
|
+
pq_secure_wipe(&sk, sizeof(sk));
|
|
675
419
|
return ret;
|
|
676
420
|
}
|
|
677
421
|
|
|
678
|
-
int pq_sign_keypair(uint8_t *public_key, uint8_t *secret_key) {
|
|
679
|
-
return mldsa_keypair(public_key, secret_key) == 0 ? PQ_SUCCESS : PQ_ERROR_KEYPAIR;
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
int pq_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len,
|
|
683
|
-
const uint8_t *secret_key) {
|
|
684
|
-
return mldsa_sign(signature, signature_len, message, message_len, secret_key) == 0
|
|
685
|
-
? PQ_SUCCESS
|
|
686
|
-
: PQ_ERROR_SIGN;
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
int pq_verify(const uint8_t *signature, size_t signature_len, const uint8_t *message,
|
|
690
|
-
size_t message_len, const uint8_t *public_key) {
|
|
691
|
-
return mldsa_verify(signature, signature_len, message, message_len, public_key) == 0
|
|
692
|
-
? PQ_SUCCESS
|
|
693
|
-
: PQ_ERROR_VERIFY;
|
|
694
|
-
}
|
|
695
|
-
|
|
696
422
|
#define PQC_SERIALIZATION_MAGIC_0 'P'
|
|
697
423
|
#define PQC_SERIALIZATION_MAGIC_1 'Q'
|
|
698
424
|
#define PQC_SERIALIZATION_MAGIC_2 'C'
|
|
@@ -702,72 +428,64 @@ int pq_verify(const uint8_t *signature, size_t signature_len, const uint8_t *mes
|
|
|
702
428
|
#define PQC_SERIALIZATION_TYPE_SECRET 0x02
|
|
703
429
|
|
|
704
430
|
static const char PQC_OID_ML_KEM_768[] = "2.25.186599352125448088867056807454444238446";
|
|
705
|
-
|
|
706
|
-
|
|
431
|
+
|
|
432
|
+
static const char PQC_OID_ML_KEM_768_X25519_XWING[] =
|
|
433
|
+
"2.25.318532651283923671095712569430174917109";
|
|
707
434
|
static const char PQC_OID_ML_DSA_65[] = "2.25.305232938483772195555080795650659207792";
|
|
435
|
+
static const char PQC_PUBLIC_KEY_PEM_LABEL[] = "PQC PUBLIC KEY CONTAINER";
|
|
436
|
+
static const char PQC_PRIVATE_KEY_PEM_LABEL[] = "PQC PRIVATE KEY CONTAINER";
|
|
708
437
|
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
return PQ_SUCCESS;
|
|
716
|
-
}
|
|
717
|
-
if (strcmp(algorithm, "ml_kem_768_x25519_hkdf_sha256") == 0) {
|
|
718
|
-
*expected_len = is_public ? PQ_HYBRID_PUBLICKEYBYTES : PQ_HYBRID_SECRETKEYBYTES;
|
|
719
|
-
return PQ_SUCCESS;
|
|
720
|
-
}
|
|
721
|
-
if (strcmp(algorithm, "ml_dsa_65") == 0) {
|
|
722
|
-
*expected_len = is_public ? MLDSA_PUBLICKEYBYTES : MLDSA_SECRETKEYBYTES;
|
|
723
|
-
return PQ_SUCCESS;
|
|
724
|
-
}
|
|
725
|
-
return PQ_ERROR_BUFFER;
|
|
726
|
-
}
|
|
438
|
+
typedef struct {
|
|
439
|
+
const char *algorithm;
|
|
440
|
+
const char *oid;
|
|
441
|
+
size_t public_key_len;
|
|
442
|
+
size_t secret_key_len;
|
|
443
|
+
} pq_serialization_algorithm_t;
|
|
727
444
|
|
|
728
|
-
static
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
445
|
+
static const pq_serialization_algorithm_t PQC_SERIALIZATION_ALGORITHMS[] = {
|
|
446
|
+
{"ml_kem_768", PQC_OID_ML_KEM_768, PQ_MLKEM_PUBLICKEYBYTES, PQ_MLKEM_SECRETKEYBYTES},
|
|
447
|
+
{"ml_kem_768_x25519_xwing", PQC_OID_ML_KEM_768_X25519_XWING, PQ_HYBRID_PUBLICKEYBYTES,
|
|
448
|
+
PQ_HYBRID_SECRETKEYBYTES},
|
|
449
|
+
{"ml_dsa_65", PQC_OID_ML_DSA_65, MLDSA_PUBLICKEYBYTES, MLDSA_SECRETKEYBYTES},
|
|
450
|
+
};
|
|
451
|
+
|
|
452
|
+
static const pq_serialization_algorithm_t *pq_find_serialization_algorithm(const char *algorithm) {
|
|
453
|
+
size_t i;
|
|
454
|
+
|
|
455
|
+
if (!algorithm)
|
|
456
|
+
return NULL;
|
|
457
|
+
|
|
458
|
+
for (i = 0; i < sizeof(PQC_SERIALIZATION_ALGORITHMS) / sizeof(PQC_SERIALIZATION_ALGORITHMS[0]);
|
|
459
|
+
++i) {
|
|
460
|
+
if (strcmp(algorithm, PQC_SERIALIZATION_ALGORITHMS[i].algorithm) == 0)
|
|
461
|
+
return &PQC_SERIALIZATION_ALGORITHMS[i];
|
|
742
462
|
}
|
|
743
|
-
|
|
463
|
+
|
|
464
|
+
return NULL;
|
|
744
465
|
}
|
|
745
466
|
|
|
746
|
-
static
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
if (
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
}
|
|
759
|
-
if (oid_len == strlen(PQC_OID_ML_DSA_65) && memcmp(oid, PQC_OID_ML_DSA_65, oid_len) == 0) {
|
|
760
|
-
*algorithm_out = "ml_dsa_65";
|
|
761
|
-
return PQ_SUCCESS;
|
|
467
|
+
static const pq_serialization_algorithm_t *pq_find_serialization_algorithm_by_oid(const char *oid,
|
|
468
|
+
size_t oid_len) {
|
|
469
|
+
size_t i;
|
|
470
|
+
|
|
471
|
+
if (!oid)
|
|
472
|
+
return NULL;
|
|
473
|
+
|
|
474
|
+
for (i = 0; i < sizeof(PQC_SERIALIZATION_ALGORITHMS) / sizeof(PQC_SERIALIZATION_ALGORITHMS[0]);
|
|
475
|
+
++i) {
|
|
476
|
+
const pq_serialization_algorithm_t *entry = &PQC_SERIALIZATION_ALGORITHMS[i];
|
|
477
|
+
if (oid_len == strlen(entry->oid) && memcmp(oid, entry->oid, oid_len) == 0)
|
|
478
|
+
return entry;
|
|
762
479
|
}
|
|
763
|
-
|
|
480
|
+
|
|
481
|
+
return NULL;
|
|
764
482
|
}
|
|
765
483
|
|
|
766
484
|
static int pq_encode_serialized_key(uint8_t **output, size_t *output_len, uint8_t type,
|
|
767
485
|
const uint8_t *key_bytes, size_t key_len,
|
|
768
486
|
const char *algorithm) {
|
|
769
|
-
const
|
|
770
|
-
size_t expected_len
|
|
487
|
+
const pq_serialization_algorithm_t *entry;
|
|
488
|
+
size_t expected_len;
|
|
771
489
|
size_t oid_len;
|
|
772
490
|
size_t total_len = 0;
|
|
773
491
|
uint8_t *buf;
|
|
@@ -779,15 +497,16 @@ static int pq_encode_serialized_key(uint8_t **output, size_t *output_len, uint8_
|
|
|
779
497
|
*output = NULL;
|
|
780
498
|
*output_len = 0;
|
|
781
499
|
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
if (ret != PQ_SUCCESS || key_len != expected_len)
|
|
500
|
+
entry = pq_find_serialization_algorithm(algorithm);
|
|
501
|
+
if (!entry)
|
|
785
502
|
return PQ_ERROR_BUFFER;
|
|
786
|
-
ret = pq_serialization_oid_for_algorithm(algorithm, &oid);
|
|
787
|
-
if (ret != PQ_SUCCESS)
|
|
788
|
-
return ret;
|
|
789
503
|
|
|
790
|
-
|
|
504
|
+
expected_len =
|
|
505
|
+
(type == PQC_SERIALIZATION_TYPE_PUBLIC) ? entry->public_key_len : entry->secret_key_len;
|
|
506
|
+
if (key_len != expected_len)
|
|
507
|
+
return PQ_ERROR_BUFFER;
|
|
508
|
+
|
|
509
|
+
oid_len = strlen(entry->oid);
|
|
791
510
|
if (oid_len == 0 || oid_len > UINT16_MAX)
|
|
792
511
|
return PQ_ERROR_BUFFER;
|
|
793
512
|
if (key_len > UINT32_MAX)
|
|
@@ -821,7 +540,7 @@ static int pq_encode_serialized_key(uint8_t **output, size_t *output_len, uint8_
|
|
|
821
540
|
buf[5] = type;
|
|
822
541
|
buf[6] = (uint8_t)((oid_len >> 8) & 0xFF);
|
|
823
542
|
buf[7] = (uint8_t)(oid_len & 0xFF);
|
|
824
|
-
memcpy(buf + 8, oid, oid_len);
|
|
543
|
+
memcpy(buf + 8, entry->oid, oid_len);
|
|
825
544
|
buf[8 + oid_len + 0] = (uint8_t)((key_len >> 24) & 0xFF);
|
|
826
545
|
buf[8 + oid_len + 1] = (uint8_t)((key_len >> 16) & 0xFF);
|
|
827
546
|
buf[8 + oid_len + 2] = (uint8_t)((key_len >> 8) & 0xFF);
|
|
@@ -837,12 +556,11 @@ static int pq_decode_serialized_key(const uint8_t *input, size_t input_len, uint
|
|
|
837
556
|
char **algorithm_out, uint8_t **key_out, size_t *key_len_out) {
|
|
838
557
|
uint16_t oid_len;
|
|
839
558
|
uint32_t key_len;
|
|
840
|
-
const
|
|
559
|
+
const pq_serialization_algorithm_t *entry;
|
|
841
560
|
size_t offset;
|
|
842
561
|
size_t expected_len = 0;
|
|
843
562
|
uint8_t *key_copy = NULL;
|
|
844
563
|
char *algorithm_copy = NULL;
|
|
845
|
-
int ret;
|
|
846
564
|
|
|
847
565
|
if (!input || !algorithm_out || !key_out || !key_len_out)
|
|
848
566
|
return PQ_ERROR_BUFFER;
|
|
@@ -866,18 +584,18 @@ static int pq_decode_serialized_key(const uint8_t *input, size_t input_len, uint
|
|
|
866
584
|
offset = 8;
|
|
867
585
|
if (input_len < offset || input_len - offset < (size_t)oid_len + 4)
|
|
868
586
|
return PQ_ERROR_BUFFER;
|
|
869
|
-
|
|
870
|
-
if (
|
|
871
|
-
return
|
|
587
|
+
entry = pq_find_serialization_algorithm_by_oid((const char *)(input + offset), oid_len);
|
|
588
|
+
if (!entry)
|
|
589
|
+
return PQ_ERROR_BUFFER;
|
|
872
590
|
offset += oid_len;
|
|
873
591
|
key_len = ((uint32_t)input[offset + 0] << 24) | ((uint32_t)input[offset + 1] << 16) |
|
|
874
592
|
((uint32_t)input[offset + 2] << 8) | (uint32_t)input[offset + 3];
|
|
875
593
|
offset += 4;
|
|
876
594
|
if (input_len < offset || input_len - offset != (size_t)key_len)
|
|
877
595
|
return PQ_ERROR_BUFFER;
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
if (
|
|
596
|
+
expected_len = (expected_type == PQC_SERIALIZATION_TYPE_PUBLIC) ? entry->public_key_len
|
|
597
|
+
: entry->secret_key_len;
|
|
598
|
+
if ((size_t)key_len != expected_len)
|
|
881
599
|
return PQ_ERROR_BUFFER;
|
|
882
600
|
|
|
883
601
|
key_copy = malloc((size_t)key_len);
|
|
@@ -886,14 +604,14 @@ static int pq_decode_serialized_key(const uint8_t *input, size_t input_len, uint
|
|
|
886
604
|
memcpy(key_copy, input + offset, (size_t)key_len);
|
|
887
605
|
|
|
888
606
|
{
|
|
889
|
-
size_t algorithm_len = strlen(algorithm);
|
|
607
|
+
size_t algorithm_len = strlen(entry->algorithm);
|
|
890
608
|
algorithm_copy = malloc(algorithm_len + 1);
|
|
891
609
|
if (!algorithm_copy) {
|
|
892
610
|
pq_secure_wipe(key_copy, (size_t)key_len);
|
|
893
611
|
free(key_copy);
|
|
894
612
|
return PQ_ERROR_NOMEM;
|
|
895
613
|
}
|
|
896
|
-
memcpy(algorithm_copy, algorithm, algorithm_len + 1);
|
|
614
|
+
memcpy(algorithm_copy, entry->algorithm, algorithm_len + 1);
|
|
897
615
|
}
|
|
898
616
|
|
|
899
617
|
*algorithm_out = algorithm_copy;
|
|
@@ -904,17 +622,17 @@ static int pq_decode_serialized_key(const uint8_t *input, size_t input_len, uint
|
|
|
904
622
|
|
|
905
623
|
static int pq_der_to_pem(const char *label, const uint8_t *der, size_t der_len, char **output,
|
|
906
624
|
size_t *output_len) {
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
unsigned char *encoded = NULL;
|
|
912
|
-
char *pem = NULL;
|
|
625
|
+
BIO *bio_mem = NULL;
|
|
626
|
+
BIO *bio_b64 = NULL;
|
|
627
|
+
BIO *bio_chain = NULL;
|
|
628
|
+
BUF_MEM *bptr = NULL;
|
|
913
629
|
char header[64];
|
|
914
630
|
char footer[64];
|
|
915
|
-
char *cursor;
|
|
916
631
|
int header_len, footer_len;
|
|
917
|
-
int ret;
|
|
632
|
+
int ret = PQ_ERROR_OPENSSL;
|
|
633
|
+
char *pem = NULL;
|
|
634
|
+
size_t total_len = 0;
|
|
635
|
+
size_t needed = 0;
|
|
918
636
|
|
|
919
637
|
if (!label || !der || !output || !output_len)
|
|
920
638
|
return PQ_ERROR_BUFFER;
|
|
@@ -927,55 +645,68 @@ static int pq_der_to_pem(const char *label, const uint8_t *der, size_t der_len,
|
|
|
927
645
|
if (der_len > (size_t)INT_MAX)
|
|
928
646
|
return PQ_ERROR_BUFFER;
|
|
929
647
|
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
line_count /= 64;
|
|
937
|
-
ret = pq_size_add(encoded_len, line_count, &body_len);
|
|
938
|
-
if (ret != PQ_SUCCESS)
|
|
939
|
-
return ret;
|
|
940
|
-
ret = pq_size_add((size_t)header_len, body_len, &total_len);
|
|
941
|
-
if (ret != PQ_SUCCESS)
|
|
942
|
-
return ret;
|
|
943
|
-
ret = pq_size_add(total_len, (size_t)footer_len, &total_len);
|
|
944
|
-
if (ret != PQ_SUCCESS)
|
|
945
|
-
return ret;
|
|
648
|
+
bio_b64 = BIO_new(BIO_f_base64());
|
|
649
|
+
bio_mem = BIO_new(BIO_s_mem());
|
|
650
|
+
if (!bio_b64 || !bio_mem) {
|
|
651
|
+
ret = PQ_ERROR_NOMEM;
|
|
652
|
+
goto cleanup;
|
|
653
|
+
}
|
|
946
654
|
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
if (
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
655
|
+
bio_chain = BIO_push(bio_b64, bio_mem);
|
|
656
|
+
|
|
657
|
+
if (BIO_write(bio_chain, der, (int)der_len) != (int)der_len)
|
|
658
|
+
goto cleanup;
|
|
659
|
+
if (BIO_flush(bio_chain) != 1)
|
|
660
|
+
goto cleanup;
|
|
661
|
+
BIO_get_mem_ptr(bio_chain, &bptr);
|
|
662
|
+
if (!bptr || !bptr->data)
|
|
663
|
+
goto cleanup;
|
|
664
|
+
|
|
665
|
+
{
|
|
666
|
+
size_t body_len = bptr->length;
|
|
667
|
+
needed = (size_t)header_len + 1 + body_len;
|
|
668
|
+
if (body_len == 0 || bptr->data[body_len - 1] != '\n')
|
|
669
|
+
needed += 1;
|
|
670
|
+
needed += (size_t)footer_len + 1;
|
|
671
|
+
|
|
672
|
+
pem = malloc(needed);
|
|
673
|
+
if (!pem) {
|
|
674
|
+
ret = PQ_ERROR_NOMEM;
|
|
675
|
+
goto cleanup;
|
|
676
|
+
}
|
|
677
|
+
char *cur = pem;
|
|
678
|
+
memcpy(cur, header, (size_t)header_len);
|
|
679
|
+
cur += header_len;
|
|
680
|
+
*cur++ = '\n';
|
|
681
|
+
memcpy(cur, bptr->data, body_len);
|
|
682
|
+
cur += body_len;
|
|
683
|
+
if (body_len == 0 || bptr->data[body_len - 1] != '\n')
|
|
684
|
+
*cur++ = '\n';
|
|
685
|
+
memcpy(cur, footer, (size_t)footer_len);
|
|
686
|
+
cur += footer_len;
|
|
687
|
+
*cur = '\0';
|
|
688
|
+
total_len = (size_t)(cur - pem);
|
|
953
689
|
}
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
690
|
+
|
|
691
|
+
*output = pem;
|
|
692
|
+
*output_len = total_len;
|
|
693
|
+
pem = NULL;
|
|
694
|
+
ret = PQ_SUCCESS;
|
|
695
|
+
|
|
696
|
+
cleanup:
|
|
697
|
+
if (bio_chain) {
|
|
698
|
+
BIO_free_all(bio_chain);
|
|
699
|
+
} else {
|
|
700
|
+
if (bio_b64)
|
|
701
|
+
BIO_free(bio_b64);
|
|
702
|
+
if (bio_mem)
|
|
703
|
+
BIO_free(bio_mem);
|
|
704
|
+
}
|
|
705
|
+
if (pem) {
|
|
706
|
+
pq_secure_wipe(pem, needed);
|
|
957
707
|
free(pem);
|
|
958
|
-
return PQ_ERROR_OPENSSL;
|
|
959
|
-
}
|
|
960
|
-
cursor = pem;
|
|
961
|
-
memcpy(cursor, header, (size_t)header_len);
|
|
962
|
-
cursor += header_len;
|
|
963
|
-
for (size_t off = 0; off < encoded_len; off += 64) {
|
|
964
|
-
size_t chunk = encoded_len - off;
|
|
965
|
-
if (chunk > 64)
|
|
966
|
-
chunk = 64;
|
|
967
|
-
memcpy(cursor, encoded + off, chunk);
|
|
968
|
-
cursor += chunk;
|
|
969
|
-
*cursor++ = '\n';
|
|
970
708
|
}
|
|
971
|
-
|
|
972
|
-
cursor += footer_len;
|
|
973
|
-
*cursor = '\0';
|
|
974
|
-
*output = pem;
|
|
975
|
-
*output_len = (size_t)(cursor - pem);
|
|
976
|
-
pq_secure_wipe(encoded, encoded_len + 1);
|
|
977
|
-
free(encoded);
|
|
978
|
-
return PQ_SUCCESS;
|
|
709
|
+
return ret;
|
|
979
710
|
}
|
|
980
711
|
|
|
981
712
|
static int pq_pem_to_der(const char *label, const char *input, size_t input_len, uint8_t **der_out,
|
|
@@ -984,13 +715,13 @@ static int pq_pem_to_der(const char *label, const char *input, size_t input_len,
|
|
|
984
715
|
int header_len, footer_len;
|
|
985
716
|
const char *body_start, *footer_pos;
|
|
986
717
|
const char *tail;
|
|
987
|
-
char *encoded = NULL;
|
|
988
718
|
uint8_t *der = NULL;
|
|
989
|
-
size_t
|
|
990
|
-
size_t der_capacity = 0;
|
|
991
|
-
int decoded_len;
|
|
719
|
+
size_t body_len = 0;
|
|
992
720
|
int ret;
|
|
993
|
-
|
|
721
|
+
BIO *bio_b64 = NULL;
|
|
722
|
+
BIO *bio_mem = NULL;
|
|
723
|
+
BIO *bio_chain = NULL;
|
|
724
|
+
int decoded_len = 0;
|
|
994
725
|
|
|
995
726
|
if (!label || !input || !der_out || !der_len_out)
|
|
996
727
|
return PQ_ERROR_BUFFER;
|
|
@@ -1030,63 +761,57 @@ static int pq_pem_to_der(const char *label, const char *input, size_t input_len,
|
|
|
1030
761
|
tail++;
|
|
1031
762
|
}
|
|
1032
763
|
|
|
1033
|
-
|
|
1034
|
-
if (
|
|
1035
|
-
return PQ_ERROR_NOMEM;
|
|
1036
|
-
for (const char *p = body_start; p < footer_pos; ++p) {
|
|
1037
|
-
if (pq_is_pem_whitespace(*p))
|
|
1038
|
-
continue;
|
|
1039
|
-
encoded[encoded_len++] = *p;
|
|
1040
|
-
}
|
|
1041
|
-
if (encoded_len == 0 || (encoded_len % 4) != 0) {
|
|
1042
|
-
free(encoded);
|
|
764
|
+
body_len = (size_t)(footer_pos - body_start);
|
|
765
|
+
if (body_len > (size_t)INT_MAX)
|
|
1043
766
|
return PQ_ERROR_BUFFER;
|
|
1044
|
-
}
|
|
1045
|
-
encoded[encoded_len] = '\0';
|
|
1046
767
|
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
}
|
|
1053
|
-
ret = pq_size_add(der_capacity, 1, &der_capacity);
|
|
1054
|
-
if (ret != PQ_SUCCESS || der_capacity == 0) {
|
|
1055
|
-
pq_secure_wipe(encoded, encoded_len + 1);
|
|
1056
|
-
free(encoded);
|
|
1057
|
-
return PQ_ERROR_BUFFER;
|
|
1058
|
-
}
|
|
768
|
+
{
|
|
769
|
+
size_t der_cap = (body_len * 3) / 4 + 3;
|
|
770
|
+
der = malloc(der_cap ? der_cap : 1);
|
|
771
|
+
if (!der)
|
|
772
|
+
return PQ_ERROR_NOMEM;
|
|
1059
773
|
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
774
|
+
bio_mem = BIO_new_mem_buf(body_start, (int)body_len);
|
|
775
|
+
bio_b64 = BIO_new(BIO_f_base64());
|
|
776
|
+
if (!bio_mem || !bio_b64) {
|
|
777
|
+
ret = PQ_ERROR_NOMEM;
|
|
778
|
+
goto cleanup;
|
|
779
|
+
}
|
|
780
|
+
bio_chain = BIO_push(bio_b64, bio_mem);
|
|
781
|
+
|
|
782
|
+
decoded_len = BIO_read(bio_chain, der, (int)der_cap);
|
|
783
|
+
if (decoded_len <= 0) {
|
|
784
|
+
ret = PQ_ERROR_BUFFER;
|
|
785
|
+
goto cleanup;
|
|
786
|
+
}
|
|
787
|
+
{
|
|
788
|
+
unsigned char tail_byte;
|
|
789
|
+
int extra = BIO_read(bio_chain, &tail_byte, 1);
|
|
790
|
+
if (extra > 0) {
|
|
791
|
+
ret = PQ_ERROR_BUFFER;
|
|
792
|
+
goto cleanup;
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
*der_len_out = (size_t)decoded_len;
|
|
797
|
+
*der_out = der;
|
|
798
|
+
der = NULL;
|
|
799
|
+
ret = PQ_SUCCESS;
|
|
1073
800
|
}
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
if (
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
801
|
+
|
|
802
|
+
cleanup:
|
|
803
|
+
if (bio_chain) {
|
|
804
|
+
BIO_free_all(bio_chain);
|
|
805
|
+
} else {
|
|
806
|
+
if (bio_b64)
|
|
807
|
+
BIO_free(bio_b64);
|
|
808
|
+
if (bio_mem)
|
|
809
|
+
BIO_free(bio_mem);
|
|
810
|
+
}
|
|
811
|
+
if (der) {
|
|
1082
812
|
free(der);
|
|
1083
|
-
return PQ_ERROR_BUFFER;
|
|
1084
813
|
}
|
|
1085
|
-
|
|
1086
|
-
*der_out = der;
|
|
1087
|
-
pq_secure_wipe(encoded, encoded_len + 1);
|
|
1088
|
-
free(encoded);
|
|
1089
|
-
return PQ_SUCCESS;
|
|
814
|
+
return ret;
|
|
1090
815
|
}
|
|
1091
816
|
|
|
1092
817
|
int pq_public_key_to_pqc_container_der(uint8_t **output, size_t *output_len,
|
|
@@ -1104,7 +829,7 @@ int pq_public_key_to_pqc_container_pem(char **output, size_t *output_len, const
|
|
|
1104
829
|
ret = pq_public_key_to_pqc_container_der(&der, &der_len, public_key, public_key_len, algorithm);
|
|
1105
830
|
if (ret != PQ_SUCCESS)
|
|
1106
831
|
return ret;
|
|
1107
|
-
ret = pq_der_to_pem(
|
|
832
|
+
ret = pq_der_to_pem(PQC_PUBLIC_KEY_PEM_LABEL, der, der_len, output, output_len);
|
|
1108
833
|
pq_secure_wipe(der, der_len);
|
|
1109
834
|
free(der);
|
|
1110
835
|
return ret;
|
|
@@ -1125,7 +850,7 @@ int pq_secret_key_to_pqc_container_pem(char **output, size_t *output_len, const
|
|
|
1125
850
|
ret = pq_secret_key_to_pqc_container_der(&der, &der_len, secret_key, secret_key_len, algorithm);
|
|
1126
851
|
if (ret != PQ_SUCCESS)
|
|
1127
852
|
return ret;
|
|
1128
|
-
ret = pq_der_to_pem(
|
|
853
|
+
ret = pq_der_to_pem(PQC_PRIVATE_KEY_PEM_LABEL, der, der_len, output, output_len);
|
|
1129
854
|
pq_secure_wipe(der, der_len);
|
|
1130
855
|
free(der);
|
|
1131
856
|
return ret;
|
|
@@ -1143,7 +868,7 @@ int pq_public_key_from_pqc_container_pem(char **algorithm_out, uint8_t **key_out
|
|
|
1143
868
|
uint8_t *der = NULL;
|
|
1144
869
|
size_t der_len = 0;
|
|
1145
870
|
int ret;
|
|
1146
|
-
ret = pq_pem_to_der(
|
|
871
|
+
ret = pq_pem_to_der(PQC_PUBLIC_KEY_PEM_LABEL, input, input_len, &der, &der_len);
|
|
1147
872
|
if (ret != PQ_SUCCESS)
|
|
1148
873
|
return ret;
|
|
1149
874
|
ret = pq_public_key_from_pqc_container_der(algorithm_out, key_out, key_len_out, der, der_len);
|
|
@@ -1164,7 +889,7 @@ int pq_secret_key_from_pqc_container_pem(char **algorithm_out, uint8_t **key_out
|
|
|
1164
889
|
uint8_t *der = NULL;
|
|
1165
890
|
size_t der_len = 0;
|
|
1166
891
|
int ret;
|
|
1167
|
-
ret = pq_pem_to_der(
|
|
892
|
+
ret = pq_pem_to_der(PQC_PRIVATE_KEY_PEM_LABEL, input, input_len, &der, &der_len);
|
|
1168
893
|
if (ret != PQ_SUCCESS)
|
|
1169
894
|
return ret;
|
|
1170
895
|
ret = pq_secret_key_from_pqc_container_der(algorithm_out, key_out, key_len_out, der, der_len);
|
|
@@ -1174,5 +899,5 @@ int pq_secret_key_from_pqc_container_pem(char **algorithm_out, uint8_t **key_out
|
|
|
1174
899
|
}
|
|
1175
900
|
|
|
1176
901
|
const char *pq_version(void) {
|
|
1177
|
-
return "0.
|
|
902
|
+
return "0.3.0";
|
|
1178
903
|
}
|