Andrea Cosentino created CAMEL-25798:
----------------------------------------
Summary: camel-pqc - generateSecretKeyEncapsulation labels the
secret key with the enum name, not the JCE name
Key: CAMEL-25798
URL: https://issues.apache.org/jira/browse/CAMEL-25798
Project: Camel
Issue Type: Bug
Components: camel-pqc
Reporter: Andrea Cosentino
The three KEM operations disagree about which name to stamp on the resulting
secret key.
{{generateEncapsulation}} passes the raw configuration value —
{{PQCProducer.java:671-678}}:
{code:java}
generator.init(
new KEMGenerateSpec(
keyPair.getPublic(),
getEndpoint().getConfiguration().getSymmetricKeyAlgorithm(),
{code}
{{extractEncapsulation}} maps it through the enum —
{{PQCProducer.java:700-704}}:
{code:java}
PQCSymmetricAlgorithms.valueOf(getConfiguration().getSymmetricKeyAlgorithm()).getAlgorithm(),
{code}
and {{extractSecretKeyFromEncapsulation}} does the same, with a comment stating
exactly the rule that {{generateEncapsulation}} breaks —
{{PQCProducer.java:723-726}}:
{code:java}
// Use the mapped JCE algorithm name (as extractEncapsulation does),
not the raw enum name: for algorithms
// whose enum name differs from the JCE name (for example GOST3412_2015
-> GOST3412-2015) the raw name is not a
// resolvable cipher algorithm, so the restored key would carry an
unusable algorithm label
{code}
h3. Which algorithms are affected
Two of the eighteen constants differ from their JCE name —
{{PQCSymmetricAlgorithms.java:32,39}}:
{code:java}
GOST3412_2015("GOST3412-2015"),
DESEDE("DESede");
{code}
So for those two the generate side emits a {{SecretKeyWithEncapsulation}} whose
{{getAlgorithm()}} is {{DESEDE}} / {{GOST3412_2015}} while the extract side
emits {{DESede}} / {{GOST3412-2015}}. The generate-side label is not a
resolvable cipher name, so handing that key to
{{Cipher.getInstance(key.getAlgorithm())}} or to {{CryptoDataFormat}} fails,
and the two ends of one KEM exchange disagree about the key's identity.
h3. Existing tests encode both answers
{{PQCMLKEMGenerateEncapsulationCryptoRoundTripDESedeTest.java:96-97}} asserts
the wrong one:
{code:java}
assertEquals("DESEDE",
resultEncapsulate.getExchanges().get(0).getMessage().getBody(SecretKeyWithEncapsulation.class).getAlgorithm());
{code}
while {{PQCExtractSecretKeyAlgorithmNameTest.java:126}} asserts
{{assertEquals("DESede", restored.getAlgorithm());}} for the same configured
algorithm. The first test needs updating with the fix.
h3. Related: a missing guard on the same method
Both extract operations reject an empty {{symmetricKeyAlgorithm}} —
{{PQCProducer.java:693-695}}:
{code:java}
if
(ObjectHelper.isEmpty(getConfiguration().getSymmetricKeyAlgorithm())) {
throw new IllegalArgumentException("Symmetric Algorithm needs to be
specified");
}
{code}
and both hybrid KEM paths guard it too ({{:834-836}}, {{:878-880}}).
{{generateEncapsulation}} ({{:667-685}}) is the single unguarded sibling and
passes the possibly-null value straight into {{new KEMGenerateSpec(...)}}.
{{validateSymmetricKeyLength}} does not cover it either — it returns early when
the algorithm is empty ({{:1241-1243}}).
h3. Suggested fix
Use {{PQCSymmetricAlgorithms.valueOf(...).getAlgorithm()}} in
{{generateEncapsulation}}, add the missing guard, update the DESede test, and
add a test that asserts the generate-side and extract-side {{getAlgorithm()}}
agree (no GOST3412_2015 round-trip exists at all today).
----
_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)