Andrea Cosentino created CAMEL-25800:
----------------------------------------
Summary: camel-pqc - the hybrid KEM always uses P-256, so
ECDH_P384, ECDH_P521 and X448 cannot work
Key: CAMEL-25800
URL: https://issues.apache.org/jira/browse/CAMEL-25800
Project: Camel
Issue Type: Bug
Components: camel-pqc
Reporter: Andrea Cosentino
{{HybridKEM.encapsulate()}} derives the ephemeral classical key from the *key's
own* algorithm string rather than from the configured
{{classicalKEMAlgorithm}}, and hardcodes secp256r1 for every EC key.
{{HybridKEM.java:287-305}}:
{code:java}
private static KeyPair generateEphemeralKeyPair(String algorithm) throws
Exception {
KeyPairGenerator kpg;
if ("EC".equals(algorithm)) {
kpg = KeyPairGenerator.getInstance("EC");
// Default to P-256
kpg.initialize(new ECGenParameterSpec("secp256r1"),
SecureRandomHelper.getSecureRandom());
} else if ("X25519".equals(algorithm) || "XDH".equals(algorithm)) {
{code}
{{classicalPublicKey.getAlgorithm()}} returns just {{"EC"}} for every curve, so
the ephemeral key is always P-256. With a P-384 or P-521 static key,
{{classicalKA.doPhase(classicalPublicKey, true)}} ({{HybridKEM.java:97}}) fails
on mismatched domain parameters. The {{X448}} branch exists at {{:298-299}} but
nothing can select it, because the branch keys off the key's own algorithm
string rather than the configuration.
h3. The option is advertised
{{PQCConfiguration.java:85}}:
{code:java}
@UriParam(enums = "ECDH_P256,ECDH_P384,ECDH_P521,X25519,X448", ...)
{code}
and {{src/main/docs/pqc-hybrid.adoc:120-123}} documents {{ECDH_P384}},
{{ECDH_P521}} and {{X448}} as supported.
h3. The enum already has everything needed, unused
{{PQCClassicalKEMAlgorithms.getCurveSpec()}}, {{getSharedSecretSize()}} and
{{isECDH()}} have *zero callers* anywhere in {{src/main}} — verified by grep.
Only {{getKeyAlgorithm()}} is used, at {{PQCProducer.java:478-479}}. That is
precisely why this went unnoticed.
h3. Suggested fix
Thread the configured {{PQCClassicalKEMAlgorithms}} into
{{HybridKEM.encapsulate()}} and use {{getCurveSpec()}} to initialise the
ephemeral generator. Alternatively derive the curve from the static key's
{{ECParameterSpec}} instead of hardcoding one.
h3. Related: the hybrid KDF silently downgrades on an unrecognised name
{{HybridKEM.java:278-284}}:
{code:java}
private static HKDFBytesGenerator createHKDF(String algorithm) {
return switch (algorithm) {
case "HKDF-SHA256" -> new HKDFBytesGenerator(new SHA256Digest());
case "HKDF-SHA384" -> new HKDFBytesGenerator(new SHA384Digest());
case "HKDF-SHA512" -> new HKDFBytesGenerator(new SHA512Digest());
default -> new HKDFBytesGenerator(new SHA256Digest());
};
{code}
{{hybridKdfAlgorithm}} is a free-form {{String}}
({{PQCConfiguration.java:105}}) validated only by catalog metadata, never at
runtime. A typo such as {{HKDF-SHA-512}} silently yields SHA-256 instead of
failing. It should throw {{IllegalArgumentException}}.
h3. Test gap
No test anywhere in {{src/test}} references {{ECDH_P384}}, {{ECDH_P521}} or
{{X448}} — only {{ECDH_P256}} ({{PQCHybridKEMECDHMLKEMTest.java:68}}) and
{{X25519}} ({{PQCHybridKEMX25519MLKEMTest.java:68}}).
----
_Reported by Claude Code (AI agent) on behalf of [~oscerd]. Every code
reference was verified against commit {{7aae27315946}} on {{main}}._
--
This message was sent by Atlassian Jira
(v8.20.10#820010)