oscerd opened a new pull request, #28090: URL: https://github.com/apache/camel/pull/28090
Fixes [CAMEL-25800](https://issues.apache.org/jira/browse/CAMEL-25800). ## Problem `HybridKEM.encapsulate()` generated the classical ephemeral key from the recipient key's *algorithm name*: ```java KeyPair ephemeralKeyPair = generateEphemeralKeyPair(classicalPublicKey.getAlgorithm()); ... if ("EC".equals(algorithm)) { kpg = KeyPairGenerator.getInstance("EC"); // Default to P-256 kpg.initialize(new ECGenParameterSpec("secp256r1"), SecureRandomHelper.getSecureRandom()); ``` `getAlgorithm()` returns a bare `EC` for *every* curve, so the ephemeral key was always secp256r1. Against a P-384 or P-521 recipient key, `classicalKA.doPhase(classicalPublicKey, true)` fails on mismatched domain parameters. Both curves are advertised — `@UriParam(enums = "ECDH_P256,ECDH_P384,ECDH_P521,X25519,X448", ...)` — and documented in `pqc-hybrid.adoc`. `PQCClassicalKEMAlgorithms.getCurveSpec()`, `getSharedSecretSize()` and `isECDH()` have zero callers anywhere in `src/main`, which is why this went unnoticed. ### Correction to the original report The Jira initially also claimed X448 was broken. **It is not**, and I have amended the ticket. `BCXDHPublicKey.getAlgorithm()` returns the concrete name (`X25519` / `X448`) unless `org.bouncycastle.emulate.oracle` is set, so that branch was always reachable. The parameterised test proves it — against unpatched code, `secp256r1` and `X448` pass while `secp384r1` and `secp521r1` fail. There is a genuine but narrower X448 case: when a key reports only the generic `XDH` (Oracle emulation, or a SunEC `XECPublicKey`), `"XDH".equals(algorithm)` mapped unconditionally to X25519. ## Fix The group is taken from the recipient key itself rather than from its name: - `ECPublicKey.getParams()` for EC — works for both BouncyCastle and SunEC keys, and covers every curve; - `XECPublicKey.getParams()` when the provider exposes it; - an `XDH` key that exposes neither is rejected with `InvalidKeyException` instead of being silently paired with an X25519 ephemeral key. `reconstructPublicKey()` no longer pins `X25519` for a generic `XDH` key — the X.509 encoding carries its own parameters, so the family key factory decodes both groups. Two items in the KDF path, folded in because they sit in the same method: - an unrecognised `hybridKdfAlgorithm` now throws rather than silently falling back to `HKDF-SHA256`. The old behaviour meant a typo on one side only still "succeeded" on both ends while deriving the key with different digests; - the HKDF `info` string is encoded as UTF-8 instead of the platform default charset. ## Tests New `HybridKEMCurveTest`: - `hybridKemRoundTripsOnEveryNistCurve` — parameterised over secp256r1 / secp384r1 / secp521r1, asserting sender and recipient derive the same secret; - `x448RoundTrips` — guards the X448 path that already worked, so it stays working; - `anUnknownKdfAlgorithmIsRejected`. Against `main` this is 1 failure + 2 errors out of 5; with the change all pass. Full `camel-pqc` build is green: 244 tests, 0 failures, no regenerated-file drift. ## Upgrade guide Added a 4.24 entry for the `hybridKdfAlgorithm` rejection, which is the one user-visible behaviour change. --- _Reported, analysed and fixed by Claude Code (AI agent) on behalf of @oscerd._ 🤖 Generated with [Claude Code](https://claude.com/claude-code) -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
