Skip to content

Commit 97c53da

Browse files
Add encap/decapKeyCheck support in ACVP (#2872)
ACVP has support for a new test vectors that test against the encapsulation/decapsulation key checks defined in FIPS 203. > Adds "encapsulationKeyCheck" and "decapsulationKeyCheck" as functions for ML-KEM Encap/Decap FIPS203 to exercise an implementation's capability to perform the Encapsulation Key Check in FIPS 203 Section 7.2 and the Decapsulation Key Check in FIPS 203 Section 7.3. These tests are only included if the appropriate function is present in the registration. They operate by providing a valid or invalid key and expecting the IUT to return a true for a valid key or false for an invalid key. * https://github.com/usnistgov/ACVP-Server/releases This add support in ACVP to run against the relevant `crypto_kem_check_pk` and `crypto_kem_check_sk` functions that do the checks for us. Also added the new `encapsulationKeyCheck` and `decapsulationKeyCheck` test vectors in `ML-KEM.bz2`. N/A new `encapsulationKeyCheck` and `decapsulationKeyCheck` test vectors in `ML-KEM.bz2` By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license and the ISC license.
1 parent b5e2f86 commit 97c53da

File tree

7 files changed

+160
-6
lines changed

7 files changed

+160
-6
lines changed

.github/workflows/linux_x86_omnibus.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ jobs:
175175
runs-on:
176176
- codebuild-aws-lc-ci-github-actions-${{ github.run_id }}-${{ github.run_attempt }}
177177
image:linux-5.0
178-
instance-size:large
178+
instance-size:${{ matrix.build32 && 'xlarge' || 'large' }}
179179
strategy:
180180
fail-fast: false
181181
matrix:

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, size_t public_key_len) {
399+
if (public_key == NULL || public_key_len != MLKEM512_PUBLIC_KEY_BYTES) {
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, size_t secret_key_len) {
406+
if (secret_key == NULL || secret_key_len != MLKEM512_SECRET_KEY_BYTES) {
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, size_t public_key_len) {
413+
if (public_key == NULL || public_key_len != MLKEM768_PUBLIC_KEY_BYTES) {
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, size_t secret_key_len) {
420+
if (secret_key == NULL || secret_key_len != MLKEM768_SECRET_KEY_BYTES) {
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, size_t public_key_len) {
427+
if (public_key == NULL || public_key_len != MLKEM1024_PUBLIC_KEY_BYTES) {
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, size_t secret_key_len) {
434+
if (secret_key == NULL || secret_key_len != MLKEM1024_SECRET_KEY_BYTES) {
435+
return -1;
436+
}
437+
return mlkem1024_check_sk(secret_key);
438+
}

crypto/fipsmodule/ml_kem/ml_kem.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@ 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+
size_t public_key_len /* IN */);
84+
OPENSSL_EXPORT int ml_kem_512_check_sk(const uint8_t *secret_key /* IN */,
85+
size_t secret_key_len /* IN */);
86+
87+
8288
OPENSSL_EXPORT int ml_kem_768_keypair_deterministic(uint8_t *public_key /* OUT */,
8389
size_t *public_len /* IN_OUT */,
8490
uint8_t *secret_key /* OUT */,
@@ -126,6 +132,11 @@ int ml_kem_768_decapsulate_no_self_test(uint8_t *shared_secret /* OUT */,
126132
const uint8_t *ciphertext /* IN */,
127133
const uint8_t *secret_key /* IN */);
128134

135+
OPENSSL_EXPORT int ml_kem_768_check_pk(const uint8_t *public_key /* IN */,
136+
size_t public_key_len /* IN */);
137+
OPENSSL_EXPORT int ml_kem_768_check_sk(const uint8_t *secret_key /* IN */,
138+
size_t secret_key_len /* IN */);
139+
129140
OPENSSL_EXPORT int ml_kem_1024_keypair_deterministic(uint8_t *public_key /* OUT */,
130141
size_t *public_len /* IN_OUT */,
131142
uint8_t *secret_key /* OUT */,
@@ -175,6 +186,11 @@ int ml_kem_1024_decapsulate_no_self_test(uint8_t *shared_secret /* OUT */,
175186
const uint8_t *ciphertext /* IN */,
176187
const uint8_t *secret_key /* IN */);
177188

189+
OPENSSL_EXPORT int ml_kem_1024_check_pk(const uint8_t *public_key /* IN */,
190+
size_t public_key_len /* IN */);
191+
OPENSSL_EXPORT int ml_kem_1024_check_sk(const uint8_t *secret_key /* IN */,
192+
size_t secret_key_len /* IN */);
193+
178194
#if defined(__cplusplus)
179195
}
180196
#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: 61 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,58 @@ 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+
int (*check_fn)(const uint8_t*, size_t) = nullptr;
3181+
if(nid == NID_MLKEM512) {
3182+
check_fn = ml_kem_512_check_pk;
3183+
} else if(nid == NID_MLKEM768) {
3184+
check_fn = ml_kem_768_check_pk;
3185+
} else if(nid == NID_MLKEM1024) {
3186+
check_fn = ml_kem_1024_check_pk;
3187+
} else {
3188+
return false;
3189+
}
3190+
3191+
// The check_sk function validates mandated by FIPS 203 Section 7.2.
3192+
uint8_t success_flag[1] = {0};
3193+
if(check_fn(ek.data(), ek.size()) != 0) {
3194+
return write_reply({Span<const uint8_t>(success_flag)});
3195+
}
3196+
3197+
success_flag[0] = 1;
3198+
return write_reply({Span<const uint8_t>(success_flag)});
3199+
}
3200+
3201+
template <int nid>
3202+
static bool MLKEM_DECAP_CHECK(const Span<const uint8_t> args[],
3203+
ReplyCallback write_reply) {
3204+
const Span<const uint8_t> dk = args[0];
3205+
3206+
int (*check_fn)(const uint8_t*, size_t) = nullptr;
3207+
if(nid == NID_MLKEM512) {
3208+
check_fn = ml_kem_512_check_sk;
3209+
} else if(nid == NID_MLKEM768) {
3210+
check_fn = ml_kem_768_check_sk;
3211+
} else if(nid == NID_MLKEM1024) {
3212+
check_fn = ml_kem_1024_check_sk;
3213+
} else {
3214+
return false;
3215+
}
3216+
3217+
// The check_sk function validates mandated by FIPS 203 Section 7.3.
3218+
uint8_t success_flag[1] = {0};
3219+
if(check_fn(dk.data(), dk.size()) != 0) {
3220+
return write_reply({Span<const uint8_t>(success_flag)});
3221+
}
3222+
3223+
success_flag[0] = 1;
3224+
return write_reply({Span<const uint8_t>(success_flag)});
3225+
}
3226+
31733227
static bool ED25519KeyGen(const Span<const uint8_t> args[],
31743228
ReplyCallback write_reply) {
31753229
std::vector<uint8_t> private_key(ED25519_PRIVATE_KEY_LEN);
@@ -3685,6 +3739,12 @@ static struct {
36853739
{"ML-KEM/ML-KEM-512/decap", 2, ML_KEM_DECAP<NID_MLKEM512>},
36863740
{"ML-KEM/ML-KEM-768/decap", 2, ML_KEM_DECAP<NID_MLKEM768>},
36873741
{"ML-KEM/ML-KEM-1024/decap", 2, ML_KEM_DECAP<NID_MLKEM1024>},
3742+
{"ML-KEM/ML-KEM-512/encapKeyCheck", 1, MLKEM_ENCAP_CHECK<NID_MLKEM512>},
3743+
{"ML-KEM/ML-KEM-768/encapKeyCheck", 1, MLKEM_ENCAP_CHECK<NID_MLKEM768>},
3744+
{"ML-KEM/ML-KEM-1024/encapKeyCheck", 1, MLKEM_ENCAP_CHECK<NID_MLKEM1024>},
3745+
{"ML-KEM/ML-KEM-512/decapKeyCheck", 1, MLKEM_DECAP_CHECK<NID_MLKEM512>},
3746+
{"ML-KEM/ML-KEM-768/decapKeyCheck", 1, MLKEM_DECAP_CHECK<NID_MLKEM768>},
3747+
{"ML-KEM/ML-KEM-1024/decapKeyCheck", 1, MLKEM_DECAP_CHECK<NID_MLKEM1024>},
36883748
{"EDDSA/ED-25519/keyGen", 0, ED25519KeyGen},
36893749
{"EDDSA/ED-25519/keyVer", 1, ED25519KeyVer},
36903750
{"EDDSA/ED-25519/sigGen", 2, ED25519SigGen},

0 commit comments

Comments
 (0)