pq_crypto 0.6.0 → 0.6.1

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.
@@ -15,6 +15,9 @@
15
15
  #include <openssl/crypto.h>
16
16
  #include <openssl/evp.h>
17
17
  #include <openssl/rand.h>
18
+ #include <openssl/x509.h>
19
+ #include <openssl/pkcs12.h>
20
+ #include <openssl/objects.h>
18
21
 
19
22
  #if OPENSSL_VERSION_NUMBER < 0x30000000L
20
23
  #error "OpenSSL 3.0 or later is required for pq_crypto"
@@ -1159,6 +1162,535 @@ int pq_secret_key_from_pqc_container_pem(char **algorithm_out, uint8_t **key_out
1159
1162
  return ret;
1160
1163
  }
1161
1164
 
1165
+ #define PQ_PKCS8_PRIVATE_KEY_PEM_LABEL "PRIVATE KEY"
1166
+ #define PQ_PKCS8_ENCRYPTED_PRIVATE_KEY_PEM_LABEL "ENCRYPTED PRIVATE KEY"
1167
+
1168
+ static size_t pq_der_length_octets(size_t len) {
1169
+ size_t octets = 0;
1170
+ size_t v = len;
1171
+
1172
+ if (len < 0x80)
1173
+ return 1;
1174
+ do {
1175
+ octets++;
1176
+ v >>= 8;
1177
+ } while (v != 0);
1178
+ return 1 + octets;
1179
+ }
1180
+
1181
+ static int pq_der_write_length(uint8_t **cursor, size_t len) {
1182
+ uint8_t *p;
1183
+ size_t octets = 0;
1184
+ size_t v = len;
1185
+
1186
+ if (!cursor || !*cursor)
1187
+ return PQ_ERROR_BUFFER;
1188
+
1189
+ p = *cursor;
1190
+ if (len < 0x80) {
1191
+ *p++ = (uint8_t)len;
1192
+ *cursor = p;
1193
+ return PQ_SUCCESS;
1194
+ }
1195
+
1196
+ do {
1197
+ octets++;
1198
+ v >>= 8;
1199
+ } while (v != 0);
1200
+ if (octets > sizeof(size_t))
1201
+ return PQ_ERROR_BUFFER;
1202
+
1203
+ *p++ = (uint8_t)(0x80u | (uint8_t)octets);
1204
+ for (size_t i = 0; i < octets; ++i) {
1205
+ size_t shift = 8 * (octets - 1 - i);
1206
+ *p++ = (uint8_t)((len >> shift) & 0xffu);
1207
+ }
1208
+ *cursor = p;
1209
+ return PQ_SUCCESS;
1210
+ }
1211
+
1212
+ static int pq_der_read_length(const uint8_t *input, size_t input_len, size_t *offset,
1213
+ size_t *len_out) {
1214
+ uint8_t first;
1215
+ size_t len = 0;
1216
+ size_t length_octets;
1217
+
1218
+ if (!input || !offset || !len_out || *offset >= input_len)
1219
+ return PQ_ERROR_BUFFER;
1220
+
1221
+ first = input[(*offset)++];
1222
+ if (first < 0x80) {
1223
+ *len_out = (size_t)first;
1224
+ return PQ_SUCCESS;
1225
+ }
1226
+
1227
+ length_octets = (size_t)(first & 0x7fu);
1228
+ if (length_octets == 0 || length_octets > sizeof(size_t))
1229
+ return PQ_ERROR_BUFFER;
1230
+ if (input_len - *offset < length_octets)
1231
+ return PQ_ERROR_BUFFER;
1232
+ if (input[*offset] == 0)
1233
+ return PQ_ERROR_BUFFER;
1234
+
1235
+ for (size_t i = 0; i < length_octets; ++i) {
1236
+ if (len > (SIZE_MAX >> 8))
1237
+ return PQ_ERROR_BUFFER;
1238
+ len = (len << 8) | (size_t)input[*offset + i];
1239
+ }
1240
+ if (len < 0x80)
1241
+ return PQ_ERROR_BUFFER;
1242
+
1243
+ *offset += length_octets;
1244
+ *len_out = len;
1245
+ return PQ_SUCCESS;
1246
+ }
1247
+
1248
+ static int pq_der_expect_tlv(const uint8_t *input, size_t input_len, size_t *offset,
1249
+ uint8_t expected_tag, size_t *value_offset_out,
1250
+ size_t *value_len_out) {
1251
+ size_t value_len;
1252
+ size_t value_offset;
1253
+
1254
+ if (!input || !offset || !value_offset_out || !value_len_out || *offset >= input_len)
1255
+ return PQ_ERROR_BUFFER;
1256
+ if (input[(*offset)++] != expected_tag)
1257
+ return PQ_ERROR_BUFFER;
1258
+ if (pq_der_read_length(input, input_len, offset, &value_len) != PQ_SUCCESS)
1259
+ return PQ_ERROR_BUFFER;
1260
+ value_offset = *offset;
1261
+ if (input_len - value_offset < value_len)
1262
+ return PQ_ERROR_BUFFER;
1263
+ *offset = value_offset + value_len;
1264
+ *value_offset_out = value_offset;
1265
+ *value_len_out = value_len;
1266
+ return PQ_SUCCESS;
1267
+ }
1268
+
1269
+ static int pq_oid_text_to_der(const char *oid_text, uint8_t **oid_der_out,
1270
+ size_t *oid_der_len_out) {
1271
+ ASN1_OBJECT *obj = NULL;
1272
+ uint8_t *der = NULL;
1273
+ unsigned char *cursor;
1274
+ int der_len;
1275
+ int ret = PQ_ERROR_OPENSSL;
1276
+
1277
+ if (!oid_text || !oid_der_out || !oid_der_len_out)
1278
+ return PQ_ERROR_BUFFER;
1279
+ *oid_der_out = NULL;
1280
+ *oid_der_len_out = 0;
1281
+
1282
+ obj = OBJ_txt2obj(oid_text, 1);
1283
+ if (!obj)
1284
+ goto cleanup;
1285
+ der_len = i2d_ASN1_OBJECT(obj, NULL);
1286
+ if (der_len <= 0)
1287
+ goto cleanup;
1288
+ der = malloc((size_t)der_len);
1289
+ if (!der) {
1290
+ ret = PQ_ERROR_NOMEM;
1291
+ goto cleanup;
1292
+ }
1293
+ cursor = der;
1294
+ if (i2d_ASN1_OBJECT(obj, &cursor) != der_len || (size_t)(cursor - der) != (size_t)der_len)
1295
+ goto cleanup;
1296
+
1297
+ *oid_der_out = der;
1298
+ *oid_der_len_out = (size_t)der_len;
1299
+ der = NULL;
1300
+ ret = PQ_SUCCESS;
1301
+
1302
+ cleanup:
1303
+ if (der) {
1304
+ pq_secure_wipe(der, (size_t)(der_len > 0 ? der_len : 0));
1305
+ free(der);
1306
+ }
1307
+ if (obj)
1308
+ ASN1_OBJECT_free(obj);
1309
+ return ret;
1310
+ }
1311
+
1312
+ static int pq_oid_der_to_text(const uint8_t *oid_der, size_t oid_der_len, char **oid_text_out) {
1313
+ ASN1_OBJECT *obj = NULL;
1314
+ const unsigned char *cursor;
1315
+ char tmp[128];
1316
+ int text_len;
1317
+ char *copy = NULL;
1318
+ int ret = PQ_ERROR_OPENSSL;
1319
+
1320
+ if (!oid_der || oid_der_len == 0 || oid_der_len > (size_t)LONG_MAX || !oid_text_out)
1321
+ return PQ_ERROR_BUFFER;
1322
+ *oid_text_out = NULL;
1323
+
1324
+ cursor = oid_der;
1325
+ obj = d2i_ASN1_OBJECT(NULL, &cursor, (long)oid_der_len);
1326
+ if (!obj || cursor != oid_der + oid_der_len)
1327
+ goto cleanup;
1328
+ text_len = OBJ_obj2txt(tmp, sizeof(tmp), obj, 1);
1329
+ if (text_len <= 0 || (size_t)text_len >= sizeof(tmp))
1330
+ goto cleanup;
1331
+ copy = malloc((size_t)text_len + 1);
1332
+ if (!copy) {
1333
+ ret = PQ_ERROR_NOMEM;
1334
+ goto cleanup;
1335
+ }
1336
+ memcpy(copy, tmp, (size_t)text_len + 1);
1337
+ *oid_text_out = copy;
1338
+ copy = NULL;
1339
+ ret = PQ_SUCCESS;
1340
+
1341
+ cleanup:
1342
+ if (copy)
1343
+ free(copy);
1344
+ if (obj)
1345
+ ASN1_OBJECT_free(obj);
1346
+ return ret;
1347
+ }
1348
+
1349
+ int pq_pkcs8_private_key_info_to_der(uint8_t **output, size_t *output_len, const char *oid_text,
1350
+ const uint8_t *private_key, size_t private_key_len) {
1351
+ uint8_t *oid_der = NULL;
1352
+ size_t oid_der_len = 0;
1353
+ size_t alg_body_len, alg_len, priv_len, inner_len, total_len;
1354
+ uint8_t *buf = NULL;
1355
+ uint8_t *cur;
1356
+ int ret;
1357
+
1358
+ if (!output || !output_len || !oid_text || !private_key)
1359
+ return PQ_ERROR_BUFFER;
1360
+ *output = NULL;
1361
+ *output_len = 0;
1362
+
1363
+ ret = pq_oid_text_to_der(oid_text, &oid_der, &oid_der_len);
1364
+ if (ret != PQ_SUCCESS)
1365
+ return ret;
1366
+
1367
+ alg_body_len = oid_der_len;
1368
+ alg_len = 1 + pq_der_length_octets(alg_body_len) + alg_body_len;
1369
+ priv_len = 1 + pq_der_length_octets(private_key_len) + private_key_len;
1370
+ if (pq_size_add(3, alg_len, &inner_len) != PQ_SUCCESS ||
1371
+ pq_size_add(inner_len, priv_len, &inner_len) != PQ_SUCCESS) {
1372
+ ret = PQ_ERROR_BUFFER;
1373
+ goto cleanup;
1374
+ }
1375
+ if (pq_size_add(1 + pq_der_length_octets(inner_len), inner_len, &total_len) != PQ_SUCCESS) {
1376
+ ret = PQ_ERROR_BUFFER;
1377
+ goto cleanup;
1378
+ }
1379
+
1380
+ buf = malloc(total_len);
1381
+ if (!buf) {
1382
+ ret = PQ_ERROR_NOMEM;
1383
+ goto cleanup;
1384
+ }
1385
+
1386
+ cur = buf;
1387
+ *cur++ = 0x30;
1388
+ ret = pq_der_write_length(&cur, inner_len);
1389
+ if (ret != PQ_SUCCESS)
1390
+ goto cleanup;
1391
+ *cur++ = 0x02;
1392
+ *cur++ = 0x01;
1393
+ *cur++ = 0x00;
1394
+ *cur++ = 0x30;
1395
+ ret = pq_der_write_length(&cur, alg_body_len);
1396
+ if (ret != PQ_SUCCESS)
1397
+ goto cleanup;
1398
+ memcpy(cur, oid_der, oid_der_len);
1399
+ cur += oid_der_len;
1400
+ *cur++ = 0x04;
1401
+ ret = pq_der_write_length(&cur, private_key_len);
1402
+ if (ret != PQ_SUCCESS)
1403
+ goto cleanup;
1404
+ memcpy(cur, private_key, private_key_len);
1405
+ cur += private_key_len;
1406
+ if ((size_t)(cur - buf) != total_len) {
1407
+ ret = PQ_ERROR_BUFFER;
1408
+ goto cleanup;
1409
+ }
1410
+
1411
+ *output = buf;
1412
+ *output_len = total_len;
1413
+ buf = NULL;
1414
+ ret = PQ_SUCCESS;
1415
+
1416
+ cleanup:
1417
+ if (buf) {
1418
+ pq_secure_wipe(buf, total_len);
1419
+ free(buf);
1420
+ }
1421
+ if (oid_der) {
1422
+ pq_secure_wipe(oid_der, oid_der_len);
1423
+ free(oid_der);
1424
+ }
1425
+ return ret;
1426
+ }
1427
+
1428
+ int pq_pkcs8_private_key_info_from_der(char **oid_text_out, uint8_t **private_key_out,
1429
+ size_t *private_key_len_out, const uint8_t *input,
1430
+ size_t input_len) {
1431
+ size_t offset = 0;
1432
+ size_t outer_off = 0, outer_len = 0, outer_end;
1433
+ size_t alg_off = 0, alg_len = 0, alg_end;
1434
+ size_t oid_off = 0, oid_len = 0;
1435
+ size_t priv_off = 0, priv_len = 0;
1436
+ uint8_t *private_key = NULL;
1437
+ char *oid_text = NULL;
1438
+ int ret;
1439
+
1440
+ if (!oid_text_out || !private_key_out || !private_key_len_out || !input)
1441
+ return PQ_ERROR_BUFFER;
1442
+ *oid_text_out = NULL;
1443
+ *private_key_out = NULL;
1444
+ *private_key_len_out = 0;
1445
+
1446
+ ret = pq_der_expect_tlv(input, input_len, &offset, 0x30, &outer_off, &outer_len);
1447
+ if (ret != PQ_SUCCESS)
1448
+ return ret;
1449
+ outer_end = outer_off + outer_len;
1450
+ if (offset != input_len || outer_end != input_len)
1451
+ return PQ_ERROR_BUFFER;
1452
+
1453
+ offset = outer_off;
1454
+ {
1455
+ size_t version_off = 0, version_len = 0;
1456
+ ret = pq_der_expect_tlv(input, outer_end, &offset, 0x02, &version_off, &version_len);
1457
+ if (ret != PQ_SUCCESS)
1458
+ return ret;
1459
+ if (version_len != 1 || input[version_off] != 0x00)
1460
+ return PQ_ERROR_BUFFER;
1461
+ }
1462
+
1463
+ ret = pq_der_expect_tlv(input, outer_end, &offset, 0x30, &alg_off, &alg_len);
1464
+ if (ret != PQ_SUCCESS)
1465
+ return ret;
1466
+ alg_end = alg_off + alg_len;
1467
+ {
1468
+ size_t alg_cursor = alg_off;
1469
+ size_t oid_tlv_start = alg_cursor;
1470
+ ret = pq_der_expect_tlv(input, alg_end, &alg_cursor, 0x06, &oid_off, &oid_len);
1471
+ if (ret != PQ_SUCCESS)
1472
+ return ret;
1473
+ if (alg_cursor != alg_end)
1474
+ return PQ_ERROR_BUFFER;
1475
+ ret = pq_oid_der_to_text(input + oid_tlv_start, alg_cursor - oid_tlv_start, &oid_text);
1476
+ }
1477
+ if (ret != PQ_SUCCESS)
1478
+ return ret;
1479
+
1480
+ ret = pq_der_expect_tlv(input, outer_end, &offset, 0x04, &priv_off, &priv_len);
1481
+ if (ret != PQ_SUCCESS)
1482
+ goto cleanup;
1483
+ if (offset != outer_end) {
1484
+ ret = PQ_ERROR_BUFFER;
1485
+ goto cleanup;
1486
+ }
1487
+ private_key = malloc(priv_len ? priv_len : 1);
1488
+ if (!private_key) {
1489
+ ret = PQ_ERROR_NOMEM;
1490
+ goto cleanup;
1491
+ }
1492
+ if (priv_len)
1493
+ memcpy(private_key, input + priv_off, priv_len);
1494
+
1495
+ *oid_text_out = oid_text;
1496
+ *private_key_out = private_key;
1497
+ *private_key_len_out = priv_len;
1498
+ oid_text = NULL;
1499
+ private_key = NULL;
1500
+ ret = PQ_SUCCESS;
1501
+
1502
+ cleanup:
1503
+ if (oid_text)
1504
+ free(oid_text);
1505
+ if (private_key) {
1506
+ pq_secure_wipe(private_key, priv_len);
1507
+ free(private_key);
1508
+ }
1509
+ return ret;
1510
+ }
1511
+
1512
+ int pq_pkcs8_encrypt_private_key_info_der(uint8_t **output, size_t *output_len,
1513
+ const uint8_t *plain_der, size_t plain_der_len,
1514
+ const char *passphrase, size_t passphrase_len,
1515
+ int iterations) {
1516
+ const unsigned char *cursor;
1517
+ PKCS8_PRIV_KEY_INFO *p8 = NULL;
1518
+ X509_SIG *encrypted = NULL;
1519
+ unsigned char salt[16];
1520
+ unsigned char *der = NULL;
1521
+ unsigned char *der_cursor;
1522
+ int der_len;
1523
+ int ret = PQ_ERROR_OPENSSL;
1524
+
1525
+ if (!output || !output_len || !plain_der || !passphrase || iterations <= 0 ||
1526
+ passphrase_len > (size_t)INT_MAX || plain_der_len > (size_t)LONG_MAX)
1527
+ return PQ_ERROR_BUFFER;
1528
+ *output = NULL;
1529
+ *output_len = 0;
1530
+
1531
+ cursor = plain_der;
1532
+ p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, &cursor, (long)plain_der_len);
1533
+ if (!p8 || cursor != plain_der + plain_der_len)
1534
+ goto cleanup;
1535
+ if (RAND_bytes(salt, sizeof(salt)) != 1)
1536
+ goto cleanup;
1537
+
1538
+ encrypted = PKCS8_encrypt(-1, EVP_aes_256_cbc(), passphrase, (int)passphrase_len, salt,
1539
+ (int)sizeof(salt), iterations, p8);
1540
+ if (!encrypted)
1541
+ goto cleanup;
1542
+
1543
+ der_len = i2d_X509_SIG(encrypted, NULL);
1544
+ if (der_len <= 0) {
1545
+ ret = PQ_ERROR_OPENSSL;
1546
+ goto cleanup;
1547
+ }
1548
+ der = malloc((size_t)der_len);
1549
+ if (!der) {
1550
+ ret = PQ_ERROR_NOMEM;
1551
+ goto cleanup;
1552
+ }
1553
+ der_cursor = der;
1554
+ if (i2d_X509_SIG(encrypted, &der_cursor) != der_len ||
1555
+ (size_t)(der_cursor - der) != (size_t)der_len)
1556
+ goto cleanup;
1557
+
1558
+ *output = der;
1559
+ *output_len = (size_t)der_len;
1560
+ der = NULL;
1561
+ ret = PQ_SUCCESS;
1562
+
1563
+ cleanup:
1564
+ pq_secure_wipe(salt, sizeof(salt));
1565
+ if (der) {
1566
+ pq_secure_wipe(der, (size_t)(der_len > 0 ? der_len : 0));
1567
+ free(der);
1568
+ }
1569
+ if (encrypted)
1570
+ X509_SIG_free(encrypted);
1571
+ if (p8)
1572
+ PKCS8_PRIV_KEY_INFO_free(p8);
1573
+ return ret;
1574
+ }
1575
+
1576
+ int pq_pkcs8_decrypt_private_key_info_der(uint8_t **output, size_t *output_len,
1577
+ const uint8_t *encrypted_der, size_t encrypted_der_len,
1578
+ const char *passphrase, size_t passphrase_len) {
1579
+ const unsigned char *cursor;
1580
+ X509_SIG *encrypted = NULL;
1581
+ PKCS8_PRIV_KEY_INFO *p8 = NULL;
1582
+ unsigned char *der = NULL;
1583
+ unsigned char *der_cursor;
1584
+ int der_len;
1585
+ int ret = PQ_ERROR_OPENSSL;
1586
+
1587
+ if (!output || !output_len || !encrypted_der || !passphrase ||
1588
+ passphrase_len > (size_t)INT_MAX || encrypted_der_len > (size_t)LONG_MAX)
1589
+ return PQ_ERROR_BUFFER;
1590
+ *output = NULL;
1591
+ *output_len = 0;
1592
+
1593
+ cursor = encrypted_der;
1594
+ encrypted = d2i_X509_SIG(NULL, &cursor, (long)encrypted_der_len);
1595
+ if (!encrypted || cursor != encrypted_der + encrypted_der_len)
1596
+ goto cleanup;
1597
+ p8 = PKCS8_decrypt(encrypted, passphrase, (int)passphrase_len);
1598
+ if (!p8)
1599
+ goto cleanup;
1600
+
1601
+ der_len = i2d_PKCS8_PRIV_KEY_INFO(p8, NULL);
1602
+ if (der_len <= 0)
1603
+ goto cleanup;
1604
+ der = malloc((size_t)der_len);
1605
+ if (!der) {
1606
+ ret = PQ_ERROR_NOMEM;
1607
+ goto cleanup;
1608
+ }
1609
+ der_cursor = der;
1610
+ if (i2d_PKCS8_PRIV_KEY_INFO(p8, &der_cursor) != der_len ||
1611
+ (size_t)(der_cursor - der) != (size_t)der_len)
1612
+ goto cleanup;
1613
+
1614
+ *output = der;
1615
+ *output_len = (size_t)der_len;
1616
+ der = NULL;
1617
+ ret = PQ_SUCCESS;
1618
+
1619
+ cleanup:
1620
+ if (der) {
1621
+ pq_secure_wipe(der, (size_t)(der_len > 0 ? der_len : 0));
1622
+ free(der);
1623
+ }
1624
+ if (p8)
1625
+ PKCS8_PRIV_KEY_INFO_free(p8);
1626
+ if (encrypted)
1627
+ X509_SIG_free(encrypted);
1628
+ return ret;
1629
+ }
1630
+
1631
+ int pq_pkcs8_der_is_encrypted_private_key_info(const uint8_t *input, size_t input_len) {
1632
+ const unsigned char *cursor;
1633
+ X509_SIG *encrypted = NULL;
1634
+ const X509_ALGOR *alg = NULL;
1635
+ const ASN1_OCTET_STRING *digest = NULL;
1636
+ const ASN1_OBJECT *obj = NULL;
1637
+ int ptype = 0;
1638
+ const void *pval = NULL;
1639
+ int ret = 0;
1640
+
1641
+ if (!input || input_len > (size_t)LONG_MAX)
1642
+ return 0;
1643
+ cursor = input;
1644
+ encrypted = d2i_X509_SIG(NULL, &cursor, (long)input_len);
1645
+ if (!encrypted || cursor != input + input_len)
1646
+ goto cleanup;
1647
+ X509_SIG_get0(encrypted, &alg, &digest);
1648
+ if (!alg || !digest)
1649
+ goto cleanup;
1650
+ X509_ALGOR_get0(&obj, &ptype, &pval, alg);
1651
+ (void)ptype;
1652
+ (void)pval;
1653
+ if (obj && OBJ_obj2nid(obj) == NID_pbes2)
1654
+ ret = 1;
1655
+
1656
+ cleanup:
1657
+ if (encrypted)
1658
+ X509_SIG_free(encrypted);
1659
+ return ret;
1660
+ }
1661
+
1662
+ int pq_pkcs8_der_to_pem(char **output, size_t *output_len, const uint8_t *der, size_t der_len,
1663
+ int encrypted) {
1664
+ return pq_der_to_pem(encrypted ? PQ_PKCS8_ENCRYPTED_PRIVATE_KEY_PEM_LABEL
1665
+ : PQ_PKCS8_PRIVATE_KEY_PEM_LABEL,
1666
+ der, der_len, output, output_len);
1667
+ }
1668
+
1669
+ int pq_pkcs8_pem_to_der(uint8_t **der_out, size_t *der_len_out, int *encrypted_out,
1670
+ const char *input, size_t input_len) {
1671
+ int ret;
1672
+
1673
+ if (!der_out || !der_len_out || !encrypted_out || !input)
1674
+ return PQ_ERROR_BUFFER;
1675
+ *der_out = NULL;
1676
+ *der_len_out = 0;
1677
+ *encrypted_out = 0;
1678
+
1679
+ ret = pq_pem_to_der(PQ_PKCS8_PRIVATE_KEY_PEM_LABEL, input, input_len, der_out, der_len_out);
1680
+ if (ret == PQ_SUCCESS) {
1681
+ *encrypted_out = 0;
1682
+ return PQ_SUCCESS;
1683
+ }
1684
+
1685
+ ret = pq_pem_to_der(PQ_PKCS8_ENCRYPTED_PRIVATE_KEY_PEM_LABEL, input, input_len, der_out,
1686
+ der_len_out);
1687
+ if (ret == PQ_SUCCESS) {
1688
+ *encrypted_out = 1;
1689
+ return PQ_SUCCESS;
1690
+ }
1691
+ return PQ_ERROR_BUFFER;
1692
+ }
1693
+
1162
1694
  const char *pq_version(void) {
1163
1695
  return PQCRYPTO_VERSION;
1164
1696
  }
