Skip to content

Commit 9f557c6

Browse files
authored
Merge branch 'main' into update-vectors-ci
2 parents 931b73b + d4cc872 commit 9f557c6

File tree

146 files changed

+40175
-12077
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

146 files changed

+40175
-12077
lines changed

.github/workflows/image-build-windows.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ on:
1717
paths:
1818
- .github/docker_images/aws-lc/windows/Dockerfile.ltsc2022
1919
- .github/docker_images/scripts/**
20+
- .github/workflows/image-build-windows.yml
2021
concurrency:
2122
group: ${{ inputs.concurrency_prefix || github.workflow }}-${{ github.ref_name }}
2223
cancel-in-progress: true
@@ -42,6 +43,8 @@ jobs:
4243
vs2022: ${{ steps.images.outputs.vs2022 }}
4344
sde: ${{ steps.images.outputs.sde }}
4445
steps:
46+
- name: Enable long paths
47+
run: git config --global core.longpaths true
4548
- uses: actions/checkout@v5
4649
- name: Login to Amazon ECR
4750
id: login-ecr
@@ -138,6 +141,8 @@ jobs:
138141
outputs:
139142
ltsc2022: ${{ steps.images.outputs.ltsc2022 }}
140143
steps:
144+
- name: Enable long paths
145+
run: git config --global core.longpaths true
141146
- uses: actions/checkout@v5
142147
- name: Login to Amazon ECR
143148
id: login-ecr

LICENSE

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -206,9 +206,6 @@ are met:
206206
written permission.
207207

208208

209-
The code in crypto/kyber/pqcrystals-kyber_kyber512_ref and
210-
crypto/ml_kem/ml_kem_ipd_ref_common carries the Public Domain license:
211-
212209
Public Domain (https://creativecommons.org/share-your-work/public-domain/cc0/)
213210

214211
For Keccak and AES we are using public-domain

crypto/CMakeLists.txt

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -442,11 +442,6 @@ add_library(
442442
ex_data.c
443443
hpke/hpke.c
444444
hrss/hrss.c
445-
kyber/kyber512r3_ref.c
446-
kyber/kyber768r3_ref.c
447-
kyber/kyber1024r3_ref.c
448-
kyber/pqcrystals_kyber_ref_common/fips202.c
449-
kyber/kem_kyber.c
450445
lhash/lhash.c
451446
mem.c
452447
obj/obj.c

crypto/evp_extra/evp_extra_test.cc

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2200,9 +2200,6 @@ struct KnownKEM {
22002200
};
22012201

22022202
static const struct KnownKEM kKEMs[] = {
2203-
{"Kyber512r3", NID_KYBER512_R3, 800, 1632, 768, 32, 64, 32, "kyber/kat/kyber512r3.txt"},
2204-
{"Kyber768r3", NID_KYBER768_R3, 1184, 2400, 1088, 32, 64, 32, "kyber/kat/kyber768r3.txt"},
2205-
{"Kyber1024r3", NID_KYBER1024_R3, 1568, 3168, 1568, 32, 64, 32, "kyber/kat/kyber1024r3.txt"},
22062203
{"MLKEM512", NID_MLKEM512, 800, 1632, 768, 32, 64, 32, "fipsmodule/ml_kem/kat/mlkem512.txt"},
22072204
{"MLKEM768", NID_MLKEM768, 1184, 2400, 1088, 32, 64, 32, "fipsmodule/ml_kem/kat/mlkem768.txt"},
22082205
{"MLKEM1024", NID_MLKEM1024, 1568, 3168, 1568, 32, 64, 32, "fipsmodule/ml_kem/kat/mlkem1024.txt"},

crypto/evp_extra/p_kem_test.cc

Lines changed: 260 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0 OR ISC
33

4+
#include <algorithm>
45
#include <gtest/gtest.h>
56
#include <openssl/base.h>
67
#include <openssl/bio.h>
78
#include <openssl/evp.h>
9+
#include <openssl/experimental/kem_deterministic_api.h>
810
#include <openssl/mem.h>
911
#include <openssl/pem.h>
1012
#include <openssl/pkcs8.h>
1113
#include <openssl/ssl.h>
1214
#include "../fipsmodule/evp/internal.h"
1315
#include "../fipsmodule/kem/internal.h"
16+
#include "../test/file_test.h"
1417
#include "../test/test_util.h"
15-
#include <openssl/experimental/kem_deterministic_api.h>
18+
#include "../test/wycheproof_util.h"
1619

1720

1821
// https://datatracker.ietf.org/doc/draft-ietf-lamps-kyber-certificates/
@@ -927,3 +930,259 @@ TEST(KEMTest, InvalidSeedLength) {
927930

928931
OPENSSL_free(der_priv);
929932
}
933+
934+
935+
// Wycheproof test vector mapping for KEMs
936+
struct WycheproofKEM {
937+
const char name[20];
938+
const int nid;
939+
size_t ciphertext_len;
940+
size_t shared_secret_len;
941+
const char *encaps_test;
942+
const char *decaps_seed_test;
943+
const char *decaps_noseed_test;
944+
};
945+
946+
//= third_party/vectors/vectors_spec.md#wycheproof
947+
//# AWS-LC MUST test against `testvectors_v1/mlkem_1024_test.txt`.
948+
//# AWS-LC MUST test against `testvectors_v1/mlkem_512_test.txt`.
949+
//# AWS-LC MUST test against `testvectors_v1/mlkem_768_test.txt`.
950+
//# AWS-LC MUST test against `testvectors_v1/mlkem_1024_encaps_test.txt`.
951+
//# AWS-LC MUST test against `testvectors_v1/mlkem_1024_semi_expanded_decaps_test.txt`.
952+
//# AWS-LC MUST test against `testvectors_v1/mlkem_512_encaps_test.txt`.
953+
//# AWS-LC MUST test against `testvectors_v1/mlkem_512_semi_expanded_decaps_test.txt`.
954+
//# AWS-LC MUST test against `testvectors_v1/mlkem_768_encaps_test.txt`.
955+
//# AWS-LC MUST test against `testvectors_v1/mlkem_768_semi_expanded_decaps_test.txt`.
956+
static const struct WycheproofKEM kWycheproofKEMs[] = {
957+
{
958+
"ML-KEM-512",
959+
NID_MLKEM512,
960+
768,
961+
32,
962+
"mlkem_512_encaps_test.txt",
963+
"mlkem_512_test.txt",
964+
"mlkem_512_semi_expanded_decaps_test.txt",
965+
},
966+
{
967+
"ML-KEM-768",
968+
NID_MLKEM768,
969+
1088,
970+
32,
971+
"mlkem_768_encaps_test.txt",
972+
"mlkem_768_test.txt",
973+
"mlkem_768_semi_expanded_decaps_test.txt",
974+
},
975+
{
976+
"ML-KEM-1024",
977+
NID_MLKEM1024,
978+
1568,
979+
32,
980+
"mlkem_1024_encaps_test.txt",
981+
"mlkem_1024_test.txt",
982+
"mlkem_1024_semi_expanded_decaps_test.txt",
983+
},
984+
};
985+
986+
class WycheproofKEMTest : public testing::TestWithParam<WycheproofKEM> {};
987+
988+
INSTANTIATE_TEST_SUITE_P(
989+
All, WycheproofKEMTest, testing::ValuesIn(kWycheproofKEMs),
990+
[](const testing::TestParamInfo<WycheproofKEM> &params) -> std::string {
991+
std::string name = params.param.name;
992+
// Replace dashes with underscores for valid C++ test names
993+
std::replace(name.begin(), name.end(), '-', '_');
994+
return name;
995+
});
996+
997+
TEST_P(WycheproofKEMTest, Encaps) {
998+
std::string test_path =
999+
std::string(kWycheproofV1Path) + GetParam().encaps_test;
1000+
FileTestGTest(test_path.c_str(), [&](FileTest *t) {
1001+
std::vector<uint8_t> ek, m, expected_k, expected_c;
1002+
std::string param_set;
1003+
1004+
ASSERT_TRUE(t->GetInstruction(&param_set, "parameterSet"));
1005+
ASSERT_EQ(param_set, GetParam().name);
1006+
1007+
ASSERT_TRUE(t->GetBytes(&ek, "ek"));
1008+
ASSERT_TRUE(t->GetBytes(&m, "m"));
1009+
ASSERT_TRUE(t->GetBytes(&expected_k, "K"));
1010+
ASSERT_TRUE(t->GetBytes(&expected_c, "c"));
1011+
1012+
WycheproofResult result;
1013+
ASSERT_TRUE(GetWycheproofResult(t, &result));
1014+
1015+
bssl::UniquePtr<EVP_PKEY> pkey(
1016+
EVP_PKEY_kem_new_raw_public_key(GetParam().nid, ek.data(), ek.size()));
1017+
1018+
if (!result.IsValid() && result.HasFlag("ModulusOverflow")) {
1019+
if (pkey) {
1020+
// FIPS 203 only requires doing this check before encapsulation.
1021+
fprintf(stderr,
1022+
"WARNING: Successfully imported %s encapsulation key with "
1023+
"ModulusOverflow. This is allowed by FIPS 203.\n",
1024+
param_set.c_str());
1025+
}
1026+
}
1027+
if (pkey) {
1028+
bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new(pkey.get(), nullptr));
1029+
ASSERT_TRUE(ctx);
1030+
1031+
// Perform deterministic encapsulation using the m field as seed
1032+
// see https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.pdf#algorithm.17
1033+
std::vector<uint8_t> ciphertext(GetParam().ciphertext_len);
1034+
std::vector<uint8_t> shared_secret(GetParam().shared_secret_len);
1035+
size_t ciphertext_len = ciphertext.size();
1036+
size_t shared_secret_len = shared_secret.size();
1037+
size_t seed_len = m.size();
1038+
int encaps_result =
1039+
EVP_PKEY_encapsulate_deterministic(ctx.get(), ciphertext.data(), &ciphertext_len,
1040+
shared_secret.data(), &shared_secret_len, m.data(), &seed_len);
1041+
1042+
if (result.IsValid()) {
1043+
EXPECT_TRUE(encaps_result);
1044+
EXPECT_EQ(Bytes(ciphertext.data(), ciphertext_len), Bytes(expected_c));
1045+
EXPECT_EQ(Bytes(shared_secret.data(), shared_secret_len),
1046+
Bytes(expected_k));
1047+
} else {
1048+
EXPECT_FALSE(encaps_result)
1049+
<< "Expected encapsulation to fail for flags: "
1050+
<< result.StringifyFlags();
1051+
}
1052+
}
1053+
});
1054+
}
1055+
1056+
TEST_P(WycheproofKEMTest, DecapsSeed) {
1057+
std::string test_path =
1058+
std::string(kWycheproofV1Path) + GetParam().decaps_seed_test;
1059+
FileTestGTest(test_path.c_str(), [&](FileTest *t) {
1060+
std::vector<uint8_t> ek, seed, expected_k, ciphertext;
1061+
std::string param_set;
1062+
1063+
ASSERT_TRUE(t->GetInstruction(&param_set, "parameterSet"));
1064+
ASSERT_EQ(param_set, GetParam().name);
1065+
1066+
ASSERT_TRUE(t->GetBytes(&expected_k, "K"));
1067+
ASSERT_TRUE(t->GetBytes(&ciphertext, "c"));
1068+
1069+
WycheproofResult result;
1070+
ASSERT_TRUE(GetWycheproofResult(t, &result));
1071+
ASSERT_TRUE(t->GetBytes(&seed, "seed"));
1072+
1073+
// Initialize using provided seed
1074+
bssl::UniquePtr<EVP_PKEY_CTX> ctx(
1075+
EVP_PKEY_CTX_new_id(EVP_PKEY_KEM, nullptr));
1076+
ASSERT_TRUE(ctx);
1077+
ASSERT_TRUE(EVP_PKEY_CTX_kem_set_params(ctx.get(), GetParam().nid));
1078+
EVP_PKEY *raw = nullptr;
1079+
ASSERT_TRUE(EVP_PKEY_keygen_init(ctx.get()));
1080+
size_t seed_len = seed.size();
1081+
int keygen_result = EVP_PKEY_keygen_deterministic(ctx.get(), &raw, seed.data(), &seed_len);
1082+
1083+
// For invalid test cases, key generation might fail
1084+
if (!result.IsValid() && !keygen_result) {
1085+
// Expected failure in key generation for invalid cases
1086+
return;
1087+
}
1088+
1089+
ASSERT_TRUE(keygen_result);
1090+
ASSERT_TRUE(raw);
1091+
bssl::UniquePtr<EVP_PKEY> pkey(raw);
1092+
1093+
// Verify the generated public key matches the expected public key (if provided)
1094+
if (t->HasAttribute("ek")) {
1095+
ASSERT_TRUE(t->GetBytes(&ek, "ek"));
1096+
size_t actual_ek_len = 0;
1097+
ASSERT_TRUE(
1098+
EVP_PKEY_get_raw_public_key(pkey.get(), nullptr, &actual_ek_len));
1099+
ASSERT_EQ(actual_ek_len, ek.size());
1100+
std::vector<uint8_t> actual_ek(actual_ek_len);
1101+
ASSERT_TRUE(EVP_PKEY_get_raw_public_key(pkey.get(), actual_ek.data(),
1102+
&actual_ek_len));
1103+
EXPECT_EQ(Bytes(actual_ek), Bytes(ek));
1104+
}
1105+
1106+
// Perform decapsulation
1107+
ctx.reset(EVP_PKEY_CTX_new(pkey.get(), nullptr));
1108+
ASSERT_TRUE(ctx);
1109+
std::vector<uint8_t> shared_secret(GetParam().shared_secret_len);
1110+
size_t shared_secret_len = shared_secret.size();
1111+
int decaps_result = EVP_PKEY_decapsulate(
1112+
ctx.get(), shared_secret.data(), &shared_secret_len, ciphertext.data(),
1113+
ciphertext.size());
1114+
1115+
if (result.IsValid()) {
1116+
EXPECT_TRUE(decaps_result);
1117+
EXPECT_EQ(Bytes(shared_secret.data(), shared_secret_len),
1118+
Bytes(expected_k));
1119+
} else {
1120+
EXPECT_FALSE(decaps_result)
1121+
<< "Expected decapsulation to fail for flags: "
1122+
<< result.StringifyFlags();
1123+
}
1124+
});
1125+
}
1126+
1127+
// Test decapsulation with expanded decaps keys
1128+
TEST_P(WycheproofKEMTest, DecapsNoSeed) {
1129+
std::string test_path =
1130+
std::string(kWycheproofV1Path) + GetParam().decaps_noseed_test;
1131+
FileTestGTest(test_path.c_str(), [&](FileTest *t) {
1132+
std::vector<uint8_t> dk, ciphertext;
1133+
std::string param_set;
1134+
1135+
ASSERT_TRUE(t->GetInstruction(&param_set, "parameterSet"));
1136+
ASSERT_EQ(param_set, GetParam().name);
1137+
1138+
ASSERT_TRUE(t->GetBytes(&dk, "dk"));
1139+
ASSERT_TRUE(t->GetBytes(&ciphertext, "c"));
1140+
1141+
WycheproofResult result;
1142+
ASSERT_TRUE(GetWycheproofResult(t, &result));
1143+
1144+
// Create key from raw private key bytes
1145+
bssl::UniquePtr<EVP_PKEY> pkey(
1146+
EVP_PKEY_kem_new_raw_secret_key(GetParam().nid, dk.data(), dk.size()));
1147+
1148+
// Key creation should fail for incorrect key length
1149+
if (result.HasFlag("IncorrectDecapsulationKeyLength")) {
1150+
EXPECT_FALSE(pkey)
1151+
<< "Expected key creation to fail for incorrect key length";
1152+
return;
1153+
}
1154+
1155+
// Warn if we successfully imported an invalid private key
1156+
if (pkey && result.HasFlag("InvalidDecapsulationKey")) {
1157+
fprintf(stderr,
1158+
"WARNING: Successfully imported correct-length-but-invalid %s "
1159+
"decapsulation key. This is allowed by FIPS 203.\n",
1160+
param_set.c_str());
1161+
}
1162+
1163+
// For valid test cases, key creation should succeed
1164+
if (result.IsValid()) {
1165+
ASSERT_TRUE(pkey) << "Key creation failed unexpectedly for flags: "
1166+
<< result.StringifyFlags();
1167+
}
1168+
1169+
// Perform decapsulation
1170+
bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new(pkey.get(), nullptr));
1171+
ASSERT_TRUE(ctx);
1172+
1173+
std::vector<uint8_t> shared_secret(GetParam().shared_secret_len);
1174+
size_t shared_secret_len = shared_secret.size();
1175+
int decaps_result = EVP_PKEY_decapsulate(
1176+
ctx.get(), shared_secret.data(), &shared_secret_len, ciphertext.data(),
1177+
ciphertext.size());
1178+
1179+
if (result.IsValid()) {
1180+
EXPECT_TRUE(decaps_result)
1181+
<< "Expected decapsulation to succeed for valid test case";
1182+
} else {
1183+
EXPECT_FALSE(decaps_result)
1184+
<< "Expected decapsulation to fail for flags: "
1185+
<< result.StringifyFlags();
1186+
}
1187+
});
1188+
}

crypto/fipsmodule/PQREADME.md

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ To support these initiatives, the U.S. Department of Commerce’s National Insti
1313

1414
## AWS-LC Post-Quantum Algorithms
1515

16-
AWS-LC provides two post-quantum Key Encapsulation Mechanisms (KEMs), FIPS 203 ML-KEM and KyberR3, and a post-quantum digital signature scheme FIPS 204 ML-DSA. For details on the KEM API and how it can be used please see [README](https://github.com/aws/aws-lc/blob/main/crypto/fipsmodule/kem/README.md).
16+
AWS-LC supports the post-quantum Key Encapsulation Mechanisms (KEMs) FIPS 203 ML-KEM and the post-quantum digital signature scheme FIPS 204 ML-DSA. For details on the KEM API and how it can be used please see [README](https://github.com/aws/aws-lc/blob/main/crypto/fipsmodule/kem/README.md).
1717

1818
### FIPS 203: Module-Lattice-Based Key-Encapsulation Mechanism (ML-KEM)
1919

@@ -29,10 +29,6 @@ Performance benchmarks for key generation, encapsulation, and decapsulation are
2929

3030
```aws-lc-build % ./tool/bssl speed -filter ML-KEM```
3131

32-
#### KyberR3
33-
34-
Round 3 Kyber (KyberR3) was added to AWS-LC in September 2021 ([README](https://github.com/aws/aws-lc/blob/main/crypto/kyber/README.md)). Once all existing deployments of Kyber are migrated over to ML-KEM we will be removing support for Kyber from AWS-LC.
35-
3632
### FIPS 204: Module-Lattice-Based Digital Signature Algorithm (ML-DSA)
3733

3834
| Algorithm | Public Key (B) | Private Key (B) | Signature (B) |
@@ -47,19 +43,21 @@ The parameter set ML-DSA-44 is claimed to be in security strength category 2, ML
4743

4844
### Hybrid Post-Quantum TLS Specifications
4945

50-
To utilize Post-Quantum key exchange in TLS we recommend using our open-source TLS implementation s2n-tls that now supports Hybrid key exchange in TLS 1.3 (draft-ietf-tls-hybrid-design). s2n-tls also provides support for Post-Quantum hybrid ECDHE-MLKEM Key Agreement for TLSv1.3 (draft-kwiatkowski-tls-ecdhe-mlkem) with a proposal for new key share identifies for x25519 and ML-KEM-768.
51-
46+
To utilize Post-Quantum key exchange in TLS we recommend using our open-source TLS implementation s2n-tls. However, AWS-LC libssl also supports Post-Quantum key exchange in TLS. Namely, ML-KEM-based cipher suites for TLSv1.3 (draft-kwiatkowski-tls-ecdhe-mlkem)
5247

5348
| Supported Group | IANA ID (Hex) | IANA ID (Dec) |
5449
|-----------------------|----------------|----------------|
55-
| x25519_kyber512 | 0x2f39 | 12089 |
56-
| p256_kyber512 | 0x2f3a | 12090 |
57-
| X25519Kyber768Draft00 | 0x6399 | 25497 |
58-
| X25519Kyber768Draft00 | 0x639a | 25498 |
5950
| SecP256r1MLKEM768 | 0x11eb | 4587 |
51+
| SecP384r1MLKEM1024 | 0x11ed | 4589 |
6052
| X25519MLKEM768 | 0x11ec | 4588 |
6153

62-
Note that pre-standard groups (those that include Kyber) will stop being supported after the Kyber deprecation described above.
54+
In addition, AWS-LC libssl supports "pure" ML-KEM cipher suites (https://datatracker.ietf.org/doc/html/draft-connolly-tls-mlkem-key-agreement.html).
55+
56+
| Supported Group | IANA ID (Hex) | IANA ID (Dec) |
57+
|-----------------------|----------------|----------------|
58+
| MLKEM512 | 0x0200 | 512 |
59+
| MLKEM768 | 0x0201 | 513 |
60+
| MLKEM1024 | 0x0202 | 514 |
6361

6462
### AWS Java V2 SDK
6563

0 commit comments

Comments
 (0)