Skip to content

Commit 4bf6877

Browse files
Add encap/decapKeyCheck support in ACVP
1 parent b5e2f86 commit 4bf6877

File tree

6 files changed

+161
-5
lines changed

6 files changed

+161
-5
lines changed

crypto/fipsmodule/ml_kem/ml_kem.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,3 +394,45 @@ int ml_kem_common_decapsulate(int (*decapsulate)(uint8_t *shared_secret, const u
394394
set_written_len_on_success(res, shared_secret);
395395
return res;
396396
}
397+
398+
int ml_kem_512_check_pk(const uint8_t *public_key) {
399+
if (public_key == NULL) {
400+
return 1;
401+
}
402+
return mlkem512_check_pk(public_key);
403+
}
404+
405+
int ml_kem_512_check_sk(const uint8_t *secret_key) {
406+
if (secret_key == NULL) {
407+
return 1;
408+
}
409+
return mlkem512_check_sk(secret_key);
410+
}
411+
412+
int ml_kem_768_check_pk(const uint8_t *public_key) {
413+
if (public_key == NULL) {
414+
return 1;
415+
}
416+
return mlkem768_check_pk(public_key);
417+
}
418+
419+
int ml_kem_768_check_sk(const uint8_t *secret_key) {
420+
if (secret_key == NULL) {
421+
return 1;
422+
}
423+
return mlkem768_check_sk(secret_key);
424+
}
425+
426+
int ml_kem_1024_check_pk(const uint8_t *public_key) {
427+
if (public_key == NULL) {
428+
return 1;
429+
}
430+
return mlkem1024_check_pk(public_key);
431+
}
432+
433+
int ml_kem_1024_check_sk(const uint8_t *secret_key) {
434+
if (secret_key == NULL) {
435+
return 1;
436+
}
437+
return mlkem1024_check_sk(secret_key);
438+
}

crypto/fipsmodule/ml_kem/ml_kem.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ int ml_kem_512_decapsulate_no_self_test(uint8_t *shared_secret /* OUT */,
7979
const uint8_t *ciphertext /* IN */,
8080
const uint8_t *secret_key /* IN */);
8181

82+
OPENSSL_EXPORT int ml_kem_512_check_pk(const uint8_t *public_key /* IN */);
83+
OPENSSL_EXPORT int ml_kem_512_check_sk(const uint8_t *secret_key /* IN */);
84+
8285
OPENSSL_EXPORT int ml_kem_768_keypair_deterministic(uint8_t *public_key /* OUT */,
8386
size_t *public_len /* IN_OUT */,
8487
uint8_t *secret_key /* OUT */,
@@ -126,6 +129,9 @@ int ml_kem_768_decapsulate_no_self_test(uint8_t *shared_secret /* OUT */,
126129
const uint8_t *ciphertext /* IN */,
127130
const uint8_t *secret_key /* IN */);
128131

132+
OPENSSL_EXPORT int ml_kem_768_check_pk(const uint8_t *public_key /* IN */);
133+
OPENSSL_EXPORT int ml_kem_768_check_sk(const uint8_t *secret_key /* IN */);
134+
129135
OPENSSL_EXPORT int ml_kem_1024_keypair_deterministic(uint8_t *public_key /* OUT */,
130136
size_t *public_len /* IN_OUT */,
131137
uint8_t *secret_key /* OUT */,
@@ -175,6 +181,9 @@ int ml_kem_1024_decapsulate_no_self_test(uint8_t *shared_secret /* OUT */,
175181
const uint8_t *ciphertext /* IN */,
176182
const uint8_t *secret_key /* IN */);
177183

184+
OPENSSL_EXPORT int ml_kem_1024_check_pk(const uint8_t *public_key /* IN */);
185+
OPENSSL_EXPORT int ml_kem_1024_check_sk(const uint8_t *secret_key /* IN */);
186+
178187
#if defined(__cplusplus)
179188
}
180189
#endif

util/fipstools/acvp/acvptool/subprocess/ml_kem.go

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,10 @@ type mlKemEncDecapTestGroupResponse struct {
113113
}
114114

115115
type mlKemEncDecapTestCaseResponse struct {
116-
ID uint64 `json:"tcId"`
117-
C hexEncodedByteString `json:"c,omitempty"`
118-
K hexEncodedByteString `json:"k,omitempty"`
116+
ID uint64 `json:"tcId"`
117+
C hexEncodedByteString `json:"c,omitempty"`
118+
K hexEncodedByteString `json:"k,omitempty"`
119+
Passed *bool `json:"testPassed,omitempty"`
119120
}
120121

121122
func processMlKemEncapDecap(vectors json.RawMessage, m Transactable) (interface{}, error) {
@@ -129,7 +130,9 @@ func processMlKemEncapDecap(vectors json.RawMessage, m Transactable) (interface{
129130

130131
for _, group := range groups {
131132
if (strings.EqualFold(group.Function, "encapsulation") && !strings.EqualFold(group.Type, "AFT")) ||
132-
(strings.EqualFold(group.Function, "decapsulation") && !strings.EqualFold(group.Type, "VAL")) {
133+
(strings.EqualFold(group.Function, "decapsulation") && !strings.EqualFold(group.Type, "VAL")) ||
134+
(strings.EqualFold(group.Function, "decapsulationKeyCheck") && !strings.EqualFold(group.Type, "VAL")) ||
135+
(strings.EqualFold(group.Function, "encapsulationKeyCheck") && !strings.EqualFold(group.Type, "VAL")) {
133136
return nil, fmt.Errorf("unsupported encapDecap function and test group type pair: (%v, %v)", group.Function, group.Type)
134137
}
135138

@@ -148,6 +151,10 @@ func processMlKemEncapDecap(vectors json.RawMessage, m Transactable) (interface{
148151
testResponse, err = processMlKemEncapTestCase(test.ID, group.ParameterSet, test.EK, test.M, m)
149152
case strings.EqualFold(group.Function, "decapsulation"):
150153
testResponse, err = processMlKemDecapTestCase(test.ID, group.ParameterSet, test.DK, test.C, m)
154+
case strings.EqualFold(group.Function, "encapsulationKeyCheck"):
155+
testResponse, err = processMlKemEncapKeyCheckTestCase(test.ID, group.ParameterSet, test.EK, m)
156+
case strings.EqualFold(group.Function, "decapsulationKeyCheck"):
157+
testResponse, err = processMlKemDecapKeyCheckTestCase(test.ID, group.ParameterSet, test.DK, m)
151158
default:
152159
return nil, fmt.Errorf("unknown encDecap function: %v", group.Function)
153160
}
@@ -192,3 +199,32 @@ func processMlKemDecapTestCase(id uint64, algorithm string, dk []byte, c []byte,
192199
K: k,
193200
}, nil
194201
}
202+
203+
func processMlKemEncapKeyCheckTestCase(id uint64, algorithm string, ek []byte, t Transactable) (mlKemEncDecapTestCaseResponse, error) {
204+
results, err := t.Transact("ML-KEM/"+algorithm+"/encapKeyCheck", 1, ek)
205+
if err != nil {
206+
return mlKemEncDecapTestCaseResponse{}, err
207+
}
208+
209+
testPassed := results[0][0] == 1
210+
211+
return mlKemEncDecapTestCaseResponse{
212+
ID: id,
213+
Passed: &testPassed,
214+
}, nil
215+
}
216+
217+
func processMlKemDecapKeyCheckTestCase(id uint64, algorithm string, dk []byte, t Transactable) (mlKemEncDecapTestCaseResponse, error) {
218+
results, err := t.Transact("ML-KEM/"+algorithm+"/decapKeyCheck", 1, dk)
219+
if err != nil {
220+
return mlKemEncDecapTestCaseResponse{}, err
221+
}
222+
223+
testPassed := results[0][0] == 1
224+
225+
return mlKemEncDecapTestCaseResponse{
226+
ID: id,
227+
Passed: &testPassed,
228+
}, nil
229+
}
230+
65 Bytes
Binary file not shown.
11.2 KB
Binary file not shown.

util/fipstools/acvp/modulewrapper/modulewrapper.cc

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@
5959
#include "../../../../crypto/fipsmodule/curve25519/internal.h"
6060
#include "../../../../crypto/fipsmodule/ml_dsa/ml_dsa.h"
6161
#include "../../../../crypto/fipsmodule/ml_dsa/ml_dsa_ref/params.h"
62+
#include "../../../../crypto/fipsmodule/ml_kem/ml_kem.h"
63+
6264
#include "modulewrapper.h"
6365

6466

@@ -1392,7 +1394,7 @@ static bool GetConfig(const Span<const uint8_t> args[],
13921394
"mode": "encapDecap",
13931395
"revision": "FIPS203",
13941396
"parameterSets": ["ML-KEM-512", "ML-KEM-768", "ML-KEM-1024"],
1395-
"functions": ["encapsulation", "decapsulation"]
1397+
"functions": ["encapsulation", "decapsulation", "encapsulationKeyCheck", "decapsulationKeyCheck"]
13961398
},)"
13971399
R"({
13981400
"algorithm": "EDDSA",
@@ -3170,6 +3172,67 @@ static bool ML_KEM_DECAP(const Span<const uint8_t> args[],
31703172
{Span<const uint8_t>(shared_secret.data(), shared_secret_len)});
31713173
}
31723174

3175+
template <int nid>
3176+
static bool MLKEM_ENCAP_CHECK(const Span<const uint8_t> args[],
3177+
ReplyCallback write_reply) {
3178+
const Span<const uint8_t> ek = args[0];
3179+
3180+
size_t expected_size = 0;
3181+
int (*check_fn)(const uint8_t*) = nullptr;
3182+
if(nid == NID_MLKEM512) {
3183+
expected_size = MLKEM512_PUBLIC_KEY_BYTES;
3184+
check_fn = ml_kem_512_check_pk;
3185+
} else if(nid == NID_MLKEM768) {
3186+
expected_size = MLKEM768_PUBLIC_KEY_BYTES;
3187+
check_fn = ml_kem_768_check_pk;
3188+
} else if(nid == NID_MLKEM1024) {
3189+
expected_size = MLKEM1024_PUBLIC_KEY_BYTES;
3190+
check_fn = ml_kem_1024_check_pk;
3191+
} else {
3192+
return false;
3193+
}
3194+
3195+
// The check_sk function validates mandated by FIPS 203 Section 7.2.
3196+
uint8_t success_flag[1] = {0};
3197+
if(ek.size() != expected_size || check_fn(ek.data()) != 0) {
3198+
return write_reply({Span<const uint8_t>(success_flag)});
3199+
}
3200+
3201+
success_flag[0] = 1;
3202+
return write_reply({Span<const uint8_t>(success_flag)});
3203+
}
3204+
3205+
template <int nid>
3206+
static bool MLKEM_DECAP_CHECK(const Span<const uint8_t> args[],
3207+
ReplyCallback write_reply) {
3208+
const Span<const uint8_t> dk = args[0];
3209+
3210+
// Validate the secret key size matches the expected size.
3211+
size_t expected_size = 0;
3212+
int (*check_fn)(const uint8_t*) = nullptr;
3213+
if(nid == NID_MLKEM512) {
3214+
expected_size = MLKEM512_SECRET_KEY_BYTES;
3215+
check_fn = ml_kem_512_check_sk;
3216+
} else if(nid == NID_MLKEM768) {
3217+
expected_size = MLKEM768_SECRET_KEY_BYTES;
3218+
check_fn = ml_kem_768_check_sk;
3219+
} else if(nid == NID_MLKEM1024) {
3220+
expected_size = MLKEM1024_SECRET_KEY_BYTES;
3221+
check_fn = ml_kem_1024_check_sk;
3222+
} else {
3223+
return false;
3224+
}
3225+
3226+
// The check_sk function validates mandated by FIPS 203 Section 7.3.
3227+
uint8_t success_flag[1] = {0};
3228+
if(dk.size() != expected_size || check_fn(dk.data()) != 0) {
3229+
return write_reply({Span<const uint8_t>(success_flag)});
3230+
}
3231+
3232+
success_flag[0] = 1;
3233+
return write_reply({Span<const uint8_t>(success_flag)});
3234+
}
3235+
31733236
static bool ED25519KeyGen(const Span<const uint8_t> args[],
31743237
ReplyCallback write_reply) {
31753238
std::vector<uint8_t> private_key(ED25519_PRIVATE_KEY_LEN);
@@ -3685,6 +3748,12 @@ static struct {
36853748
{"ML-KEM/ML-KEM-512/decap", 2, ML_KEM_DECAP<NID_MLKEM512>},
36863749
{"ML-KEM/ML-KEM-768/decap", 2, ML_KEM_DECAP<NID_MLKEM768>},
36873750
{"ML-KEM/ML-KEM-1024/decap", 2, ML_KEM_DECAP<NID_MLKEM1024>},
3751+
{"ML-KEM/ML-KEM-512/encapKeyCheck", 1, MLKEM_ENCAP_CHECK<NID_MLKEM512>},
3752+
{"ML-KEM/ML-KEM-768/encapKeyCheck", 1, MLKEM_ENCAP_CHECK<NID_MLKEM768>},
3753+
{"ML-KEM/ML-KEM-1024/encapKeyCheck", 1, MLKEM_ENCAP_CHECK<NID_MLKEM1024>},
3754+
{"ML-KEM/ML-KEM-512/decapKeyCheck", 1, MLKEM_DECAP_CHECK<NID_MLKEM512>},
3755+
{"ML-KEM/ML-KEM-768/decapKeyCheck", 1, MLKEM_DECAP_CHECK<NID_MLKEM768>},
3756+
{"ML-KEM/ML-KEM-1024/decapKeyCheck", 1, MLKEM_DECAP_CHECK<NID_MLKEM1024>},
36883757
{"EDDSA/ED-25519/keyGen", 0, ED25519KeyGen},
36893758
{"EDDSA/ED-25519/keyVer", 1, ED25519KeyVer},
36903759
{"EDDSA/ED-25519/sigGen", 2, ED25519SigGen},

0 commit comments

Comments
 (0)