@@ -132,6 +132,26 @@ int pq_secret_key_from_pqc_container_pem(char **algorithm_out, uint8_t **key_out
132
132
  size_t *key_len_out, const char *input,
133
133
  size_t input_len);
134
134
 
135
+ int pq_pkcs8_private_key_info_to_der(uint8_t **output, size_t *output_len,
136
+ const char *oid_text, const uint8_t *private_key,
137
+ size_t private_key_len);
138
+ int pq_pkcs8_private_key_info_from_der(char **oid_text_out, uint8_t **private_key_out,
139
+ size_t *private_key_len_out, const uint8_t *input,
140
+ size_t input_len);
141
+ int pq_pkcs8_encrypt_private_key_info_der(uint8_t **output, size_t *output_len,
142
+ const uint8_t *plain_der, size_t plain_der_len,
143
+ const char *passphrase, size_t passphrase_len,
144
+ int iterations);
145
+ int pq_pkcs8_decrypt_private_key_info_der(uint8_t **output, size_t *output_len,
146
+ const uint8_t *encrypted_der,
147
+ size_t encrypted_der_len, const char *passphrase,
148
+ size_t passphrase_len);
149
+ int pq_pkcs8_der_is_encrypted_private_key_info(const uint8_t *input, size_t input_len);
150
+ int pq_pkcs8_der_to_pem(char **output, size_t *output_len, const uint8_t *der, size_t der_len,
151
+ int encrypted);
152
+ int pq_pkcs8_pem_to_der(uint8_t **der_out, size_t *der_len_out, int *encrypted_out,
153
+ const char *input, size_t input_len);
154
+
135
155
  int pq_testing_mlkem_keypair_from_seed(uint8_t *public_key, uint8_t *secret_key,
136
156
  const uint8_t *seed, size_t seed_len);
