This is an automated email from the ASF dual-hosted git repository. acosentino pushed a commit to branch CAMEL-21993 in repository https://gitbox.apache.org/repos/asf/camel.git
commit 23e904af1d97853d4785e3201a6fcf4d332c9a93 Author: Andrea Cosentino <[email protected]> AuthorDate: Tue Apr 22 15:07:05 2025 +0200 CAMEL-21993 - Camel-PQC - Provide default KeyGenerator for KEM operations Signed-off-by: Andrea Cosentino <[email protected]> --- .../apache/camel/component/pqc/PQCComponent.java | 58 ++++++++------ .../pqc/crypto/PQCDefaultMLKEMMaterial.java | 55 ++++++++++++++ ...KEMGenerateEncapsulationAESNoAutowiredTest.java | 88 ++++++++++++++++++++++ 3 files changed, 178 insertions(+), 23 deletions(-) diff --git a/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCComponent.java b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCComponent.java index 20b474c21ee..66c2dc9e710 100644 --- a/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCComponent.java +++ b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCComponent.java @@ -20,10 +20,7 @@ import java.util.Map; import org.apache.camel.CamelContext; import org.apache.camel.Endpoint; -import org.apache.camel.component.pqc.crypto.PQCDefaultLMSMaterial; -import org.apache.camel.component.pqc.crypto.PQCDefaultMLDSAMaterial; -import org.apache.camel.component.pqc.crypto.PQCDefaultSLHDSAMaterial; -import org.apache.camel.component.pqc.crypto.PQCDefaultXMSSMaterial; +import org.apache.camel.component.pqc.crypto.*; import org.apache.camel.spi.Metadata; import org.apache.camel.spi.annotations.Component; import org.apache.camel.support.HealthCheckComponent; @@ -54,25 +51,40 @@ public class PQCComponent extends HealthCheckComponent { setProperties(endpoint, parameters); if (ObjectHelper.isEmpty(configuration.getSigner()) && ObjectHelper.isEmpty(configuration.getKeyPair())) { - switch (configuration.getSignatureAlgorithm()) { - case "MLDSA": - configuration.setSigner(PQCDefaultMLDSAMaterial.signer); - configuration.setKeyPair(PQCDefaultMLDSAMaterial.keyPair); - break; - case "SLHDSA": - configuration.setSigner(PQCDefaultSLHDSAMaterial.signer); - configuration.setKeyPair(PQCDefaultSLHDSAMaterial.keyPair); - break; - case "LMS": - configuration.setSigner(PQCDefaultLMSMaterial.signer); - configuration.setKeyPair(PQCDefaultLMSMaterial.keyPair); - break; - case "XMSS": - configuration.setSigner(PQCDefaultXMSSMaterial.signer); - configuration.setKeyPair(PQCDefaultXMSSMaterial.keyPair); - break; - default: - break; + if (ObjectHelper.isNotEmpty(configuration.getSignatureAlgorithm())) { + switch (configuration.getSignatureAlgorithm()) { + case "MLDSA": + configuration.setSigner(PQCDefaultMLDSAMaterial.signer); + configuration.setKeyPair(PQCDefaultMLDSAMaterial.keyPair); + break; + case "SLHDSA": + configuration.setSigner(PQCDefaultSLHDSAMaterial.signer); + configuration.setKeyPair(PQCDefaultSLHDSAMaterial.keyPair); + break; + case "LMS": + configuration.setSigner(PQCDefaultLMSMaterial.signer); + configuration.setKeyPair(PQCDefaultLMSMaterial.keyPair); + break; + case "XMSS": + configuration.setSigner(PQCDefaultXMSSMaterial.signer); + configuration.setKeyPair(PQCDefaultXMSSMaterial.keyPair); + break; + default: + break; + } + } + } + + if (ObjectHelper.isEmpty(configuration.getKeyGenerator()) && ObjectHelper.isEmpty(configuration.getKeyPair())) { + if (ObjectHelper.isNotEmpty(configuration.getKeyEncapsulationAlgorithm())) { + switch (configuration.getKeyEncapsulationAlgorithm()) { + case "MLKEM": + configuration.setKeyGenerator(PQCDefaultMLKEMMaterial.keyGenerator); + configuration.setKeyPair(PQCDefaultMLKEMMaterial.keyPair); + break; + default: + break; + } } } diff --git a/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/crypto/PQCDefaultMLKEMMaterial.java b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/crypto/PQCDefaultMLKEMMaterial.java new file mode 100644 index 00000000000..f4a30af33e0 --- /dev/null +++ b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/crypto/PQCDefaultMLKEMMaterial.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.pqc.crypto; + +import java.security.*; + +import javax.crypto.KeyGenerator; + +import org.apache.camel.component.pqc.PQCKeyEncapsulationAlgorithms; +import org.bouncycastle.jcajce.spec.MLKEMParameterSpec; + +public class PQCDefaultMLKEMMaterial { + + public static final KeyPair keyPair; + public static final KeyGenerator keyGenerator; + public static final KeyPairGenerator generator; + + static { + try { + generator = prepareKeyPair(); + keyPair = generator.generateKeyPair(); + keyGenerator = prepareKeyGenerator(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + protected static KeyPairGenerator prepareKeyPair() + throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException { + KeyPairGenerator kpg = KeyPairGenerator.getInstance(PQCKeyEncapsulationAlgorithms.MLKEM.getAlgorithm(), + PQCKeyEncapsulationAlgorithms.MLKEM.getBcProvider()); + kpg.initialize(MLKEMParameterSpec.ml_kem_512, new SecureRandom()); + return kpg; + } + + protected static KeyGenerator prepareKeyGenerator() throws NoSuchAlgorithmException, NoSuchProviderException { + KeyGenerator kg = KeyGenerator.getInstance(PQCKeyEncapsulationAlgorithms.MLKEM.getAlgorithm(), + PQCKeyEncapsulationAlgorithms.MLKEM.getBcProvider()); + return kg; + } +} diff --git a/components/camel-pqc/src/test/java/org/apache/camel/component/pqc/PQCMLKEMGenerateEncapsulationAESNoAutowiredTest.java b/components/camel-pqc/src/test/java/org/apache/camel/component/pqc/PQCMLKEMGenerateEncapsulationAESNoAutowiredTest.java new file mode 100644 index 00000000000..a55ac0ef3cb --- /dev/null +++ b/components/camel-pqc/src/test/java/org/apache/camel/component/pqc/PQCMLKEMGenerateEncapsulationAESNoAutowiredTest.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.pqc; + +import java.security.*; + +import org.apache.camel.EndpointInject; +import org.apache.camel.Produce; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.test.junit5.CamelTestSupport; +import org.bouncycastle.jcajce.SecretKeyWithEncapsulation; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider; +import org.bouncycastle.util.Arrays; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class PQCMLKEMGenerateEncapsulationAESNoAutowiredTest extends CamelTestSupport { + + @EndpointInject("mock:encapsulate") + protected MockEndpoint resultEncapsulate; + + @Produce("direct:encapsulate") + protected ProducerTemplate templateEncapsulate; + + @EndpointInject("mock:extract") + protected MockEndpoint resultExtract; + + public PQCMLKEMGenerateEncapsulationAESNoAutowiredTest() throws NoSuchAlgorithmException { + } + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:encapsulate").to( + "pqc:keyenc?operation=generateSecretKeyEncapsulation&symmetricKeyAlgorithm=AES&keyEncapsulationAlgorithm=MLKEM") + .to("mock:encapsulate") + .to("pqc:keyenc?operation=extractSecretKeyEncapsulation&symmetricKeyAlgorithm=AES&keyEncapsulationAlgorithm=MLKEM") + .to("mock:extract"); + } + }; + } + + @BeforeAll + public static void startup() throws Exception { + Security.addProvider(new BouncyCastleProvider()); + Security.addProvider(new BouncyCastlePQCProvider()); + } + + @Test + void testSignAndVerify() throws Exception { + resultEncapsulate.expectedMessageCount(1); + resultExtract.expectedMessageCount(1); + templateEncapsulate.sendBody("Hello"); + resultEncapsulate.assertIsSatisfied(); + assertNotNull(resultEncapsulate.getExchanges().get(0).getMessage().getBody(SecretKeyWithEncapsulation.class)); + assertEquals(PQCSymmetricAlgorithms.AES.getAlgorithm(), + resultEncapsulate.getExchanges().get(0).getMessage().getBody(SecretKeyWithEncapsulation.class).getAlgorithm()); + SecretKeyWithEncapsulation secEncrypted + = resultEncapsulate.getExchanges().get(0).getMessage().getBody(SecretKeyWithEncapsulation.class); + assertNotNull(resultExtract.getExchanges().get(0).getMessage().getBody(SecretKeyWithEncapsulation.class)); + assertEquals(PQCSymmetricAlgorithms.AES.getAlgorithm(), + resultExtract.getExchanges().get(0).getMessage().getBody(SecretKeyWithEncapsulation.class).getAlgorithm()); + SecretKeyWithEncapsulation secEncryptedExtracted + = resultExtract.getExchanges().get(0).getMessage().getBody(SecretKeyWithEncapsulation.class); + assertTrue(Arrays.areEqual(secEncrypted.getEncoded(), secEncryptedExtracted.getEncoded())); + } +}
