pq_crypto 0.5.3 → 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -0
- data/GET_STARTED.md +70 -9
- data/README.md +11 -6
- data/ext/pqcrypto/extconf.rb +2 -0
- data/ext/pqcrypto/pq_externalmu.c +23 -18
- data/ext/pqcrypto/pqcrypto_native_api.h +10 -0
- data/ext/pqcrypto/pqcrypto_ruby_secure.c +351 -48
- data/ext/pqcrypto/pqcrypto_secure.c +615 -84
- data/ext/pqcrypto/pqcrypto_secure.h +35 -10
- data/ext/pqcrypto/pqcrypto_version.h +1 -1
- data/lib/pq_crypto/hybrid_kem.rb +2 -1
- data/lib/pq_crypto/internal.rb +23 -0
- data/lib/pq_crypto/kem.rb +79 -44
- data/lib/pq_crypto/key.rb +90 -0
- data/lib/pq_crypto/pkcs8/der.rb +68 -0
- data/lib/pq_crypto/pkcs8/private_key_choice.rb +186 -0
- data/lib/pq_crypto/pkcs8.rb +61 -304
- data/lib/pq_crypto/serialization.rb +19 -29
- data/lib/pq_crypto/signature.rb +81 -51
- data/lib/pq_crypto/version.rb +1 -1
- data/lib/pq_crypto.rb +16 -4
- metadata +10 -3
|
@@ -81,6 +81,8 @@ typedef struct {
|
|
|
81
81
|
size_t signature_len;
|
|
82
82
|
uint8_t *message;
|
|
83
83
|
size_t message_len;
|
|
84
|
+
uint8_t *context;
|
|
85
|
+
size_t context_len;
|
|
84
86
|
const uint8_t *secret_key;
|
|
85
87
|
const uint8_t *seed;
|
|
86
88
|
size_t seed_len;
|
|
@@ -92,6 +94,8 @@ typedef struct {
|
|
|
92
94
|
size_t signature_len;
|
|
93
95
|
uint8_t *message;
|
|
94
96
|
size_t message_len;
|
|
97
|
+
uint8_t *context;
|
|
98
|
+
size_t context_len;
|
|
95
99
|
const uint8_t *public_key;
|
|
96
100
|
} verify_call_t;
|
|
97
101
|
|
|
@@ -153,6 +157,52 @@ static const char *const PQC_CONTAINER_ALGORITHMS[] = {
|
|
|
153
157
|
static ID pqc_container_algorithm_ids[sizeof(PQC_CONTAINER_ALGORITHMS) /
|
|
154
158
|
sizeof(PQC_CONTAINER_ALGORITHMS[0])];
|
|
155
159
|
|
|
160
|
+
typedef int (*pq_mldsa_pk_from_sk_fn)(uint8_t *, const uint8_t *);
|
|
161
|
+
typedef int (*pq_mldsa_signature_extmu_fn)(uint8_t *, size_t *, const uint8_t *, const uint8_t *);
|
|
162
|
+
typedef int (*pq_mldsa_verify_extmu_fn)(const uint8_t *, size_t, const uint8_t *, const uint8_t *);
|
|
163
|
+
|
|
164
|
+
typedef struct {
|
|
165
|
+
const char *name;
|
|
166
|
+
size_t public_key_len;
|
|
167
|
+
size_t secret_key_len;
|
|
168
|
+
size_t signature_len;
|
|
169
|
+
pq_mldsa_pk_from_sk_fn pk_from_sk;
|
|
170
|
+
pq_mldsa_signature_extmu_fn signature_extmu;
|
|
171
|
+
pq_mldsa_verify_extmu_fn verify_extmu;
|
|
172
|
+
} pq_mldsa_profile_t;
|
|
173
|
+
|
|
174
|
+
static const pq_mldsa_profile_t MLDSA_PROFILES[] = {
|
|
175
|
+
{"ml_dsa_44", MLDSA44_PUBLICKEYBYTES, MLDSA44_SECRETKEYBYTES, MLDSA44_BYTES,
|
|
176
|
+
pqcr_mldsa44_pk_from_sk, pqcr_mldsa44_signature_extmu, pqcr_mldsa44_verify_extmu},
|
|
177
|
+
{"ml_dsa_65", MLDSA65_PUBLICKEYBYTES, MLDSA65_SECRETKEYBYTES, MLDSA65_BYTES,
|
|
178
|
+
pqcr_mldsa65_pk_from_sk, pqcr_mldsa65_signature_extmu, pqcr_mldsa65_verify_extmu},
|
|
179
|
+
{"ml_dsa_87", MLDSA87_PUBLICKEYBYTES, MLDSA87_SECRETKEYBYTES, MLDSA87_BYTES,
|
|
180
|
+
pqcr_mldsa87_pk_from_sk, pqcr_mldsa87_signature_extmu, pqcr_mldsa87_verify_extmu},
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
static const pq_mldsa_profile_t *pq_mldsa_profile_from_value(VALUE algorithm) {
|
|
184
|
+
ID id;
|
|
185
|
+
const char *name;
|
|
186
|
+
|
|
187
|
+
if (!SYMBOL_P(algorithm)) {
|
|
188
|
+
rb_raise(rb_eArgError, "ML-DSA algorithm must be a Symbol");
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
id = SYM2ID(algorithm);
|
|
192
|
+
name = rb_id2name(id);
|
|
193
|
+
if (!name) {
|
|
194
|
+
rb_raise(rb_eArgError, "Invalid ML-DSA algorithm symbol");
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
for (size_t i = 0; i < sizeof(MLDSA_PROFILES) / sizeof(MLDSA_PROFILES[0]); ++i) {
|
|
198
|
+
if (strcmp(name, MLDSA_PROFILES[i].name) == 0) {
|
|
199
|
+
return &MLDSA_PROFILES[i];
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
rb_raise(ePQCryptoError, "Unsupported ML-DSA algorithm: %s", name);
|
|
204
|
+
}
|
|
205
|
+
|
|
156
206
|
static void pq_init_algorithm_ids(void) {
|
|
157
207
|
for (size_t i = 0; i < sizeof(PQC_CONTAINER_ALGORITHMS) / sizeof(PQC_CONTAINER_ALGORITHMS[0]);
|
|
158
208
|
++i) {
|
|
@@ -320,12 +370,13 @@ PQ_DEFINE_SIGN_KEYPAIR_FROM_SEED_NOGVL(mldsa_87_keypair_from_seed, pq_mldsa87_ke
|
|
|
320
370
|
|
|
321
371
|
#undef PQ_DEFINE_SIGN_KEYPAIR_FROM_SEED_NOGVL
|
|
322
372
|
|
|
323
|
-
#define PQ_DEFINE_SIGN_NOGVL(rb_name, c_call)
|
|
324
|
-
static void *pq_##rb_name##_nogvl(void *arg) {
|
|
325
|
-
sign_call_t *call = (sign_call_t *)arg;
|
|
326
|
-
call->result =
|
|
327
|
-
|
|
328
|
-
|
|
373
|
+
#define PQ_DEFINE_SIGN_NOGVL(rb_name, c_call) \
|
|
374
|
+
static void *pq_##rb_name##_nogvl(void *arg) { \
|
|
375
|
+
sign_call_t *call = (sign_call_t *)arg; \
|
|
376
|
+
call->result = \
|
|
377
|
+
c_call(call->signature, &call->signature_len, call->message, call->message_len, \
|
|
378
|
+
call->context, call->context_len, call->secret_key); \
|
|
379
|
+
return NULL; \
|
|
329
380
|
}
|
|
330
381
|
|
|
331
382
|
PQ_DEFINE_SIGN_NOGVL(sign, pq_sign)
|
|
@@ -373,12 +424,13 @@ PQ_DEFINE_TESTING_SIGN_FROM_SEED(mldsa_87, pq_testing_mldsa87_sign_from_seed)
|
|
|
373
424
|
#undef PQ_DEFINE_TESTING_KEYPAIR_FROM_SEED
|
|
374
425
|
#undef PQ_DEFINE_TESTING_SIGN_FROM_SEED
|
|
375
426
|
|
|
376
|
-
#define PQ_DEFINE_VERIFY_NOGVL(rb_name, c_call)
|
|
377
|
-
static void *pq_##rb_name##_nogvl(void *arg) {
|
|
378
|
-
verify_call_t *call = (verify_call_t *)arg;
|
|
379
|
-
call->result =
|
|
380
|
-
|
|
381
|
-
|
|
427
|
+
#define PQ_DEFINE_VERIFY_NOGVL(rb_name, c_call) \
|
|
428
|
+
static void *pq_##rb_name##_nogvl(void *arg) { \
|
|
429
|
+
verify_call_t *call = (verify_call_t *)arg; \
|
|
430
|
+
call->result = \
|
|
431
|
+
c_call(call->signature, call->signature_len, call->message, call->message_len, \
|
|
432
|
+
call->context, call->context_len, call->public_key); \
|
|
433
|
+
return NULL; \
|
|
382
434
|
}
|
|
383
435
|
|
|
384
436
|
PQ_DEFINE_VERIFY_NOGVL(verify, pq_verify)
|
|
@@ -812,6 +864,26 @@ static VALUE pqcrypto_hybrid_kem_expand_secret_key_object(VALUE self, VALUE secr
|
|
|
812
864
|
return obj;
|
|
813
865
|
}
|
|
814
866
|
|
|
867
|
+
static VALUE pqcrypto_hybrid_kem_expanded_secret_key_wipe(VALUE self,
|
|
868
|
+
VALUE expanded_secret_key_obj) {
|
|
869
|
+
(void)self;
|
|
870
|
+
hybrid_expanded_key_wrapper_t *wrapper;
|
|
871
|
+
|
|
872
|
+
TypedData_Get_Struct(expanded_secret_key_obj, hybrid_expanded_key_wrapper_t,
|
|
873
|
+
&hybrid_expanded_key_data_type, wrapper);
|
|
874
|
+
if (!wrapper) {
|
|
875
|
+
return Qnil;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
pq_secure_wipe(wrapper->expanded_secret_key, sizeof(wrapper->expanded_secret_key));
|
|
879
|
+
if (wrapper->x25519_private_pkey) {
|
|
880
|
+
EVP_PKEY_free(wrapper->x25519_private_pkey);
|
|
881
|
+
wrapper->x25519_private_pkey = NULL;
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
return Qnil;
|
|
885
|
+
}
|
|
886
|
+
|
|
815
887
|
static VALUE pqcrypto_hybrid_kem_decapsulate(VALUE self, VALUE ciphertext, VALUE secret_key) {
|
|
816
888
|
(void)self;
|
|
817
889
|
return pq_run_kem_decapsulate(pq_hybrid_kem_decapsulate_nogvl, ciphertext,
|
|
@@ -1181,20 +1253,28 @@ PQ_DEFINE_RUBY_MLDSA_KEYPAIR(ml_dsa_87_keypair, mldsa_87_sign_keypair, MLDSA87_P
|
|
|
1181
1253
|
|
|
1182
1254
|
#undef PQ_DEFINE_RUBY_MLDSA_KEYPAIR
|
|
1183
1255
|
|
|
1184
|
-
static VALUE pq_run_sign(void *(*nogvl)(void *), VALUE message, VALUE secret_key,
|
|
1256
|
+
static VALUE pq_run_sign(void *(*nogvl)(void *), VALUE message, VALUE secret_key, VALUE context,
|
|
1185
1257
|
size_t secret_key_len_expected, size_t signature_len_expected) {
|
|
1186
1258
|
pq_validate_bytes_argument(secret_key, secret_key_len_expected, "secret key");
|
|
1259
|
+
StringValue(context);
|
|
1260
|
+
if (RSTRING_LEN(context) > 255) {
|
|
1261
|
+
rb_raise(rb_eArgError, "ML-DSA context length must be <= 255 bytes");
|
|
1262
|
+
}
|
|
1187
1263
|
|
|
1188
1264
|
sign_call_t call = {0};
|
|
1189
1265
|
size_t secret_key_len = 0;
|
|
1266
|
+
size_t context_len = 0;
|
|
1190
1267
|
call.secret_key = pq_copy_ruby_string(secret_key, &secret_key_len);
|
|
1191
1268
|
call.signature_len = signature_len_expected;
|
|
1192
1269
|
call.signature = pq_alloc_buffer(signature_len_expected);
|
|
1193
1270
|
call.message = pq_copy_ruby_string(message, &call.message_len);
|
|
1271
|
+
call.context = pq_copy_ruby_string(context, &context_len);
|
|
1272
|
+
call.context_len = context_len;
|
|
1194
1273
|
|
|
1195
1274
|
rb_nogvl(nogvl, &call, NULL, NULL, PQ_RB_NOGVL_OFFLOAD_SAFE);
|
|
1196
1275
|
|
|
1197
1276
|
pq_free_buffer(call.message);
|
|
1277
|
+
pq_free_buffer(call.context);
|
|
1198
1278
|
pq_wipe_and_free((uint8_t *)call.secret_key, secret_key_len);
|
|
1199
1279
|
|
|
1200
1280
|
if (call.result != PQ_SUCCESS) {
|
|
@@ -1207,10 +1287,16 @@ static VALUE pq_run_sign(void *(*nogvl)(void *), VALUE message, VALUE secret_key
|
|
|
1207
1287
|
return result;
|
|
1208
1288
|
}
|
|
1209
1289
|
|
|
1210
|
-
#define PQ_DEFINE_RUBY_MLDSA_SIGN(rb_name, nogvl_stem, sk_bytes, sig_bytes)
|
|
1211
|
-
static VALUE pqcrypto_##rb_name(
|
|
1212
|
-
(void)self;
|
|
1213
|
-
|
|
1290
|
+
#define PQ_DEFINE_RUBY_MLDSA_SIGN(rb_name, nogvl_stem, sk_bytes, sig_bytes) \
|
|
1291
|
+
static VALUE pqcrypto_##rb_name(int argc, VALUE *argv, VALUE self) { \
|
|
1292
|
+
(void)self; \
|
|
1293
|
+
VALUE message, secret_key, context; \
|
|
1294
|
+
rb_scan_args(argc, argv, "21", &message, &secret_key, &context); \
|
|
1295
|
+
if (NIL_P(context)) { \
|
|
1296
|
+
context = rb_str_new("", 0); \
|
|
1297
|
+
} \
|
|
1298
|
+
return pq_run_sign(pq_##nogvl_stem##_nogvl, message, secret_key, context, sk_bytes, \
|
|
1299
|
+
sig_bytes); \
|
|
1214
1300
|
}
|
|
1215
1301
|
|
|
1216
1302
|
PQ_DEFINE_RUBY_MLDSA_SIGN(sign, sign, PQ_MLDSA_SECRETKEYBYTES, PQ_MLDSA_BYTES)
|
|
@@ -1220,21 +1306,29 @@ PQ_DEFINE_RUBY_MLDSA_SIGN(ml_dsa_87_sign, mldsa_87_sign, MLDSA87_SECRETKEYBYTES,
|
|
|
1220
1306
|
#undef PQ_DEFINE_RUBY_MLDSA_SIGN
|
|
1221
1307
|
|
|
1222
1308
|
static VALUE pq_run_verify(void *(*nogvl)(void *), VALUE message, VALUE signature, VALUE public_key,
|
|
1223
|
-
size_t public_key_len_expected) {
|
|
1309
|
+
VALUE context, size_t public_key_len_expected) {
|
|
1224
1310
|
StringValue(signature);
|
|
1225
1311
|
pq_validate_bytes_argument(public_key, public_key_len_expected, "public key");
|
|
1312
|
+
StringValue(context);
|
|
1313
|
+
if (RSTRING_LEN(context) > 255) {
|
|
1314
|
+
rb_raise(rb_eArgError, "ML-DSA context length must be <= 255 bytes");
|
|
1315
|
+
}
|
|
1226
1316
|
|
|
1227
1317
|
verify_call_t call = {0};
|
|
1228
1318
|
size_t public_key_len = 0;
|
|
1229
1319
|
size_t signature_len = 0;
|
|
1320
|
+
size_t context_len = 0;
|
|
1230
1321
|
call.public_key = pq_copy_ruby_string(public_key, &public_key_len);
|
|
1231
1322
|
call.signature = pq_copy_ruby_string(signature, &signature_len);
|
|
1232
1323
|
call.signature_len = signature_len;
|
|
1233
1324
|
call.message = pq_copy_ruby_string(message, &call.message_len);
|
|
1325
|
+
call.context = pq_copy_ruby_string(context, &context_len);
|
|
1326
|
+
call.context_len = context_len;
|
|
1234
1327
|
|
|
1235
1328
|
rb_nogvl(nogvl, &call, NULL, NULL, PQ_RB_NOGVL_OFFLOAD_SAFE);
|
|
1236
1329
|
|
|
1237
1330
|
pq_free_buffer(call.message);
|
|
1331
|
+
pq_free_buffer(call.context);
|
|
1238
1332
|
pq_free_buffer((uint8_t *)call.public_key);
|
|
1239
1333
|
pq_free_buffer((uint8_t *)call.signature);
|
|
1240
1334
|
|
|
@@ -1247,11 +1341,16 @@ static VALUE pq_run_verify(void *(*nogvl)(void *), VALUE message, VALUE signatur
|
|
|
1247
1341
|
pq_raise_general_error(call.result);
|
|
1248
1342
|
}
|
|
1249
1343
|
|
|
1250
|
-
#define PQ_DEFINE_RUBY_MLDSA_VERIFY(rb_name, nogvl_stem, pk_bytes)
|
|
1251
|
-
static VALUE pqcrypto_##rb_name(
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1344
|
+
#define PQ_DEFINE_RUBY_MLDSA_VERIFY(rb_name, nogvl_stem, pk_bytes) \
|
|
1345
|
+
static VALUE pqcrypto_##rb_name(int argc, VALUE *argv, VALUE self) { \
|
|
1346
|
+
(void)self; \
|
|
1347
|
+
VALUE message, signature, public_key, context; \
|
|
1348
|
+
rb_scan_args(argc, argv, "31", &message, &signature, &public_key, &context); \
|
|
1349
|
+
if (NIL_P(context)) { \
|
|
1350
|
+
context = rb_str_new("", 0); \
|
|
1351
|
+
} \
|
|
1352
|
+
return pq_run_verify(pq_##nogvl_stem##_nogvl, message, signature, public_key, context, \
|
|
1353
|
+
pk_bytes); \
|
|
1255
1354
|
}
|
|
1256
1355
|
|
|
1257
1356
|
PQ_DEFINE_RUBY_MLDSA_VERIFY(verify, verify, PQ_MLDSA_PUBLICKEYBYTES)
|
|
@@ -1312,6 +1411,7 @@ typedef struct {
|
|
|
1312
1411
|
size_t signature_len;
|
|
1313
1412
|
const uint8_t *mu;
|
|
1314
1413
|
const uint8_t *secret_key;
|
|
1414
|
+
pq_mldsa_signature_extmu_fn signature_extmu;
|
|
1315
1415
|
} sign_mu_call_t;
|
|
1316
1416
|
|
|
1317
1417
|
typedef struct {
|
|
@@ -1320,6 +1420,8 @@ typedef struct {
|
|
|
1320
1420
|
size_t signature_len;
|
|
1321
1421
|
const uint8_t *mu;
|
|
1322
1422
|
const uint8_t *public_key;
|
|
1423
|
+
size_t expected_signature_len;
|
|
1424
|
+
pq_mldsa_verify_extmu_fn verify_extmu;
|
|
1323
1425
|
} verify_mu_call_t;
|
|
1324
1426
|
|
|
1325
1427
|
static void mu_builder_wrapper_free(void *ptr) {
|
|
@@ -1363,12 +1465,25 @@ static mu_builder_wrapper_t *mu_builder_unwrap(VALUE obj) {
|
|
|
1363
1465
|
return wrapper;
|
|
1364
1466
|
}
|
|
1365
1467
|
|
|
1366
|
-
static VALUE pqcrypto__native_mldsa_extract_tr(VALUE
|
|
1468
|
+
static VALUE pqcrypto__native_mldsa_extract_tr(int argc, VALUE *argv, VALUE self) {
|
|
1367
1469
|
(void)self;
|
|
1368
|
-
|
|
1470
|
+
VALUE algorithm = ID2SYM(rb_intern("ml_dsa_65"));
|
|
1471
|
+
VALUE secret_key;
|
|
1472
|
+
if (argc == 1) {
|
|
1473
|
+
secret_key = argv[0];
|
|
1474
|
+
} else if (argc == 2) {
|
|
1475
|
+
algorithm = argv[0];
|
|
1476
|
+
secret_key = argv[1];
|
|
1477
|
+
} else {
|
|
1478
|
+
rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 1..2)", argc);
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
const pq_mldsa_profile_t *profile = pq_mldsa_profile_from_value(algorithm);
|
|
1482
|
+
pq_validate_bytes_argument(secret_key, profile->secret_key_len, "secret key");
|
|
1369
1483
|
|
|
1370
1484
|
uint8_t tr[PQ_MLDSA_TRBYTES];
|
|
1371
|
-
int rc = pq_mldsa_extract_tr_from_secret_key(tr, (const uint8_t *)RSTRING_PTR(secret_key)
|
|
1485
|
+
int rc = pq_mldsa_extract_tr_from_secret_key(tr, (const uint8_t *)RSTRING_PTR(secret_key),
|
|
1486
|
+
profile->public_key_len, profile->pk_from_sk);
|
|
1372
1487
|
if (rc != PQ_SUCCESS) {
|
|
1373
1488
|
pq_secure_wipe(tr, sizeof(tr));
|
|
1374
1489
|
pq_raise_general_error(rc);
|
|
@@ -1378,12 +1493,25 @@ static VALUE pqcrypto__native_mldsa_extract_tr(VALUE self, VALUE secret_key) {
|
|
|
1378
1493
|
return result;
|
|
1379
1494
|
}
|
|
1380
1495
|
|
|
1381
|
-
static VALUE pqcrypto__native_mldsa_compute_tr(VALUE
|
|
1496
|
+
static VALUE pqcrypto__native_mldsa_compute_tr(int argc, VALUE *argv, VALUE self) {
|
|
1382
1497
|
(void)self;
|
|
1383
|
-
|
|
1498
|
+
VALUE algorithm = ID2SYM(rb_intern("ml_dsa_65"));
|
|
1499
|
+
VALUE public_key;
|
|
1500
|
+
if (argc == 1) {
|
|
1501
|
+
public_key = argv[0];
|
|
1502
|
+
} else if (argc == 2) {
|
|
1503
|
+
algorithm = argv[0];
|
|
1504
|
+
public_key = argv[1];
|
|
1505
|
+
} else {
|
|
1506
|
+
rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 1..2)", argc);
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1509
|
+
const pq_mldsa_profile_t *profile = pq_mldsa_profile_from_value(algorithm);
|
|
1510
|
+
pq_validate_bytes_argument(public_key, profile->public_key_len, "public key");
|
|
1384
1511
|
|
|
1385
1512
|
uint8_t tr[PQ_MLDSA_TRBYTES];
|
|
1386
|
-
int rc = pq_mldsa_compute_tr_from_public_key(tr, (const uint8_t *)RSTRING_PTR(public_key)
|
|
1513
|
+
int rc = pq_mldsa_compute_tr_from_public_key(tr, (const uint8_t *)RSTRING_PTR(public_key),
|
|
1514
|
+
profile->public_key_len);
|
|
1387
1515
|
if (rc != PQ_SUCCESS) {
|
|
1388
1516
|
pq_raise_general_error(rc);
|
|
1389
1517
|
}
|
|
@@ -1504,14 +1632,29 @@ static VALUE pqcrypto__native_mldsa_mu_builder_release(VALUE self, VALUE builder
|
|
|
1504
1632
|
|
|
1505
1633
|
static void *pq_sign_mu_nogvl(void *arg) {
|
|
1506
1634
|
sign_mu_call_t *call = (sign_mu_call_t *)arg;
|
|
1507
|
-
call->result = pq_sign_mu(call->signature, &call->signature_len, call->mu, call->secret_key
|
|
1635
|
+
call->result = pq_sign_mu(call->signature, &call->signature_len, call->mu, call->secret_key,
|
|
1636
|
+
call->signature_extmu);
|
|
1508
1637
|
return NULL;
|
|
1509
1638
|
}
|
|
1510
1639
|
|
|
1511
|
-
static VALUE pqcrypto__native_mldsa_sign_mu(
|
|
1640
|
+
static VALUE pqcrypto__native_mldsa_sign_mu(int argc, VALUE *argv, VALUE self) {
|
|
1512
1641
|
(void)self;
|
|
1642
|
+
VALUE algorithm = ID2SYM(rb_intern("ml_dsa_65"));
|
|
1643
|
+
VALUE mu, secret_key;
|
|
1644
|
+
if (argc == 2) {
|
|
1645
|
+
mu = argv[0];
|
|
1646
|
+
secret_key = argv[1];
|
|
1647
|
+
} else if (argc == 3) {
|
|
1648
|
+
algorithm = argv[0];
|
|
1649
|
+
mu = argv[1];
|
|
1650
|
+
secret_key = argv[2];
|
|
1651
|
+
} else {
|
|
1652
|
+
rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 2..3)", argc);
|
|
1653
|
+
}
|
|
1654
|
+
|
|
1655
|
+
const pq_mldsa_profile_t *profile = pq_mldsa_profile_from_value(algorithm);
|
|
1513
1656
|
pq_validate_bytes_argument(mu, PQ_MLDSA_MUBYTES, "mu");
|
|
1514
|
-
pq_validate_bytes_argument(secret_key,
|
|
1657
|
+
pq_validate_bytes_argument(secret_key, profile->secret_key_len, "secret key");
|
|
1515
1658
|
|
|
1516
1659
|
sign_mu_call_t call = {0};
|
|
1517
1660
|
size_t secret_key_len = 0;
|
|
@@ -1521,8 +1664,9 @@ static VALUE pqcrypto__native_mldsa_sign_mu(VALUE self, VALUE mu, VALUE secret_k
|
|
|
1521
1664
|
|
|
1522
1665
|
call.mu = mu_copy;
|
|
1523
1666
|
call.secret_key = sk_copy;
|
|
1524
|
-
call.
|
|
1525
|
-
call.
|
|
1667
|
+
call.signature_extmu = profile->signature_extmu;
|
|
1668
|
+
call.signature_len = profile->signature_len;
|
|
1669
|
+
call.signature = pq_alloc_buffer(profile->signature_len);
|
|
1526
1670
|
|
|
1527
1671
|
rb_nogvl(pq_sign_mu_nogvl, &call, NULL, NULL, PQ_RB_NOGVL_OFFLOAD_SAFE);
|
|
1528
1672
|
|
|
@@ -1541,16 +1685,32 @@ static VALUE pqcrypto__native_mldsa_sign_mu(VALUE self, VALUE mu, VALUE secret_k
|
|
|
1541
1685
|
|
|
1542
1686
|
static void *pq_verify_mu_nogvl(void *arg) {
|
|
1543
1687
|
verify_mu_call_t *call = (verify_mu_call_t *)arg;
|
|
1544
|
-
call->result = pq_verify_mu(call->signature, call->signature_len, call->mu, call->public_key
|
|
1688
|
+
call->result = pq_verify_mu(call->signature, call->signature_len, call->mu, call->public_key,
|
|
1689
|
+
call->expected_signature_len, call->verify_extmu);
|
|
1545
1690
|
return NULL;
|
|
1546
1691
|
}
|
|
1547
1692
|
|
|
1548
|
-
static VALUE pqcrypto__native_mldsa_verify_mu(
|
|
1549
|
-
VALUE public_key) {
|
|
1693
|
+
static VALUE pqcrypto__native_mldsa_verify_mu(int argc, VALUE *argv, VALUE self) {
|
|
1550
1694
|
(void)self;
|
|
1695
|
+
VALUE algorithm = ID2SYM(rb_intern("ml_dsa_65"));
|
|
1696
|
+
VALUE mu, signature, public_key;
|
|
1697
|
+
if (argc == 3) {
|
|
1698
|
+
mu = argv[0];
|
|
1699
|
+
signature = argv[1];
|
|
1700
|
+
public_key = argv[2];
|
|
1701
|
+
} else if (argc == 4) {
|
|
1702
|
+
algorithm = argv[0];
|
|
1703
|
+
mu = argv[1];
|
|
1704
|
+
signature = argv[2];
|
|
1705
|
+
public_key = argv[3];
|
|
1706
|
+
} else {
|
|
1707
|
+
rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 3..4)", argc);
|
|
1708
|
+
}
|
|
1709
|
+
|
|
1710
|
+
const pq_mldsa_profile_t *profile = pq_mldsa_profile_from_value(algorithm);
|
|
1551
1711
|
StringValue(signature);
|
|
1552
1712
|
pq_validate_bytes_argument(mu, PQ_MLDSA_MUBYTES, "mu");
|
|
1553
|
-
pq_validate_bytes_argument(public_key,
|
|
1713
|
+
pq_validate_bytes_argument(public_key, profile->public_key_len, "public key");
|
|
1554
1714
|
|
|
1555
1715
|
verify_mu_call_t call = {0};
|
|
1556
1716
|
size_t public_key_len = 0;
|
|
@@ -1564,6 +1724,8 @@ static VALUE pqcrypto__native_mldsa_verify_mu(VALUE self, VALUE mu, VALUE signat
|
|
|
1564
1724
|
call.public_key = pk_copy;
|
|
1565
1725
|
call.signature = sig_copy;
|
|
1566
1726
|
call.signature_len = signature_len;
|
|
1727
|
+
call.expected_signature_len = profile->signature_len;
|
|
1728
|
+
call.verify_extmu = profile->verify_extmu;
|
|
1567
1729
|
|
|
1568
1730
|
rb_nogvl(pq_verify_mu_nogvl, &call, NULL, NULL, PQ_RB_NOGVL_OFFLOAD_SAFE);
|
|
1569
1731
|
pq_wipe_and_free(mu_copy, mu_len);
|
|
@@ -1579,6 +1741,136 @@ static VALUE pqcrypto__native_mldsa_verify_mu(VALUE self, VALUE mu, VALUE signat
|
|
|
1579
1741
|
pq_raise_general_error(call.result);
|
|
1580
1742
|
}
|
|
1581
1743
|
|
|
1744
|
+
static VALUE pqcrypto_pkcs8_private_key_info_to_der(VALUE self, VALUE oid_text, VALUE private_key) {
|
|
1745
|
+
(void)self;
|
|
1746
|
+
uint8_t *out = NULL;
|
|
1747
|
+
size_t out_len = 0;
|
|
1748
|
+
VALUE result;
|
|
1749
|
+
int ret;
|
|
1750
|
+
|
|
1751
|
+
StringValue(oid_text);
|
|
1752
|
+
StringValue(private_key);
|
|
1753
|
+
ret = pq_pkcs8_private_key_info_to_der(&out, &out_len, RSTRING_PTR(oid_text),
|
|
1754
|
+
(const uint8_t *)RSTRING_PTR(private_key),
|
|
1755
|
+
(size_t)RSTRING_LEN(private_key));
|
|
1756
|
+
if (ret != PQ_SUCCESS)
|
|
1757
|
+
pq_raise_general_error(ret);
|
|
1758
|
+
result = pq_string_from_buffer(out, out_len);
|
|
1759
|
+
pq_wipe_and_free(out, out_len);
|
|
1760
|
+
return result;
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
static VALUE pqcrypto_pkcs8_private_key_info_from_der(VALUE self, VALUE der) {
|
|
1764
|
+
(void)self;
|
|
1765
|
+
char *oid_text = NULL;
|
|
1766
|
+
uint8_t *private_key = NULL;
|
|
1767
|
+
size_t private_key_len = 0;
|
|
1768
|
+
VALUE result;
|
|
1769
|
+
int ret;
|
|
1770
|
+
|
|
1771
|
+
StringValue(der);
|
|
1772
|
+
ret = pq_pkcs8_private_key_info_from_der(&oid_text, &private_key, &private_key_len,
|
|
1773
|
+
(const uint8_t *)RSTRING_PTR(der),
|
|
1774
|
+
(size_t)RSTRING_LEN(der));
|
|
1775
|
+
if (ret != PQ_SUCCESS)
|
|
1776
|
+
pq_raise_general_error(ret);
|
|
1777
|
+
|
|
1778
|
+
result = rb_ary_new_capa(2);
|
|
1779
|
+
rb_ary_push(result, rb_str_new_cstr(oid_text));
|
|
1780
|
+
rb_ary_push(result, pq_string_from_buffer(private_key, private_key_len));
|
|
1781
|
+
free(oid_text);
|
|
1782
|
+
pq_wipe_and_free(private_key, private_key_len);
|
|
1783
|
+
return result;
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1786
|
+
static VALUE pqcrypto_pkcs8_encrypt_der(VALUE self, VALUE der, VALUE passphrase,
|
|
1787
|
+
VALUE iterations_value) {
|
|
1788
|
+
(void)self;
|
|
1789
|
+
uint8_t *out = NULL;
|
|
1790
|
+
size_t out_len = 0;
|
|
1791
|
+
int iterations;
|
|
1792
|
+
VALUE result;
|
|
1793
|
+
int ret;
|
|
1794
|
+
|
|
1795
|
+
StringValue(der);
|
|
1796
|
+
StringValue(passphrase);
|
|
1797
|
+
iterations = NUM2INT(iterations_value);
|
|
1798
|
+
ret = pq_pkcs8_encrypt_private_key_info_der(&out, &out_len, (const uint8_t *)RSTRING_PTR(der),
|
|
1799
|
+
(size_t)RSTRING_LEN(der), RSTRING_PTR(passphrase),
|
|
1800
|
+
(size_t)RSTRING_LEN(passphrase), iterations);
|
|
1801
|
+
if (ret != PQ_SUCCESS)
|
|
1802
|
+
pq_raise_general_error(ret);
|
|
1803
|
+
result = pq_string_from_buffer(out, out_len);
|
|
1804
|
+
pq_wipe_and_free(out, out_len);
|
|
1805
|
+
return result;
|
|
1806
|
+
}
|
|
1807
|
+
|
|
1808
|
+
static VALUE pqcrypto_pkcs8_decrypt_der(VALUE self, VALUE der, VALUE passphrase) {
|
|
1809
|
+
(void)self;
|
|
1810
|
+
uint8_t *out = NULL;
|
|
1811
|
+
size_t out_len = 0;
|
|
1812
|
+
VALUE result;
|
|
1813
|
+
int ret;
|
|
1814
|
+
|
|
1815
|
+
StringValue(der);
|
|
1816
|
+
StringValue(passphrase);
|
|
1817
|
+
ret = pq_pkcs8_decrypt_private_key_info_der(&out, &out_len, (const uint8_t *)RSTRING_PTR(der),
|
|
1818
|
+
(size_t)RSTRING_LEN(der), RSTRING_PTR(passphrase),
|
|
1819
|
+
(size_t)RSTRING_LEN(passphrase));
|
|
1820
|
+
if (ret != PQ_SUCCESS)
|
|
1821
|
+
pq_raise_general_error(ret);
|
|
1822
|
+
result = pq_string_from_buffer(out, out_len);
|
|
1823
|
+
pq_wipe_and_free(out, out_len);
|
|
1824
|
+
return result;
|
|
1825
|
+
}
|
|
1826
|
+
|
|
1827
|
+
static VALUE pqcrypto_pkcs8_encrypted_der_p(VALUE self, VALUE der) {
|
|
1828
|
+
(void)self;
|
|
1829
|
+
StringValue(der);
|
|
1830
|
+
return pq_pkcs8_der_is_encrypted_private_key_info((const uint8_t *)RSTRING_PTR(der),
|
|
1831
|
+
(size_t)RSTRING_LEN(der))
|
|
1832
|
+
? Qtrue
|
|
1833
|
+
: Qfalse;
|
|
1834
|
+
}
|
|
1835
|
+
|
|
1836
|
+
static VALUE pqcrypto_pkcs8_der_to_pem(VALUE self, VALUE der, VALUE encrypted_value) {
|
|
1837
|
+
(void)self;
|
|
1838
|
+
char *pem = NULL;
|
|
1839
|
+
size_t pem_len = 0;
|
|
1840
|
+
VALUE result;
|
|
1841
|
+
int ret;
|
|
1842
|
+
|
|
1843
|
+
StringValue(der);
|
|
1844
|
+
ret = pq_pkcs8_der_to_pem(&pem, &pem_len, (const uint8_t *)RSTRING_PTR(der),
|
|
1845
|
+
(size_t)RSTRING_LEN(der), RTEST(encrypted_value) ? 1 : 0);
|
|
1846
|
+
if (ret != PQ_SUCCESS)
|
|
1847
|
+
pq_raise_general_error(ret);
|
|
1848
|
+
result = rb_str_new(pem, (long)pem_len);
|
|
1849
|
+
pq_secure_wipe(pem, pem_len);
|
|
1850
|
+
free(pem);
|
|
1851
|
+
return result;
|
|
1852
|
+
}
|
|
1853
|
+
|
|
1854
|
+
static VALUE pqcrypto_pkcs8_pem_to_der(VALUE self, VALUE pem) {
|
|
1855
|
+
(void)self;
|
|
1856
|
+
uint8_t *der = NULL;
|
|
1857
|
+
size_t der_len = 0;
|
|
1858
|
+
int encrypted = 0;
|
|
1859
|
+
VALUE result;
|
|
1860
|
+
int ret;
|
|
1861
|
+
|
|
1862
|
+
StringValue(pem);
|
|
1863
|
+
ret =
|
|
1864
|
+
pq_pkcs8_pem_to_der(&der, &der_len, &encrypted, RSTRING_PTR(pem), (size_t)RSTRING_LEN(pem));
|
|
1865
|
+
if (ret != PQ_SUCCESS)
|
|
1866
|
+
pq_raise_general_error(ret);
|
|
1867
|
+
result = rb_ary_new_capa(2);
|
|
1868
|
+
rb_ary_push(result, encrypted ? Qtrue : Qfalse);
|
|
1869
|
+
rb_ary_push(result, pq_string_from_buffer(der, der_len));
|
|
1870
|
+
pq_wipe_and_free(der, der_len);
|
|
1871
|
+
return result;
|
|
1872
|
+
}
|
|
1873
|
+
|
|
1582
1874
|
static void define_constants(void) {
|
|
1583
1875
|
rb_define_const(mPQCrypto, "ML_KEM_512_PUBLIC_KEY_BYTES", INT2NUM(MLKEM512_PUBLICKEYBYTES));
|
|
1584
1876
|
rb_define_const(mPQCrypto, "ML_KEM_512_SECRET_KEY_BYTES", INT2NUM(MLKEM512_SECRETKEYBYTES));
|
|
@@ -1707,6 +1999,8 @@ void Init_pqcrypto_secure(void) {
|
|
|
1707
1999
|
pqcrypto_hybrid_kem_expand_secret_key, 1);
|
|
1708
2000
|
rb_define_module_function(mPQCrypto, "hybrid_kem_expand_secret_key_object",
|
|
1709
2001
|
pqcrypto_hybrid_kem_expand_secret_key_object, 1);
|
|
2002
|
+
rb_define_module_function(mPQCrypto, "hybrid_kem_expanded_secret_key_wipe",
|
|
2003
|
+
pqcrypto_hybrid_kem_expanded_secret_key_wipe, 1);
|
|
1710
2004
|
rb_define_module_function(mPQCrypto, "hybrid_kem_decapsulate", pqcrypto_hybrid_kem_decapsulate,
|
|
1711
2005
|
2);
|
|
1712
2006
|
rb_define_module_function(mPQCrypto, "hybrid_kem_decapsulate_expanded",
|
|
@@ -1714,20 +2008,20 @@ void Init_pqcrypto_secure(void) {
|
|
|
1714
2008
|
rb_define_module_function(mPQCrypto, "hybrid_kem_decapsulate_expanded_object",
|
|
1715
2009
|
pqcrypto_hybrid_kem_decapsulate_expanded_object, 2);
|
|
1716
2010
|
rb_define_module_function(mPQCrypto, "sign_keypair", pqcrypto_sign_keypair, 0);
|
|
1717
|
-
rb_define_module_function(mPQCrypto, "sign", pqcrypto_sign,
|
|
1718
|
-
rb_define_module_function(mPQCrypto, "verify", pqcrypto_verify,
|
|
2011
|
+
rb_define_module_function(mPQCrypto, "sign", pqcrypto_sign, -1);
|
|
2012
|
+
rb_define_module_function(mPQCrypto, "verify", pqcrypto_verify, -1);
|
|
1719
2013
|
rb_define_module_function(mPQCrypto, "ml_dsa_44_keypair", pqcrypto_ml_dsa_44_keypair, 0);
|
|
1720
2014
|
rb_define_module_function(mPQCrypto, "ml_dsa_44_keypair_from_seed",
|
|
1721
2015
|
pqcrypto_ml_dsa_44_keypair_from_seed, 1);
|
|
1722
2016
|
rb_define_module_function(mPQCrypto, "ml_dsa_keypair_from_seed",
|
|
1723
2017
|
pqcrypto_ml_dsa_keypair_from_seed, 1);
|
|
1724
|
-
rb_define_module_function(mPQCrypto, "ml_dsa_44_sign", pqcrypto_ml_dsa_44_sign,
|
|
1725
|
-
rb_define_module_function(mPQCrypto, "ml_dsa_44_verify", pqcrypto_ml_dsa_44_verify,
|
|
2018
|
+
rb_define_module_function(mPQCrypto, "ml_dsa_44_sign", pqcrypto_ml_dsa_44_sign, -1);
|
|
2019
|
+
rb_define_module_function(mPQCrypto, "ml_dsa_44_verify", pqcrypto_ml_dsa_44_verify, -1);
|
|
1726
2020
|
rb_define_module_function(mPQCrypto, "ml_dsa_87_keypair", pqcrypto_ml_dsa_87_keypair, 0);
|
|
1727
2021
|
rb_define_module_function(mPQCrypto, "ml_dsa_87_keypair_from_seed",
|
|
1728
2022
|
pqcrypto_ml_dsa_87_keypair_from_seed, 1);
|
|
1729
|
-
rb_define_module_function(mPQCrypto, "ml_dsa_87_sign", pqcrypto_ml_dsa_87_sign,
|
|
1730
|
-
rb_define_module_function(mPQCrypto, "ml_dsa_87_verify", pqcrypto_ml_dsa_87_verify,
|
|
2023
|
+
rb_define_module_function(mPQCrypto, "ml_dsa_87_sign", pqcrypto_ml_dsa_87_sign, -1);
|
|
2024
|
+
rb_define_module_function(mPQCrypto, "ml_dsa_87_verify", pqcrypto_ml_dsa_87_verify, -1);
|
|
1731
2025
|
rb_define_module_function(mPQCrypto, "ct_equals", pqcrypto_ct_equals, 2);
|
|
1732
2026
|
rb_define_module_function(mPQCrypto, "secure_wipe", pqcrypto_secure_wipe, 1);
|
|
1733
2027
|
rb_define_module_function(mPQCrypto, "version", pqcrypto_version, 0);
|
|
@@ -1747,10 +2041,19 @@ void Init_pqcrypto_secure(void) {
|
|
|
1747
2041
|
pqcrypto_secret_key_from_pqc_container_der, 1);
|
|
1748
2042
|
rb_define_module_function(mPQCrypto, "secret_key_from_pqc_container_pem",
|
|
1749
2043
|
pqcrypto_secret_key_from_pqc_container_pem, 1);
|
|
2044
|
+
rb_define_module_function(mPQCrypto, "pkcs8_private_key_info_to_der",
|
|
2045
|
+
pqcrypto_pkcs8_private_key_info_to_der, 2);
|
|
2046
|
+
rb_define_module_function(mPQCrypto, "pkcs8_private_key_info_from_der",
|
|
2047
|
+
pqcrypto_pkcs8_private_key_info_from_der, 1);
|
|
2048
|
+
rb_define_module_function(mPQCrypto, "pkcs8_encrypt_der", pqcrypto_pkcs8_encrypt_der, 3);
|
|
2049
|
+
rb_define_module_function(mPQCrypto, "pkcs8_decrypt_der", pqcrypto_pkcs8_decrypt_der, 2);
|
|
2050
|
+
rb_define_module_function(mPQCrypto, "pkcs8_encrypted_der?", pqcrypto_pkcs8_encrypted_der_p, 1);
|
|
2051
|
+
rb_define_module_function(mPQCrypto, "pkcs8_der_to_pem", pqcrypto_pkcs8_der_to_pem, 2);
|
|
2052
|
+
rb_define_module_function(mPQCrypto, "pkcs8_pem_to_der", pqcrypto_pkcs8_pem_to_der, 1);
|
|
1750
2053
|
rb_define_module_function(mPQCrypto, "_native_mldsa_extract_tr",
|
|
1751
|
-
pqcrypto__native_mldsa_extract_tr, 1);
|
|
2054
|
+
pqcrypto__native_mldsa_extract_tr, -1);
|
|
1752
2055
|
rb_define_module_function(mPQCrypto, "_native_mldsa_compute_tr",
|
|
1753
|
-
pqcrypto__native_mldsa_compute_tr, 1);
|
|
2056
|
+
pqcrypto__native_mldsa_compute_tr, -1);
|
|
1754
2057
|
rb_define_module_function(mPQCrypto, "_native_mldsa_mu_builder_new",
|
|
1755
2058
|
pqcrypto__native_mldsa_mu_builder_new, 2);
|
|
1756
2059
|
rb_define_module_function(mPQCrypto, "_native_mldsa_mu_builder_update",
|
|
@@ -1760,9 +2063,9 @@ void Init_pqcrypto_secure(void) {
|
|
|
1760
2063
|
rb_define_module_function(mPQCrypto, "_native_mldsa_mu_builder_release",
|
|
1761
2064
|
pqcrypto__native_mldsa_mu_builder_release, 1);
|
|
1762
2065
|
rb_define_module_function(mPQCrypto, "_native_mldsa_sign_mu", pqcrypto__native_mldsa_sign_mu,
|
|
1763
|
-
|
|
2066
|
+
-1);
|
|
1764
2067
|
rb_define_module_function(mPQCrypto, "_native_mldsa_verify_mu",
|
|
1765
|
-
pqcrypto__native_mldsa_verify_mu,
|
|
2068
|
+
pqcrypto__native_mldsa_verify_mu, -1);
|
|
1766
2069
|
|
|
1767
2070
|
define_constants();
|
|
1768
2071
|
}
|