diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/NamedGroupInfo.java b/tls/src/main/java/org/bouncycastle/jsse/provider/NamedGroupInfo.java index 18611a9294..c71e37d338 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/NamedGroupInfo.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/NamedGroupInfo.java @@ -78,6 +78,10 @@ private enum All OQS_mlkem512(NamedGroup.OQS_mlkem512, "ML-KEM"), OQS_mlkem768(NamedGroup.OQS_mlkem768, "ML-KEM"), OQS_mlkem1024(NamedGroup.OQS_mlkem1024, "ML-KEM"), + OQS_secp256Mlkem512(NamedGroup.OQS_secp256Mlkem512, "ML-KEM"), + OQS_secp384Mlkem768(NamedGroup.OQS_secp384Mlkem768, "ML-KEM"), + OQS_secp521Mlkem1024(NamedGroup.OQS_secp521Mlkem1024, "ML-KEM"), + DRAFT_mlkem768(NamedGroup.DRAFT_mlkem768, "ML-KEM"), DRAFT_mlkem1024(NamedGroup.DRAFT_mlkem1024, "ML-KEM"); diff --git a/tls/src/main/java/org/bouncycastle/tls/NamedGroup.java b/tls/src/main/java/org/bouncycastle/tls/NamedGroup.java index 2e4bf4d510..facf99faf1 100644 --- a/tls/src/main/java/org/bouncycastle/tls/NamedGroup.java +++ b/tls/src/main/java/org/bouncycastle/tls/NamedGroup.java @@ -108,6 +108,12 @@ public class NamedGroup public static final int OQS_mlkem768 = 0x0248; /** Experimental API (unstable): unofficial value from Open Quantum Safe project. */ public static final int OQS_mlkem1024 = 0x0249; + /** Experimental API (unstable): unofficial value from Open Quantum Safe project. */ + public static final int OQS_secp256Mlkem512 = 0x2F47; + /** Experimental API (unstable): unofficial value from Open Quantum Safe project. */ + public static final int OQS_secp384Mlkem768 = 0x2F48; + /** Experimental API (unstable): unofficial value from Open Quantum Safe project. */ + public static final int OQS_secp521Mlkem1024 = 0x2F49; /* * draft-connolly-tls-mlkem-key-agreement-01 @@ -310,6 +316,12 @@ public static String getKemName(int namedGroup) case OQS_mlkem1024: case DRAFT_mlkem1024: return "ML-KEM-1024"; + case OQS_secp256Mlkem512: + return "secp256-ML-KEM-512"; + case OQS_secp384Mlkem768: + return "secp384-ML-KEM-768"; + case OQS_secp521Mlkem1024: + return "secp521-ML-KEM-1024"; default: return null; } @@ -376,7 +388,13 @@ public static String getName(int namedGroup) return "OQS_mlkem768"; case OQS_mlkem1024: return "OQS_mlkem1024"; - case DRAFT_mlkem768: + case OQS_secp256Mlkem512: + return "OQS_secp256Mlkem512"; + case OQS_secp384Mlkem768: + return "OQS_secp384Mlkem768"; + case OQS_secp521Mlkem1024: + return "OQS_secp521Mlkem1024"; + case DRAFT_mlkem768: return "DRAFT_mlkem768"; case DRAFT_mlkem1024: return "DRAFT_mlkem1024"; @@ -497,6 +515,9 @@ public static boolean refersToASpecificKem(int namedGroup) case OQS_mlkem512: case OQS_mlkem768: case OQS_mlkem1024: + case OQS_secp256Mlkem512: + case OQS_secp384Mlkem768: + case OQS_secp521Mlkem1024: case DRAFT_mlkem768: case DRAFT_mlkem1024: return true; diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java index 5cf7cd07d9..95b107fc2a 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java @@ -215,7 +215,15 @@ public TlsECDomain createECDomain(TlsECConfig ecConfig) public TlsKemDomain createKemDomain(TlsKemConfig kemConfig) { - return new BcTlsMLKemDomain(this, kemConfig); + switch (kemConfig.getNamedGroup()) + { + case NamedGroup.OQS_secp256Mlkem512: + case NamedGroup.OQS_secp384Mlkem768: + case NamedGroup.OQS_secp521Mlkem1024: + return new BcTlsEcdhMlkemDomain(this, kemConfig); + default: + return new BcTlsMLKemDomain(this, kemConfig); + } } public TlsNonceGenerator createNonceGenerator(byte[] additionalSeedMaterial) diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsECDomain.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsECDomain.java index 0562963d06..ddd383018d 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsECDomain.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsECDomain.java @@ -27,6 +27,19 @@ */ public class BcTlsECDomain implements TlsECDomain { + public int getPublicKeyByteLength() + { + return (((domainParameters.getCurve().getFieldSize() + 7) / 8) * 2) + 1; + } + + public byte[] calculateECDHAgreementBytes(ECPrivateKeyParameters privateKey, ECPublicKeyParameters publicKey) + { + ECDHBasicAgreement basicAgreement = new ECDHBasicAgreement(); + basicAgreement.init(privateKey); + BigInteger agreementValue = basicAgreement.calculateAgreement(publicKey); + return BigIntegers.asUnsignedByteArray(basicAgreement.getFieldSize(), agreementValue); + } + public static BcTlsSecret calculateECDHAgreement(BcTlsCrypto crypto, ECPrivateKeyParameters privateKey, ECPublicKeyParameters publicKey) { diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsEcdhMlkem.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsEcdhMlkem.java new file mode 100644 index 0000000000..6494c8acd6 --- /dev/null +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsEcdhMlkem.java @@ -0,0 +1,74 @@ +package org.bouncycastle.tls.crypto.impl.bc; + +import java.io.IOException; + +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.SecretWithEncapsulation; +import org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import org.bouncycastle.crypto.params.ECPublicKeyParameters; +import org.bouncycastle.pqc.crypto.crystals.kyber.KyberPrivateKeyParameters; +import org.bouncycastle.pqc.crypto.crystals.kyber.KyberPublicKeyParameters; +import org.bouncycastle.tls.crypto.TlsAgreement; +import org.bouncycastle.tls.crypto.TlsSecret; +import org.bouncycastle.util.Arrays; + +public class BcTlsEcdhMlkem implements TlsAgreement +{ + protected final BcTlsEcdhMlkemDomain domain; + + protected AsymmetricCipherKeyPair ecLocalKeyPair; + protected ECPublicKeyParameters ecPeerPublicKey; + protected AsymmetricCipherKeyPair kyberLocalKeyPair; + protected KyberPublicKeyParameters kyberPeerPublicKey; + protected byte[] kyberCiphertext; + protected byte[] kyberSecret; + protected TlsSecret secret; + + public BcTlsEcdhMlkem(BcTlsEcdhMlkemDomain domain) + { + this.domain = domain; + } + + public byte[] generateEphemeral() throws IOException + { + this.ecLocalKeyPair = domain.getEcDomain().generateKeyPair(); + byte[] ecPublickey = domain.getEcDomain().encodePublicKey((ECPublicKeyParameters)ecLocalKeyPair.getPublic()); + if (domain.isServer()) + { + return Arrays.concatenate(ecPublickey, kyberCiphertext); + } + else + { + this.kyberLocalKeyPair = domain.getMlkemDomain().generateKeyPair(); + byte[] kyberPublicKey = domain.getMlkemDomain().encodePublicKey((KyberPublicKeyParameters)kyberLocalKeyPair.getPublic()); + return Arrays.concatenate(ecPublickey, kyberPublicKey); + } + } + + public void receivePeerValue(byte[] peerValue) throws IOException + { + this.ecPeerPublicKey = domain.getEcDomain().decodePublicKey(Arrays.copyOf(peerValue, domain.getEcDomain().getPublicKeyByteLength())); + byte[] kyberValue = Arrays.copyOfRange(peerValue, domain.getEcDomain().getPublicKeyByteLength(), peerValue.length); + if (domain.isServer()) + { + this.kyberPeerPublicKey = domain.getMlkemDomain().decodePublicKey(kyberValue); + SecretWithEncapsulation encap = domain.getMlkemDomain().encapsulate(kyberPeerPublicKey); + kyberCiphertext = encap.getEncapsulation(); + kyberSecret = encap.getSecret(); + } + else + { + this.kyberCiphertext = Arrays.clone(kyberValue); + } + } + + public TlsSecret calculateSecret() throws IOException + { + byte[] ecSecret = domain.getEcDomain().calculateECDHAgreementBytes((ECPrivateKeyParameters)ecLocalKeyPair.getPrivate(), ecPeerPublicKey); + if (!domain.isServer()) + { + kyberSecret = domain.getMlkemDomain().decapsulate((KyberPrivateKeyParameters) kyberLocalKeyPair.getPrivate(), kyberCiphertext); + } + return domain.adoptLocalSecret(Arrays.concatenate(ecSecret, kyberSecret)); + } +} diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsEcdhMlkemDomain.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsEcdhMlkemDomain.java new file mode 100644 index 0000000000..df44ec018a --- /dev/null +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsEcdhMlkemDomain.java @@ -0,0 +1,63 @@ +package org.bouncycastle.tls.crypto.impl.bc; + +import org.bouncycastle.tls.NamedGroup; +import org.bouncycastle.tls.crypto.TlsAgreement; +import org.bouncycastle.tls.crypto.TlsECConfig; +import org.bouncycastle.tls.crypto.TlsKemConfig; +import org.bouncycastle.tls.crypto.TlsKemDomain; + +public class BcTlsEcdhMlkemDomain implements TlsKemDomain +{ + protected final BcTlsCrypto crypto; + protected final boolean isServer; + private final BcTlsECDomain ecDomain; + private final BcTlsMLKemDomain mlkemDomain; + + public BcTlsEcdhMlkemDomain(BcTlsCrypto crypto, TlsKemConfig kemConfig) + { + this.crypto = crypto; + this.ecDomain = getBcTlsECDomain(crypto, kemConfig); + this.mlkemDomain = new BcTlsMLKemDomain(crypto, kemConfig); + this.isServer = kemConfig.isServer(); + } + + public BcTlsSecret adoptLocalSecret(byte[] secret) + { + return crypto.adoptLocalSecret(secret); + } + + public TlsAgreement createKem() + { + return new BcTlsEcdhMlkem(this); + } + + public boolean isServer() + { + return isServer; + } + + public BcTlsECDomain getEcDomain() + { + return ecDomain; + } + + public BcTlsMLKemDomain getMlkemDomain() + { + return mlkemDomain; + } + + private BcTlsECDomain getBcTlsECDomain(BcTlsCrypto crypto, TlsKemConfig kemConfig) + { + switch (kemConfig.getNamedGroup()) + { + case NamedGroup.OQS_secp256Mlkem512: + return new BcTlsECDomain(crypto, new TlsECConfig(NamedGroup.secp256r1)); + case NamedGroup.OQS_secp384Mlkem768: + return new BcTlsECDomain(crypto, new TlsECConfig(NamedGroup.secp384r1)); + case NamedGroup.OQS_secp521Mlkem1024: + return new BcTlsECDomain(crypto, new TlsECConfig(NamedGroup.secp521r1)); + default: + return null; + } + } +} diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsMLKem.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsMLKem.java index 4d15220971..41d8a067f8 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsMLKem.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsMLKem.java @@ -47,7 +47,7 @@ public void receivePeerValue(byte[] peerValue) throws IOException } else { - this.secret = domain.decapsulate(privateKey, peerValue); + this.secret = domain.adoptLocalSecret(domain.decapsulate(privateKey, peerValue)); this.privateKey = null; } } diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsMLKemDomain.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsMLKemDomain.java index 2025e70b1a..7b5369eed2 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsMLKemDomain.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsMLKemDomain.java @@ -21,11 +21,14 @@ protected static KyberParameters getKyberParameters(int namedGroup) switch (namedGroup) { case NamedGroup.OQS_mlkem512: + case NamedGroup.OQS_secp256Mlkem512: return KyberParameters.kyber512; case NamedGroup.OQS_mlkem768: + case NamedGroup.OQS_secp384Mlkem768: case NamedGroup.DRAFT_mlkem768: return KyberParameters.kyber768; case NamedGroup.OQS_mlkem1024: + case NamedGroup.OQS_secp521Mlkem1024: case NamedGroup.DRAFT_mlkem1024: return KyberParameters.kyber1024; default: @@ -54,11 +57,10 @@ public TlsAgreement createKem() return new BcTlsMLKem(this); } - public BcTlsSecret decapsulate(KyberPrivateKeyParameters privateKey, byte[] ciphertext) + public byte[] decapsulate(KyberPrivateKeyParameters privateKey, byte[] ciphertext) { KyberKEMExtractor kemExtract = new KyberKEMExtractor(privateKey); - byte[] secret = kemExtract.extractSecret(ciphertext); - return adoptLocalSecret(secret); + return kemExtract.extractSecret(ciphertext); } public KyberPublicKeyParameters decodePublicKey(byte[] encoding) diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCrypto.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCrypto.java index 5c39e1a115..7347603b11 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCrypto.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCrypto.java @@ -442,6 +442,12 @@ else if (NamedGroup.refersToASpecificKem(namedGroup)) { switch (namedGroup) { + case NamedGroup.OQS_secp256Mlkem512: + return ECUtil.getAlgorithmParameters(this, NamedGroup.getCurveName(NamedGroup.secp256r1)); + case NamedGroup.OQS_secp384Mlkem768: + return ECUtil.getAlgorithmParameters(this, NamedGroup.getCurveName(NamedGroup.secp384r1)); + case NamedGroup.OQS_secp521Mlkem1024: + return ECUtil.getAlgorithmParameters(this, NamedGroup.getCurveName(NamedGroup.secp521r1)); /* * TODO[tls-kem] Return AlgorithmParameters to check against disabled algorithms? */ @@ -848,7 +854,15 @@ public TlsECDomain createECDomain(TlsECConfig ecConfig) public TlsKemDomain createKemDomain(TlsKemConfig kemConfig) { - return new JceTlsMLKemDomain(this, kemConfig); + switch (kemConfig.getNamedGroup()) + { + case NamedGroup.OQS_secp256Mlkem512: + case NamedGroup.OQS_secp384Mlkem768: + case NamedGroup.OQS_secp521Mlkem1024: + return new JceTlsEcdhMlkemDomain(this, kemConfig); + default: + return new JceTlsMLKemDomain(this, kemConfig); + } } public TlsSecret hkdfInit(int cryptoHashAlgorithm) diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsECDomain.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsECDomain.java index 8c332cbf04..d394618d2d 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsECDomain.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsECDomain.java @@ -52,6 +52,23 @@ public JceTlsECDomain(JcaTlsCrypto crypto, TlsECConfig ecConfig) throw new IllegalArgumentException("NamedGroup not supported: " + NamedGroup.getText(namedGroup)); } + public int getPublicKeyByteLength() + { + return (((ecCurve.getFieldSize() + 7) / 8) * 2) + 1; + } + + public byte[] calculateECDHAgreementBytes(PrivateKey privateKey, PublicKey publicKey) throws IOException + { + try + { + return crypto.calculateKeyAgreement("ECDH", privateKey, publicKey, "TlsPremasterSecret"); + } + catch (GeneralSecurityException e) + { + throw new TlsCryptoException("cannot calculate secret", e); + } + } + public JceTlsSecret calculateECDHAgreement(PrivateKey privateKey, PublicKey publicKey) throws IOException { diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsEcdhMlkem.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsEcdhMlkem.java new file mode 100644 index 0000000000..5b55c59030 --- /dev/null +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsEcdhMlkem.java @@ -0,0 +1,76 @@ +package org.bouncycastle.tls.crypto.impl.jcajce; + +import java.io.IOException; +import java.security.KeyPair; +import java.security.PublicKey; + +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.SecretWithEncapsulation; +import org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import org.bouncycastle.crypto.params.ECPublicKeyParameters; +import org.bouncycastle.pqc.crypto.crystals.kyber.KyberPrivateKeyParameters; +import org.bouncycastle.pqc.crypto.crystals.kyber.KyberPublicKeyParameters; +import org.bouncycastle.tls.crypto.TlsAgreement; +import org.bouncycastle.tls.crypto.TlsSecret; +import org.bouncycastle.util.Arrays; + +public class JceTlsEcdhMlkem implements TlsAgreement +{ + protected final JceTlsEcdhMlkemDomain domain; + + protected KeyPair ecLocalKeyPair; + protected PublicKey ecPeerPublicKey; + protected AsymmetricCipherKeyPair kyberLocalKeyPair; + protected KyberPublicKeyParameters kyberPeerPublicKey; + protected byte[] kyberCiphertext; + protected byte[] kyberSecret; + protected TlsSecret secret; + + public JceTlsEcdhMlkem(JceTlsEcdhMlkemDomain domain) + { + this.domain = domain; + } + + public byte[] generateEphemeral() throws IOException + { + this.ecLocalKeyPair = domain.getEcDomain().generateKeyPair(); + byte[] ecPublickey = domain.getEcDomain().encodePublicKey(ecLocalKeyPair.getPublic()); + if (domain.isServer()) + { + return Arrays.concatenate(ecPublickey, kyberCiphertext); + } + else + { + this.kyberLocalKeyPair = domain.getMlkemDomain().generateKeyPair(); + byte[] kyberPublicKey = domain.getMlkemDomain().encodePublicKey((KyberPublicKeyParameters)kyberLocalKeyPair.getPublic()); + return Arrays.concatenate(ecPublickey, kyberPublicKey); + } + } + + public void receivePeerValue(byte[] peerValue) throws IOException + { + this.ecPeerPublicKey = domain.getEcDomain().decodePublicKey(Arrays.copyOf(peerValue, domain.getEcDomain().getPublicKeyByteLength())); + byte[] kyberValue = Arrays.copyOfRange(peerValue, domain.getEcDomain().getPublicKeyByteLength(), peerValue.length); + if (domain.isServer()) + { + this.kyberPeerPublicKey = domain.getMlkemDomain().decodePublicKey(kyberValue); + SecretWithEncapsulation encap = domain.getMlkemDomain().encapsulate(kyberPeerPublicKey); + kyberCiphertext = encap.getEncapsulation(); + kyberSecret = encap.getSecret(); + } + else + { + this.kyberCiphertext = Arrays.clone(kyberValue); + } + } + + public TlsSecret calculateSecret() throws IOException + { + byte[] ecSecret = domain.getEcDomain().calculateECDHAgreementBytes(ecLocalKeyPair.getPrivate(), ecPeerPublicKey); + if (!domain.isServer()) + { + kyberSecret = domain.getMlkemDomain().decapsulate((KyberPrivateKeyParameters) kyberLocalKeyPair.getPrivate(), kyberCiphertext); + } + return domain.adoptLocalSecret(Arrays.concatenate(ecSecret, kyberSecret)); + } +} diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsEcdhMlkemDomain.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsEcdhMlkemDomain.java new file mode 100644 index 0000000000..7fb19d1134 --- /dev/null +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsEcdhMlkemDomain.java @@ -0,0 +1,72 @@ +package org.bouncycastle.tls.crypto.impl.jcajce; + +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.SecretWithEncapsulation; +import org.bouncycastle.pqc.crypto.crystals.kyber.KyberKEMExtractor; +import org.bouncycastle.pqc.crypto.crystals.kyber.KyberKEMGenerator; +import org.bouncycastle.pqc.crypto.crystals.kyber.KyberKeyGenerationParameters; +import org.bouncycastle.pqc.crypto.crystals.kyber.KyberKeyPairGenerator; +import org.bouncycastle.pqc.crypto.crystals.kyber.KyberParameters; +import org.bouncycastle.pqc.crypto.crystals.kyber.KyberPrivateKeyParameters; +import org.bouncycastle.pqc.crypto.crystals.kyber.KyberPublicKeyParameters; +import org.bouncycastle.tls.NamedGroup; +import org.bouncycastle.tls.crypto.TlsAgreement; +import org.bouncycastle.tls.crypto.TlsECConfig; +import org.bouncycastle.tls.crypto.TlsKemConfig; +import org.bouncycastle.tls.crypto.TlsKemDomain; + +public class JceTlsEcdhMlkemDomain implements TlsKemDomain +{ + protected final JcaTlsCrypto crypto; + protected final boolean isServer; + private final JceTlsECDomain ecDomain; + private final JceTlsMLKemDomain mlkemDomain; + + public JceTlsEcdhMlkemDomain(JcaTlsCrypto crypto, TlsKemConfig kemConfig) + { + this.crypto = crypto; + this.ecDomain = getJceTlsECDomain(crypto, kemConfig); + this.mlkemDomain = new JceTlsMLKemDomain(crypto, kemConfig); + this.isServer = kemConfig.isServer(); + } + + public JceTlsSecret adoptLocalSecret(byte[] secret) + { + return crypto.adoptLocalSecret(secret); + } + + public TlsAgreement createKem() + { + return new JceTlsEcdhMlkem(this); + } + + public boolean isServer() + { + return isServer; + } + + public JceTlsECDomain getEcDomain() + { + return ecDomain; + } + + public JceTlsMLKemDomain getMlkemDomain() + { + return mlkemDomain; + } + + private JceTlsECDomain getJceTlsECDomain(JcaTlsCrypto crypto, TlsKemConfig kemConfig) + { + switch (kemConfig.getNamedGroup()) + { + case NamedGroup.OQS_secp256Mlkem512: + return new JceTlsECDomain(crypto, new TlsECConfig(NamedGroup.secp256r1)); + case NamedGroup.OQS_secp384Mlkem768: + return new JceTlsECDomain(crypto, new TlsECConfig(NamedGroup.secp384r1)); + case NamedGroup.OQS_secp521Mlkem1024: + return new JceTlsECDomain(crypto, new TlsECConfig(NamedGroup.secp521r1)); + default: + return null; + } + } +} diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsMLKem.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsMLKem.java index 3a318e4f51..24d2176dcc 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsMLKem.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsMLKem.java @@ -47,7 +47,7 @@ public void receivePeerValue(byte[] peerValue) throws IOException } else { - this.secret = domain.decapsulate(privateKey, peerValue); + this.secret = domain.adoptLocalSecret(domain.decapsulate(privateKey, peerValue)); this.privateKey = null; } } diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsMLKemDomain.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsMLKemDomain.java index 7a67176231..85c4e8a6b4 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsMLKemDomain.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsMLKemDomain.java @@ -21,11 +21,14 @@ protected static KyberParameters getKyberParameters(int namedGroup) switch (namedGroup) { case NamedGroup.OQS_mlkem512: + case NamedGroup.OQS_secp256Mlkem512: return KyberParameters.kyber512; case NamedGroup.OQS_mlkem768: + case NamedGroup.OQS_secp384Mlkem768: case NamedGroup.DRAFT_mlkem768: return KyberParameters.kyber768; case NamedGroup.OQS_mlkem1024: + case NamedGroup.OQS_secp521Mlkem1024: case NamedGroup.DRAFT_mlkem1024: return KyberParameters.kyber1024; default: @@ -54,11 +57,10 @@ public TlsAgreement createKem() return new JceTlsMLKem(this); } - public JceTlsSecret decapsulate(KyberPrivateKeyParameters privateKey, byte[] ciphertext) + public byte[] decapsulate(KyberPrivateKeyParameters privateKey, byte[] ciphertext) { KyberKEMExtractor kemExtract = new KyberKEMExtractor(privateKey); - byte[] secret = kemExtract.extractSecret(ciphertext); - return adoptLocalSecret(secret); + return kemExtract.extractSecret(ciphertext); } public KyberPublicKeyParameters decodePublicKey(byte[] encoding) diff --git a/tls/src/test/java/org/bouncycastle/jsse/provider/test/BasicTlsTest.java b/tls/src/test/java/org/bouncycastle/jsse/provider/test/BasicTlsTest.java index 03f5bf58a7..341aeaed06 100644 --- a/tls/src/test/java/org/bouncycastle/jsse/provider/test/BasicTlsTest.java +++ b/tls/src/test/java/org/bouncycastle/jsse/provider/test/BasicTlsTest.java @@ -24,7 +24,7 @@ public class BasicTlsTest protected void setUp() { ProviderUtils.setupLowPriority(false); -// System.setProperty("jdk.tls.namedGroups", "kyber768"); + // System.setProperty("jdk.tls.namedGroups", "OQS_secp521Mlkem1024"); } private static final String HOST = "localhost";