137
157
  int pq_testing_mlkem512_keypair_from_seed(uint8_t *public_key, uint8_t *secret_key,
@@ -2,6 +2,6 @@
2
2
  #ifndef PQCRYPTO_VERSION_H
3
3
  #define PQCRYPTO_VERSION_H
4
4
 
5
- #define PQCRYPTO_VERSION "0.6.0"
5
+ #define PQCRYPTO_VERSION "0.6.1"
6
6
 
7
7
  #endif
@@ -79,7 +79,7 @@ module PQCrypto
79
79
 
80
80
  class SecretKey < KEM::SecretKey
81
81
  def decapsulate(ciphertext)
82
- PQCrypto.__send__(:native_hybrid_kem_decapsulate_expanded_object, String(ciphertext).b, expanded_key_for_native)
82
+ PQCrypto.__send__(:native_hybrid_kem_decapsulate_expanded_object, Internal.binary_string(ciphertext), expanded_key_for_native)
83
83
  rescue ArgumentError => e
84
84
  raise InvalidCiphertextError, e.message
85
85
  end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PQCrypto
4
+ module Internal
5
+ module_function
6
+
7
+ def binary_string(value)
8
+ String(value).b
9
+ end
10
+
11
+ def safe_wipe(value)
12
+ return unless value.is_a?(String) && !value.frozen?
13
+
14
+ PQCrypto.secure_wipe(value)
15
+ rescue ArgumentError
16
+ nil
17
+ end
18
+
19
+ def constant_time_equal?(left, right)
20
+ PQCrypto.__send__(:native_ct_equals, left, right)
21
+ end
22
+ end
23
+ end