Skip to content

Add PQC (ML-DSA and ML-KEM) support for XML Digital Signature and Enc… - #645

Open
ffang wants to merge 1 commit into
apache:mainfrom
ffang:PQC
Open

Add PQC (ML-DSA and ML-KEM) support for XML Digital Signature and Enc…#645
ffang wants to merge 1 commit into
apache:mainfrom
ffang:PQC

Conversation

@ffang

@ffang ffang commented Aug 7, 2026

Copy link
Copy Markdown

…ryption

  • ML-DSA (FIPS 204): signature algorithm constants for ML-DSA-44/65/87, JCA mappings and whitelist URIs in XMLSignature, DOM and JSR-105 support.

  • ML-KEM (FIPS 203): key transport support using the W3C "XML Security: Generic Hybrid Cipher" structure (https://www.w3.org/TR/xmlsec-generic-hybrid/, closing SANTUARIO-633): KeyUtils.kemEncapsulate/kemDecapsulate perform real javax.crypto.KEM (JEP 452) encapsulation/decapsulation plus HKDF key derivation, with the AES-KeyWrap output and KEM encapsulation concatenated into CipherValue. New ALGO_ID_KEYTRANSPORT_GENERIC_HYBRID top-level algorithm and GenericHybridCipherMethod/KeyEncapsulationMethod/ DataEncapsulationMethod XML structure, wired into both the DOM XMLCipher and STAX (XMLEncryptOutputProcessor/XMLEncryptedKeyInputHandler) paths.

  • Both features require BouncyCastle 1.84+ and skip gracefully without it; ML-KEM additionally requires Java 21+ for javax.crypto.KEM, accessed via reflection so the module still compiles under its Java 11 target.

Algorithm URIs follow the RFC 9231 provisional naming pattern under http://www.w3.org/tbd# per draft-eastlake-rfc9231bis-xmlsec-uris, pending final URI assignment.

…ryption

- ML-DSA (FIPS 204): signature algorithm constants for ML-DSA-44/65/87,
  JCA mappings and whitelist URIs in XMLSignature, DOM and JSR-105 support.

- ML-KEM (FIPS 203): key transport support using the W3C "XML Security:
  Generic Hybrid Cipher" structure (https://www.w3.org/TR/xmlsec-generic-hybrid/,
  closing SANTUARIO-633): KeyUtils.kemEncapsulate/kemDecapsulate perform real
  javax.crypto.KEM (JEP 452) encapsulation/decapsulation plus HKDF key
  derivation, with the AES-KeyWrap output and KEM encapsulation concatenated
  into CipherValue. New ALGO_ID_KEYTRANSPORT_GENERIC_HYBRID top-level
  algorithm and GenericHybridCipherMethod/KeyEncapsulationMethod/
  DataEncapsulationMethod XML structure, wired into both the DOM XMLCipher
  and STAX (XMLEncryptOutputProcessor/XMLEncryptedKeyInputHandler) paths.

- Both features require BouncyCastle 1.84+ and skip gracefully without it;
  ML-KEM additionally requires Java 21+ for javax.crypto.KEM, accessed via
  reflection so the module still compiles under its Java 11 target.

Algorithm URIs follow the RFC 9231 provisional naming pattern under
http://www.w3.org/tbd# per draft-eastlake-rfc9231bis-xmlsec-uris, pending
final URI assignment.
if (provider == null) {
String providerId = JCEMapper.getProviderId();
if (providerId == null) {
this.signatureAlgorithm = Signature.getInstance(algorithmID);
if (provider == null) {
String providerId = JCEMapper.getProviderId();
if (providerId == null) {
this.signatureAlgorithm = Signature.getInstance(algorithmID);
if (providerId == null) {
this.signatureAlgorithm = Signature.getInstance(algorithmID);
} else {
this.signatureAlgorithm = Signature.getInstance(algorithmID, providerId);
if (providerId == null) {
this.signatureAlgorithm = Signature.getInstance(algorithmID);
} else {
this.signatureAlgorithm = Signature.getInstance(algorithmID, providerId);
this.signatureAlgorithm = Signature.getInstance(algorithmID, providerId);
}
} else {
this.signatureAlgorithm = Signature.getInstance(algorithmID, provider);
this.signatureAlgorithm = Signature.getInstance(algorithmID, providerId);
}
} else {
this.signatureAlgorithm = Signature.getInstance(algorithmID, provider);
KeyUtils.KemDecapsulation kemResult = KeyUtils.kemDecapsulate(
(PrivateKey) wrapKeyToken, kemAlgorithm, encryptedBytes, kdp);
String jceWrapId = JCEMapper.translateURItoJCEID(dataEncapsulationAlgorithm);
Cipher cipher = Cipher.getInstance(jceWrapId);
KeyUtils.KemDecapsulation kemResult = KeyUtils.kemDecapsulate(
(PrivateKey) wrapKeyToken, kemAlgorithm, encryptedBytes, kdp);
String jceWrapId = JCEMapper.translateURItoJCEID(dataEncapsulationAlgorithm);
Cipher cipher = Cipher.getInstance(jceWrapId);
KeyUtils.KemEncapsulation kemResult = KeyUtils.kemEncapsulate(pubKey, kemAlgorithm, kdfParams);
try {
String jceWrapId = JCEMapper.translateURItoJCEID(dataEncapsulationAlgorithm);
Cipher wrapCipher = Cipher.getInstance(jceWrapId);
KeyUtils.KemEncapsulation kemResult = KeyUtils.kemEncapsulate(pubKey, kemAlgorithm, kdfParams);
try {
String jceWrapId = JCEMapper.translateURItoJCEID(dataEncapsulationAlgorithm);
Cipher wrapCipher = Cipher.getInstance(jceWrapId);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants