mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 07:14:30 +02:00
8298390: Implement JEP 496: Quantum-Resistant Module-Lattice-Based Key Encapsulation Mechanism
Co-authored-by: Ferenc Rakoczi <ferenc.r.rakoczi@oracle.com> Reviewed-by: valeriep
This commit is contained in:
parent
6d3becb486
commit
13987b4244
10 changed files with 4781 additions and 1 deletions
1511
src/java.base/share/classes/com/sun/crypto/provider/ML_KEM.java
Normal file
1511
src/java.base/share/classes/com/sun/crypto/provider/ML_KEM.java
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,233 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sun.crypto.provider;
|
||||||
|
|
||||||
|
import sun.security.jca.JCAUtil;
|
||||||
|
import sun.security.provider.NamedKEM;
|
||||||
|
import sun.security.provider.NamedKeyFactory;
|
||||||
|
import sun.security.provider.NamedKeyPairGenerator;
|
||||||
|
|
||||||
|
import java.security.*;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import javax.crypto.DecapsulateException;
|
||||||
|
|
||||||
|
public final class ML_KEM_Impls {
|
||||||
|
|
||||||
|
static int name2int(String name) {
|
||||||
|
if (name.endsWith("512")) {
|
||||||
|
return 512;
|
||||||
|
} else if (name.endsWith("768")) {
|
||||||
|
return 768;
|
||||||
|
} else if (name.endsWith("1024")) {
|
||||||
|
return 1024;
|
||||||
|
} else {
|
||||||
|
// should not happen
|
||||||
|
throw new ProviderException("Unknown name " + name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed static class KPG
|
||||||
|
extends NamedKeyPairGenerator permits KPG2, KPG3, KPG5 {
|
||||||
|
|
||||||
|
public KPG() {
|
||||||
|
// ML-KEM-768 is the default
|
||||||
|
super("ML-KEM", "ML-KEM-768", "ML-KEM-512", "ML-KEM-1024");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected KPG(String pname) {
|
||||||
|
super("ML-KEM", pname);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte[][] implGenerateKeyPair(String name, SecureRandom random) {
|
||||||
|
byte[] seed = new byte[32];
|
||||||
|
var r = random != null ? random : JCAUtil.getDefSecureRandom();
|
||||||
|
r.nextBytes(seed);
|
||||||
|
byte[] z = new byte[32];
|
||||||
|
r.nextBytes(z);
|
||||||
|
|
||||||
|
ML_KEM mlKem = new ML_KEM(name);
|
||||||
|
ML_KEM.ML_KEM_KeyPair kp;
|
||||||
|
try {
|
||||||
|
kp = mlKem.generateKemKeyPair(seed, z);
|
||||||
|
} finally {
|
||||||
|
Arrays.fill(seed, (byte)0);
|
||||||
|
Arrays.fill(z, (byte)0);
|
||||||
|
}
|
||||||
|
return new byte[][] {
|
||||||
|
kp.encapsulationKey().keyBytes(),
|
||||||
|
kp.decapsulationKey().keyBytes()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final static class KPG2 extends KPG {
|
||||||
|
public KPG2() {
|
||||||
|
super("ML-KEM-512");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final static class KPG3 extends KPG {
|
||||||
|
public KPG3() {
|
||||||
|
super("ML-KEM-768");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final static class KPG5 extends KPG {
|
||||||
|
public KPG5() {
|
||||||
|
super("ML-KEM-1024");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed static class KF extends NamedKeyFactory permits KF2, KF3, KF5 {
|
||||||
|
public KF() {
|
||||||
|
super("ML-KEM", "ML-KEM-512", "ML-KEM-768", "ML-KEM-1024");
|
||||||
|
}
|
||||||
|
public KF(String name) {
|
||||||
|
super("ML-KEM", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final static class KF2 extends KF {
|
||||||
|
public KF2() {
|
||||||
|
super("ML-KEM-512");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final static class KF3 extends KF {
|
||||||
|
public KF3() {
|
||||||
|
super("ML-KEM-768");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final static class KF5 extends KF {
|
||||||
|
public KF5() {
|
||||||
|
super("ML-KEM-1024");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed static class K extends NamedKEM permits K2, K3, K5 {
|
||||||
|
private static final int SEED_SIZE = 32;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte[][] implEncapsulate(String name, byte[] encapsulationKey,
|
||||||
|
Object ek, SecureRandom secureRandom) {
|
||||||
|
|
||||||
|
byte[] randomBytes = new byte[SEED_SIZE];
|
||||||
|
var r = secureRandom != null ? secureRandom : JCAUtil.getDefSecureRandom();
|
||||||
|
r.nextBytes(randomBytes);
|
||||||
|
|
||||||
|
ML_KEM mlKem = new ML_KEM(name);
|
||||||
|
ML_KEM.ML_KEM_EncapsulateResult mlKemEncapsulateResult = null;
|
||||||
|
try {
|
||||||
|
mlKemEncapsulateResult = mlKem.encapsulate(
|
||||||
|
new ML_KEM.ML_KEM_EncapsulationKey(
|
||||||
|
encapsulationKey), randomBytes);
|
||||||
|
} finally {
|
||||||
|
Arrays.fill(randomBytes, (byte) 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new byte[][] {
|
||||||
|
mlKemEncapsulateResult.cipherText().encryptedBytes(),
|
||||||
|
mlKemEncapsulateResult.sharedSecret()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte[] implDecapsulate(String name, byte[] decapsulationKey,
|
||||||
|
Object dk, byte[] cipherText)
|
||||||
|
throws DecapsulateException {
|
||||||
|
|
||||||
|
ML_KEM mlKem = new ML_KEM(name);
|
||||||
|
var kpkeCipherText = new ML_KEM.K_PKE_CipherText(cipherText);
|
||||||
|
|
||||||
|
byte[] decapsulateResult;
|
||||||
|
try {
|
||||||
|
decapsulateResult = mlKem.decapsulate(
|
||||||
|
new ML_KEM.ML_KEM_DecapsulationKey(
|
||||||
|
decapsulationKey), kpkeCipherText);
|
||||||
|
} catch (DecapsulateException e) {
|
||||||
|
throw new DecapsulateException("Decapsulate error", e) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
return decapsulateResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int implSecretSize(String name) {
|
||||||
|
return ML_KEM.SECRET_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int implEncapsulationSize(String name) {
|
||||||
|
ML_KEM mlKem = new ML_KEM(name);
|
||||||
|
return mlKem.getEncapsulationSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Object implCheckPublicKey(String name, byte[] pk)
|
||||||
|
throws InvalidKeyException {
|
||||||
|
|
||||||
|
ML_KEM mlKem = new ML_KEM(name);
|
||||||
|
return mlKem.checkPublicKey(pk);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Object implCheckPrivateKey(String name, byte[] sk)
|
||||||
|
throws InvalidKeyException {
|
||||||
|
|
||||||
|
ML_KEM mlKem = new ML_KEM(name);
|
||||||
|
return mlKem.checkPrivateKey(sk);
|
||||||
|
}
|
||||||
|
|
||||||
|
public K() {
|
||||||
|
super("ML-KEM", "ML-KEM-512", "ML-KEM-768", "ML-KEM-1024");
|
||||||
|
}
|
||||||
|
|
||||||
|
public K(String name) {
|
||||||
|
super("ML-KEM", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final static class K2 extends K {
|
||||||
|
public K2() {
|
||||||
|
super("ML-KEM-512");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final static class K3 extends K {
|
||||||
|
public K3() {
|
||||||
|
super("ML-KEM-768");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final static class K5 extends K {
|
||||||
|
public K5() {
|
||||||
|
super("ML-KEM-1024");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -76,6 +76,8 @@ import static sun.security.util.SecurityProviderConstants.*;
|
||||||
*
|
*
|
||||||
* - DHKEM
|
* - DHKEM
|
||||||
*
|
*
|
||||||
|
* - ML-KEM
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public final class SunJCE extends Provider {
|
public final class SunJCE extends Provider {
|
||||||
|
@ -85,7 +87,7 @@ public final class SunJCE extends Provider {
|
||||||
|
|
||||||
private static final String info = "SunJCE Provider " +
|
private static final String info = "SunJCE Provider " +
|
||||||
"(implements RSA, DES, Triple DES, AES, Blowfish, ARCFOUR, RC2, PBE, "
|
"(implements RSA, DES, Triple DES, AES, Blowfish, ARCFOUR, RC2, PBE, "
|
||||||
+ "Diffie-Hellman, HMAC, ChaCha20)";
|
+ "Diffie-Hellman, HMAC, ChaCha20, DHKEM, and ML-KEM)";
|
||||||
|
|
||||||
/* Are we debugging? -- for developers */
|
/* Are we debugging? -- for developers */
|
||||||
static final boolean debug = false;
|
static final boolean debug = false;
|
||||||
|
@ -752,6 +754,23 @@ public final class SunJCE extends Provider {
|
||||||
"|java.security.interfaces.XECKey");
|
"|java.security.interfaces.XECKey");
|
||||||
ps("KEM", "DHKEM", "com.sun.crypto.provider.DHKEM", null, attrs);
|
ps("KEM", "DHKEM", "com.sun.crypto.provider.DHKEM", null, attrs);
|
||||||
|
|
||||||
|
attrs.clear();
|
||||||
|
attrs.put("ImplementedIn", "Software");
|
||||||
|
ps("KEM", "ML-KEM", "com.sun.crypto.provider.ML_KEM_Impls$K", null, attrs);
|
||||||
|
psA("KEM", "ML-KEM-512", "com.sun.crypto.provider.ML_KEM_Impls$K2", attrs);
|
||||||
|
psA("KEM", "ML-KEM-768", "com.sun.crypto.provider.ML_KEM_Impls$K3", attrs);
|
||||||
|
psA("KEM", "ML-KEM-1024", "com.sun.crypto.provider.ML_KEM_Impls$K5",attrs);
|
||||||
|
|
||||||
|
ps("KeyPairGenerator", "ML-KEM", "com.sun.crypto.provider.ML_KEM_Impls$KPG", null, attrs);
|
||||||
|
psA("KeyPairGenerator", "ML-KEM-512", "com.sun.crypto.provider.ML_KEM_Impls$KPG2", attrs);
|
||||||
|
psA("KeyPairGenerator", "ML-KEM-768", "com.sun.crypto.provider.ML_KEM_Impls$KPG3", attrs);
|
||||||
|
psA("KeyPairGenerator", "ML-KEM-1024", "com.sun.crypto.provider.ML_KEM_Impls$KPG5", attrs);
|
||||||
|
|
||||||
|
ps("KeyFactory", "ML-KEM", "com.sun.crypto.provider.ML_KEM_Impls$KF", null, attrs);
|
||||||
|
psA("KeyFactory", "ML-KEM-512", "com.sun.crypto.provider.ML_KEM_Impls$KF2", attrs);
|
||||||
|
psA("KeyFactory", "ML-KEM-768", "com.sun.crypto.provider.ML_KEM_Impls$KF3", attrs);
|
||||||
|
psA("KeyFactory", "ML-KEM-1024", "com.sun.crypto.provider.ML_KEM_Impls$KF5", attrs);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SSL/TLS mechanisms
|
* SSL/TLS mechanisms
|
||||||
*
|
*
|
||||||
|
|
|
@ -68,6 +68,30 @@ public class NamedParameterSpec implements AlgorithmParameterSpec {
|
||||||
public static final NamedParameterSpec ED448
|
public static final NamedParameterSpec ED448
|
||||||
= new NamedParameterSpec("Ed448");
|
= new NamedParameterSpec("Ed448");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ML-KEM-512 parameters
|
||||||
|
*
|
||||||
|
* @since 24
|
||||||
|
*/
|
||||||
|
public static final NamedParameterSpec ML_KEM_512
|
||||||
|
= new NamedParameterSpec("ML-KEM-512");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ML-KEM-768 parameters
|
||||||
|
*
|
||||||
|
* @since 24
|
||||||
|
*/
|
||||||
|
public static final NamedParameterSpec ML_KEM_768
|
||||||
|
= new NamedParameterSpec("ML-KEM-768");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ML-KEM-1024 parameters
|
||||||
|
*
|
||||||
|
* @since 24
|
||||||
|
*/
|
||||||
|
public static final NamedParameterSpec ML_KEM_1024
|
||||||
|
= new NamedParameterSpec("ML-KEM-1024");
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sun.security.provider;
|
||||||
|
|
||||||
|
import jdk.internal.vm.annotation.IntrinsicCandidate;
|
||||||
|
|
||||||
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import static sun.security.provider.ByteArrayAccess.b2lLittle;
|
||||||
|
import static sun.security.provider.ByteArrayAccess.l2bLittle;
|
||||||
|
|
||||||
|
import static sun.security.provider.SHA3.keccak;
|
||||||
|
|
||||||
|
public class SHA3Parallel {
|
||||||
|
private int blockSize = 0;
|
||||||
|
private static final int DM = 5; // dimension of lanesArr
|
||||||
|
private byte[][] buffers;
|
||||||
|
private long[][] lanesArr;
|
||||||
|
private static final int NRPAR = 2;
|
||||||
|
|
||||||
|
private SHA3Parallel(byte[][] buffers, int blockSize) throws InvalidAlgorithmParameterException {
|
||||||
|
if ((buffers.length != NRPAR) || (buffers[0].length < blockSize)) {
|
||||||
|
throw new InvalidAlgorithmParameterException("Bad buffersize.");
|
||||||
|
}
|
||||||
|
this.buffers = buffers;
|
||||||
|
this.blockSize = blockSize;
|
||||||
|
lanesArr = new long[NRPAR][];
|
||||||
|
for (int i = 0; i < NRPAR; i++) {
|
||||||
|
lanesArr[i] = new long[DM * DM];
|
||||||
|
b2lLittle(buffers[i], 0, lanesArr[i], 0, blockSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset(byte[][] buffers) throws InvalidAlgorithmParameterException {
|
||||||
|
if ((buffers.length != NRPAR) || (buffers[0].length < blockSize)) {
|
||||||
|
throw new InvalidAlgorithmParameterException("Bad buffersize.");
|
||||||
|
}
|
||||||
|
this.buffers = buffers;
|
||||||
|
for (int i = 0; i < NRPAR; i++) {
|
||||||
|
Arrays.fill(lanesArr[i], 0L);
|
||||||
|
b2lLittle(buffers[i], 0, lanesArr[i], 0, blockSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int squeezeBlock() {
|
||||||
|
int retVal = doubleKeccak(lanesArr[0], lanesArr[1]);
|
||||||
|
for (int i = 0; i < NRPAR; i++) {
|
||||||
|
l2bLittle(lanesArr[i], 0, buffers[i], 0, blockSize);
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@IntrinsicCandidate
|
||||||
|
private static int doubleKeccak(long[] lanes0, long[] lanes1) {
|
||||||
|
doubleKeccakJava(lanes0, lanes1);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int doubleKeccakJava(long[] lanes0, long[] lanes1) {
|
||||||
|
keccak(lanes0);
|
||||||
|
keccak(lanes1);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class Shake128Parallel extends SHA3Parallel {
|
||||||
|
public Shake128Parallel(byte[][] buf) throws InvalidAlgorithmParameterException {
|
||||||
|
super(buf, 168);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -179,6 +179,11 @@ public enum KnownOIDs {
|
||||||
SHA3_384withRSA("2.16.840.1.101.3.4.3.15", "SHA3-384withRSA"),
|
SHA3_384withRSA("2.16.840.1.101.3.4.3.15", "SHA3-384withRSA"),
|
||||||
SHA3_512withRSA("2.16.840.1.101.3.4.3.16", "SHA3-512withRSA"),
|
SHA3_512withRSA("2.16.840.1.101.3.4.3.16", "SHA3-512withRSA"),
|
||||||
|
|
||||||
|
// kems 2.16.840.1.101.3.4.4.*
|
||||||
|
ML_KEM_512("2.16.840.1.101.3.4.4.1", "ML-KEM-512"),
|
||||||
|
ML_KEM_768("2.16.840.1.101.3.4.4.2", "ML-KEM-768"),
|
||||||
|
ML_KEM_1024("2.16.840.1.101.3.4.4.3", "ML-KEM-1024"),
|
||||||
|
|
||||||
// RSASecurity
|
// RSASecurity
|
||||||
// PKCS1 1.2.840.113549.1.1.*
|
// PKCS1 1.2.840.113549.1.1.*
|
||||||
PKCS1("1.2.840.113549.1.1", "RSA") { // RSA KeyPairGenerator and KeyFactory
|
PKCS1("1.2.840.113549.1.1", "RSA") { // RSA KeyPairGenerator and KeyFactory
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -205,6 +205,7 @@ public class Deterministic {
|
||||||
case "EC" -> 256;
|
case "EC" -> 256;
|
||||||
case "EdDSA", "Ed25519", "XDH", "X25519" -> 255;
|
case "EdDSA", "Ed25519", "XDH", "X25519" -> 255;
|
||||||
case "Ed448", "X448" -> 448;
|
case "Ed448", "X448" -> 448;
|
||||||
|
case "ML-KEM", "ML-KEM-768", "ML-KEM-512", "ML-KEM-1024" -> -1;
|
||||||
default -> throw new UnsupportedOperationException(alg);
|
default -> throw new UnsupportedOperationException(alg);
|
||||||
};
|
};
|
||||||
g.initialize(size, new SeededSecureRandom(SEED + offset));
|
g.initialize(size, new SeededSecureRandom(SEED + offset));
|
||||||
|
|
1240
test/micro/org/openjdk/bench/java/security/MLKEMBench.java
Normal file
1240
test/micro/org/openjdk/bench/java/security/MLKEMBench.java
Normal file
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue