You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@camel.apache.org by "Andrea Cosentino (Jira)" <ji...@apache.org> on 2026/10/19 08:57:00 UTC

[jira] [Assigned] (CAMEL-25803) camel-pqc - the hybrid wire format v2 is documented but not implemented

     [ https://issues.apache.org/jira/browse/CAMEL-25803?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Andrea Cosentino reassigned CAMEL-25803:
----------------------------------------

    Assignee: Andrea Cosentino

> camel-pqc - the hybrid wire format v2 is documented but not implemented
> -----------------------------------------------------------------------
>
>                 Key: CAMEL-25803
>                 URL: https://issues.apache.org/jira/browse/CAMEL-25803
>             Project: Camel
>          Issue Type: Bug
>          Components: camel-pqc
>            Reporter: Andrea Cosentino
>            Assignee: Andrea Cosentino
>            Priority: Major
>
> {{src/main/docs/pqc-hybrid.adoc}} documents a self-describing "wire format v2" for hybrid signatures and encapsulations, in a dedicated hundred-line section. The code implements only v1.
> h3. What the documentation claims
> {{pqc-hybrid.adoc:104}}:
> {noformat}
> Since Camel 4.19, hybrid signatures use wire format v2 which includes magic bytes, version, and algorithm identifiers (see <<Wire Format v2 and Algorithm Identification>>). The v1 format `[4 bytes: classical sig length][classical sig][pqc sig]` is still accepted on input for backward compatibility.
> {noformat}
> The same sentence appears for encapsulations at {{:217}}, with the format laid out under {{== Wire Format v2 and Algorithm Identification}} ({{:289}}) and {{=== Wire Format v2 Layout}} ({{:364}}).
> h3. What the code does
> {{HybridSignature.java:73-74}}:
> {code:java}
>         // Combine: [4 bytes length][classical sig][pqc sig]
>         return combineSignatures(classicalSignature, pqcSignature);
> {code}
> That is the v1 format. {{HybridKEM}} is the same. There are no magic bytes, no version byte and no algorithm identifiers anywhere in either class.
> h3. {{PQCAlgorithmId}} is public, documented and referenced by nothing
> {{PQCAlgorithmId.java:36}} declares a public enum of about fifty constants whose Javadoc says it is "used in the wire format header to make hybrid cryptographic outputs self-describing". A repository-wide grep finds *zero* references outside its own file — no production caller, no test, only the adoc. It is untested public API surface.
> It is also internally inconsistent with the algorithm enums, so {{fromJcaName()}} returns {{UNKNOWN}} for the real JCE names. {{PQCAlgorithmId.java:77}}:
> {code:java}
>     FRODO(0x0406, "FRODO"),
> {code}
> versus {{PQCKeyEncapsulationAlgorithms.java:29}}:
> {code:java}
>     FRODO("FrodoKEM", "BC"),
> {code}
> Same for {{KYBER}} ({{"KYBER"}} vs {{"ML-KEM"}}), {{DILITHIUM}} and {{SPHINCSPLUS}}. The enum is also missing HSS and seven {{PQCSymmetricAlgorithms}} constants, and carries a {{PICNIC}} constant that exists in no other enum (Picnic was removed from Bouncy Castle).
> h3. The documented API does not compile
> {{pqc-hybrid.adoc:357}}:
> {code:java}
> PQCAlgorithmId classical = components.classicalAlgorithmId(); // e.g. SHA256_WITH_ECDSA
> {code}
> {{HybridSignature.java:216}}:
> {code:java}
>     public record HybridSignatureComponents(byte[] classicalSignature, byte[] pqcSignature) {
> {code}
> There is no {{classicalAlgorithmId()}} accessor. A user following the published snippet gets a compile error.
> h3. Decision needed
> Either implement v2 — magic bytes, version, algorithm ids, with v1 still accepted on input as the docs already promise — and give {{HybridSignatureComponents}} the documented accessors; or delete {{PQCAlgorithmId}} and the entire v2 section of the documentation and describe the v1 format that actually ships. Shipping a documented format that does not exist is worse than either.
> If v2 is implemented, it would also be the natural place to fix the related gap in {{PQCDataFormat}} ({{:182-185}}), whose output carries neither the symmetric algorithm nor the key length even though both can be overridden per message via {{CamelPQCSymmetricAlgorithm}} — a mismatch currently surfaces as a misleading "may have been tampered with" at {{:240-243}}.
> h3. Note on the combiner itself
> For the record, the hybrid construction is sound in kind and should not change as part of this: both secrets are fed through HKDF ({{HybridKEM.java:260-266}}, not XOR and not single-secret), {{HybridSignature.verify}} correctly uses {{&&}} ({{:118}}), and the v1 wire format is length-prefixed and bounds-checked on parse. Two smaller hardening items worth folding in: the HKDF {{salt}} is {{null}} and {{info}} is only the cipher name, where the established combiners also bind the PQ ciphertext and the public keys; and {{info.getBytes()}} uses the platform default charset inside a key derivation.
> h3. Test gap
> The only negative hybrid-signature test tampers with the data, which invalidates *both* signatures — it would pass identically if the verification operator were {{||}}. A test that forges exactly one half (valid classical signature spliced onto a garbage PQC signature) is the highest-value missing test in this area.
> ----
> _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)