Skip to content

Commit b88eca8

Browse files
committed
crypto: refactor PQC raw seed handling
Refactor ML-DSA and ML-KEM seed sizes and seed import/export helpers into shared helpers. Keep the provider-specific OpenSSL and BoringSSL paths contained in those helpers. Signed-off-by: Filip Skokan <panva.ip@gmail.com>
1 parent 328bf1a commit b88eca8

1 file changed

Lines changed: 67 additions & 85 deletions

File tree

deps/ncrypto/ncrypto.cc

Lines changed: 67 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -2100,69 +2100,99 @@ EVPKeyPointer EVPKeyPointer::NewRawPrivate(
21002100
}
21012101

21022102
#if OPENSSL_WITH_PQC
2103-
EVPKeyPointer EVPKeyPointer::NewRawSeed(
2104-
int id, const Buffer<const unsigned char>& data) {
2105-
if (id == 0) return {};
2103+
namespace {
2104+
constexpr size_t kPqcMlDsaSeedSize = 32;
2105+
constexpr size_t kPqcMlKemSeedSize = 64;
21062106

2107-
#ifdef OPENSSL_IS_BORINGSSL
2108-
// BoringSSL exposes seed-based construction via EVP_PKEY_from_private_seed,
2109-
// which needs an |EVP_PKEY_ALG*| rather than a NID.
2110-
const EVP_PKEY_ALG* alg = nullptr;
2107+
size_t GetPqcSeedSize(int id) {
21112108
switch (id) {
21122109
case EVP_PKEY_ML_DSA_44:
2113-
alg = EVP_pkey_ml_dsa_44();
2114-
break;
21152110
case EVP_PKEY_ML_DSA_65:
2116-
alg = EVP_pkey_ml_dsa_65();
2117-
break;
21182111
case EVP_PKEY_ML_DSA_87:
2119-
alg = EVP_pkey_ml_dsa_87();
2120-
break;
2112+
return kPqcMlDsaSeedSize;
2113+
#if OPENSSL_WITH_PQC_ML_KEM_512
2114+
case EVP_PKEY_ML_KEM_512:
2115+
#endif
21212116
case EVP_PKEY_ML_KEM_768:
2122-
alg = EVP_pkey_ml_kem_768();
2123-
break;
21242117
case EVP_PKEY_ML_KEM_1024:
2125-
alg = EVP_pkey_ml_kem_1024();
2126-
break;
2118+
return kPqcMlKemSeedSize;
21272119
default:
2128-
return {};
2120+
unreachable();
2121+
}
2122+
}
2123+
2124+
#if OPENSSL_WITH_BORINGSSL_PQC
2125+
const EVP_PKEY_ALG* GetPqcSeedAlg(int id) {
2126+
switch (id) {
2127+
case EVP_PKEY_ML_DSA_44:
2128+
return EVP_pkey_ml_dsa_44();
2129+
case EVP_PKEY_ML_DSA_65:
2130+
return EVP_pkey_ml_dsa_65();
2131+
case EVP_PKEY_ML_DSA_87:
2132+
return EVP_pkey_ml_dsa_87();
2133+
case EVP_PKEY_ML_KEM_768:
2134+
return EVP_pkey_ml_kem_768();
2135+
case EVP_PKEY_ML_KEM_1024:
2136+
return EVP_pkey_ml_kem_1024();
2137+
default:
2138+
unreachable();
21292139
}
2130-
return EVPKeyPointer(EVP_PKEY_from_private_seed(alg, data.data, data.len));
2140+
}
21312141
#else
2132-
// ML-DSA and ML-KEM seeds use distinct OSSL_PARAM keys.
2133-
const char* param_name;
2142+
const char* GetPqcSeedParamName(int id) {
21342143
switch (id) {
21352144
case EVP_PKEY_ML_DSA_44:
21362145
case EVP_PKEY_ML_DSA_65:
21372146
case EVP_PKEY_ML_DSA_87:
2138-
param_name = OSSL_PKEY_PARAM_ML_DSA_SEED;
2139-
break;
2147+
return OSSL_PKEY_PARAM_ML_DSA_SEED;
21402148
case EVP_PKEY_ML_KEM_512:
21412149
case EVP_PKEY_ML_KEM_768:
21422150
case EVP_PKEY_ML_KEM_1024:
2143-
param_name = OSSL_PKEY_PARAM_ML_KEM_SEED;
2144-
break;
2151+
return OSSL_PKEY_PARAM_ML_KEM_SEED;
21452152
default:
2146-
return {};
2153+
unreachable();
21472154
}
2155+
}
2156+
#endif
21482157

2158+
EVPKeyPointer NewPqcKeyFromSeed(int id,
2159+
const Buffer<const unsigned char>& data) {
2160+
#if OPENSSL_WITH_BORINGSSL_PQC
2161+
return EVPKeyPointer(
2162+
EVP_PKEY_from_private_seed(GetPqcSeedAlg(id), data.data, data.len));
2163+
#else
21492164
OSSL_PARAM params[] = {
2150-
OSSL_PARAM_construct_octet_string(
2151-
param_name, const_cast<unsigned char*>(data.data), data.len),
2165+
OSSL_PARAM_construct_octet_string(GetPqcSeedParamName(id),
2166+
const_cast<unsigned char*>(data.data),
2167+
data.len),
21522168
OSSL_PARAM_END};
21532169

2154-
EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_id(id, nullptr);
2155-
if (ctx == nullptr) return {};
2170+
auto ctx = EVPKeyCtxPointer::NewFromID(id);
2171+
if (!ctx) return {};
21562172

21572173
EVP_PKEY* pkey = nullptr;
2158-
if (ctx == nullptr || EVP_PKEY_fromdata_init(ctx) <= 0 ||
2159-
EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_KEYPAIR, params) <= 0) {
2160-
EVP_PKEY_CTX_free(ctx);
2174+
if (EVP_PKEY_fromdata_init(ctx.get()) <= 0 ||
2175+
EVP_PKEY_fromdata(ctx.get(), &pkey, EVP_PKEY_KEYPAIR, params) <= 0) {
21612176
return {};
21622177
}
2163-
21642178
return EVPKeyPointer(pkey);
2165-
#endif // OPENSSL_IS_BORINGSSL
2179+
#endif
2180+
}
2181+
2182+
bool GetPqcSeed(EVP_PKEY* pkey, int id, const Buffer<unsigned char>& out) {
2183+
size_t len = out.len;
2184+
#if OPENSSL_WITH_BORINGSSL_PQC
2185+
return EVP_PKEY_get_private_seed(pkey, out.data, &len) == 1;
2186+
#else
2187+
return EVP_PKEY_get_octet_string_param(
2188+
pkey, GetPqcSeedParamName(id), out.data, out.len, &len) == 1;
2189+
#endif
2190+
}
2191+
} // namespace
2192+
2193+
EVPKeyPointer EVPKeyPointer::NewRawSeed(
2194+
int id, const Buffer<const unsigned char>& data) {
2195+
return NewPqcKeyFromSeed(id, data);
21662196
}
21672197
#endif
21682198

@@ -2290,62 +2320,14 @@ DataPointer EVPKeyPointer::rawPublicKey() const {
22902320
DataPointer EVPKeyPointer::rawSeed() const {
22912321
if (!pkey_) return {};
22922322

2293-
#ifdef OPENSSL_IS_BORINGSSL
2294-
size_t seed_len;
2295-
switch (id()) {
2296-
case EVP_PKEY_ML_DSA_44:
2297-
case EVP_PKEY_ML_DSA_65:
2298-
case EVP_PKEY_ML_DSA_87:
2299-
seed_len = 32; // ML-DSA uses 32-byte seeds
2300-
break;
2301-
case EVP_PKEY_ML_KEM_768:
2302-
case EVP_PKEY_ML_KEM_1024:
2303-
seed_len = 64; // ML-KEM uses 64-byte seeds
2304-
break;
2305-
default:
2306-
return {};
2307-
}
2308-
2309-
if (auto data = DataPointer::Alloc(seed_len)) {
2310-
const Buffer<unsigned char> buf = data;
2311-
size_t len = data.size();
2312-
if (EVP_PKEY_get_private_seed(get(), buf.data, &len) != 1) return {};
2313-
return data;
2314-
}
2315-
return {};
2316-
#else
2317-
// Determine seed length and parameter name based on key type
2318-
size_t seed_len;
2319-
const char* param_name;
2320-
2321-
switch (id()) {
2322-
case EVP_PKEY_ML_DSA_44:
2323-
case EVP_PKEY_ML_DSA_65:
2324-
case EVP_PKEY_ML_DSA_87:
2325-
seed_len = 32; // ML-DSA uses 32-byte seeds
2326-
param_name = OSSL_PKEY_PARAM_ML_DSA_SEED;
2327-
break;
2328-
case EVP_PKEY_ML_KEM_512:
2329-
case EVP_PKEY_ML_KEM_768:
2330-
case EVP_PKEY_ML_KEM_1024:
2331-
seed_len = 64; // ML-KEM uses 64-byte seeds
2332-
param_name = OSSL_PKEY_PARAM_ML_KEM_SEED;
2333-
break;
2334-
default:
2335-
unreachable();
2336-
}
2323+
const size_t seed_len = GetPqcSeedSize(id());
23372324

23382325
if (auto data = DataPointer::Alloc(seed_len)) {
23392326
const Buffer<unsigned char> buf = data;
2340-
size_t len = data.size();
2341-
2342-
if (EVP_PKEY_get_octet_string_param(
2343-
get(), param_name, buf.data, len, &seed_len) != 1)
2344-
return {};
2327+
if (!GetPqcSeed(get(), id(), buf)) return {};
23452328
return data;
23462329
}
23472330
return {};
2348-
#endif // OPENSSL_IS_BORINGSSL
23492331
}
23502332
#endif
23512333

0 commit comments

Comments
 (0)