mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 07:14:30 +02:00
8297878: KEM: Implementation
Reviewed-by: ascarpino, mullan
This commit is contained in:
parent
21af8bae38
commit
6b90b0519e
12 changed files with 2324 additions and 21 deletions
395
src/java.base/share/classes/com/sun/crypto/provider/DHKEM.java
Normal file
395
src/java.base/share/classes/com/sun/crypto/provider/DHKEM.java
Normal file
|
@ -0,0 +1,395 @@
|
|||
/*
|
||||
* Copyright (c) 2023, 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.ssl.HKDF;
|
||||
import sun.security.util.*;
|
||||
|
||||
import javax.crypto.*;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.*;
|
||||
import java.security.interfaces.*;
|
||||
import java.security.spec.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
// Implementing DHKEM defined inside https://www.rfc-editor.org/rfc/rfc9180.html,
|
||||
// without the AuthEncap and AuthDecap functions
|
||||
public class DHKEM implements KEMSpi {
|
||||
|
||||
private static final byte[] KEM = new byte[]
|
||||
{'K', 'E', 'M'};
|
||||
private static final byte[] EAE_PRK = new byte[]
|
||||
{'e', 'a', 'e', '_', 'p', 'r', 'k'};
|
||||
private static final byte[] SHARED_SECRET = new byte[]
|
||||
{'s', 'h', 'a', 'r', 'e', 'd', '_', 's', 'e', 'c', 'r', 'e', 't'};
|
||||
private static final byte[] DKP_PRK = new byte[]
|
||||
{'d', 'k', 'p', '_', 'p', 'r', 'k'};
|
||||
private static final byte[] CANDIDATE = new byte[]
|
||||
{'c', 'a', 'n', 'd', 'i', 'd', 'a', 't', 'e'};
|
||||
private static final byte[] SK = new byte[]
|
||||
{'s', 'k'};
|
||||
private static final byte[] HPKE_V1 = new byte[]
|
||||
{'H', 'P', 'K', 'E', '-', 'v', '1'};
|
||||
private static final byte[] EMPTY = new byte[0];
|
||||
|
||||
private record Handler(Params params, SecureRandom secureRandom,
|
||||
PrivateKey skR, PublicKey pkR)
|
||||
implements EncapsulatorSpi, DecapsulatorSpi {
|
||||
|
||||
@Override
|
||||
public KEM.Encapsulated engineEncapsulate(int from, int to, String algorithm) {
|
||||
Objects.checkFromToIndex(from, to, params.Nsecret);
|
||||
Objects.requireNonNull(algorithm, "null algorithm");
|
||||
KeyPair kpE = params.generateKeyPair(secureRandom);
|
||||
PrivateKey skE = kpE.getPrivate();
|
||||
PublicKey pkE = kpE.getPublic();
|
||||
byte[] pkEm = params.SerializePublicKey(pkE);
|
||||
byte[] pkRm = params.SerializePublicKey(pkR);
|
||||
byte[] kem_context = concat(pkEm, pkRm);
|
||||
try {
|
||||
byte[] dh = params.DH(skE, pkR);
|
||||
byte[] key = params.ExtractAndExpand(dh, kem_context);
|
||||
return new KEM.Encapsulated(
|
||||
new SecretKeySpec(key, from, to - from, algorithm),
|
||||
pkEm, null);
|
||||
} catch (Exception e) {
|
||||
throw new ProviderException("internal error", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecretKey engineDecapsulate(byte[] encapsulation,
|
||||
int from, int to, String algorithm) throws DecapsulateException {
|
||||
Objects.checkFromToIndex(from, to, params.Nsecret);
|
||||
Objects.requireNonNull(algorithm, "null algorithm");
|
||||
Objects.requireNonNull(encapsulation, "null encapsulation");
|
||||
if (encapsulation.length != params.Npk) {
|
||||
throw new DecapsulateException("incorrect encapsulation size");
|
||||
}
|
||||
try {
|
||||
PublicKey pkE = params.DeserializePublicKey(encapsulation);
|
||||
byte[] dh = params.DH(skR, pkE);
|
||||
byte[] pkRm = params.SerializePublicKey(pkR);
|
||||
byte[] kem_context = concat(encapsulation, pkRm);
|
||||
byte[] key = params.ExtractAndExpand(dh, kem_context);
|
||||
return new SecretKeySpec(key, from, to - from, algorithm);
|
||||
} catch (IOException | InvalidKeyException e) {
|
||||
throw new DecapsulateException("Cannot decapsulate", e);
|
||||
} catch (Exception e) {
|
||||
throw new ProviderException("internal error", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int engineSecretSize() {
|
||||
return params.Nsecret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int engineEncapsulationSize() {
|
||||
return params.Npk;
|
||||
}
|
||||
}
|
||||
|
||||
// Not really a random. For KAT test only. It generates key pair from ikm.
|
||||
public static class RFC9180DeriveKeyPairSR extends SecureRandom {
|
||||
|
||||
static final long serialVersionUID = 0L;
|
||||
|
||||
private final byte[] ikm;
|
||||
|
||||
public RFC9180DeriveKeyPairSR(byte[] ikm) {
|
||||
super(null, null); // lightest constructor
|
||||
this.ikm = ikm;
|
||||
}
|
||||
|
||||
public KeyPair derive(Params params) {
|
||||
try {
|
||||
return params.deriveKeyPair(ikm);
|
||||
} catch (Exception e) {
|
||||
throw new UnsupportedOperationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public KeyPair derive(int kem_id) {
|
||||
Params params = Arrays.stream(Params.values())
|
||||
.filter(p -> p.kem_id == kem_id)
|
||||
.findFirst()
|
||||
.orElseThrow();
|
||||
return derive(params);
|
||||
}
|
||||
}
|
||||
|
||||
private enum Params {
|
||||
|
||||
P256(0x10, 32, 32, 2 * 32 + 1,
|
||||
"ECDH", "EC", CurveDB.P_256, "SHA-256"),
|
||||
|
||||
P384(0x11, 48, 48, 2 * 48 + 1,
|
||||
"ECDH", "EC", CurveDB.P_384, "SHA-384"),
|
||||
|
||||
P521(0x12, 64, 66, 2 * 66 + 1,
|
||||
"ECDH", "EC", CurveDB.P_521, "SHA-512"),
|
||||
|
||||
X25519(0x20, 32, 32, 32,
|
||||
"XDH", "XDH", NamedParameterSpec.X25519, "SHA-256"),
|
||||
|
||||
X448(0x21, 64, 56, 56,
|
||||
"XDH", "XDH", NamedParameterSpec.X448, "SHA-512"),
|
||||
;
|
||||
|
||||
private final int kem_id;
|
||||
private final int Nsecret;
|
||||
private final int Nsk;
|
||||
private final int Npk;
|
||||
private final String kaAlgorithm;
|
||||
private final String keyAlgorithm;
|
||||
private final AlgorithmParameterSpec spec;
|
||||
private final String hkdfAlgorithm;
|
||||
|
||||
private final byte[] suiteId;
|
||||
|
||||
Params(int kem_id, int Nsecret, int Nsk, int Npk,
|
||||
String kaAlgorithm, String keyAlgorithm, AlgorithmParameterSpec spec,
|
||||
String hkdfAlgorithm) {
|
||||
this.kem_id = kem_id;
|
||||
this.spec = spec;
|
||||
this.Nsecret = Nsecret;
|
||||
this.Nsk = Nsk;
|
||||
this.Npk = Npk;
|
||||
this.kaAlgorithm = kaAlgorithm;
|
||||
this.keyAlgorithm = keyAlgorithm;
|
||||
this.hkdfAlgorithm = hkdfAlgorithm;
|
||||
suiteId = concat(KEM, I2OSP(kem_id, 2));
|
||||
}
|
||||
|
||||
private boolean isEC() {
|
||||
return this == P256 || this == P384 || this == P521;
|
||||
}
|
||||
|
||||
private KeyPair generateKeyPair(SecureRandom sr) {
|
||||
if (sr instanceof RFC9180DeriveKeyPairSR r9) {
|
||||
return r9.derive(this);
|
||||
}
|
||||
try {
|
||||
KeyPairGenerator g = KeyPairGenerator.getInstance(keyAlgorithm);
|
||||
g.initialize(spec, sr);
|
||||
return g.generateKeyPair();
|
||||
} catch (Exception e) {
|
||||
throw new ProviderException("internal error", e);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] SerializePublicKey(PublicKey k) {
|
||||
if (isEC()) {
|
||||
ECPoint w = ((ECPublicKey) k).getW();
|
||||
return ECUtil.encodePoint(w, ((NamedCurve) spec).getCurve());
|
||||
} else {
|
||||
byte[] uArray = ((XECPublicKey) k).getU().toByteArray();
|
||||
ArrayUtil.reverse(uArray);
|
||||
return Arrays.copyOf(uArray, Npk);
|
||||
}
|
||||
}
|
||||
|
||||
private PublicKey DeserializePublicKey(byte[] data)
|
||||
throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
|
||||
KeySpec keySpec;
|
||||
if (isEC()) {
|
||||
NamedCurve curve = (NamedCurve) this.spec;
|
||||
keySpec = new ECPublicKeySpec(
|
||||
ECUtil.decodePoint(data, curve.getCurve()), curve);
|
||||
} else {
|
||||
data = data.clone();
|
||||
ArrayUtil.reverse(data);
|
||||
keySpec = new XECPublicKeySpec(
|
||||
this.spec, new BigInteger(1, data));
|
||||
}
|
||||
return KeyFactory.getInstance(keyAlgorithm).generatePublic(keySpec);
|
||||
}
|
||||
|
||||
private byte[] DH(PrivateKey skE, PublicKey pkR)
|
||||
throws NoSuchAlgorithmException, InvalidKeyException {
|
||||
KeyAgreement ka = KeyAgreement.getInstance(kaAlgorithm);
|
||||
ka.init(skE);
|
||||
ka.doPhase(pkR, true);
|
||||
return ka.generateSecret();
|
||||
}
|
||||
|
||||
private byte[] ExtractAndExpand(byte[] dh, byte[] kem_context)
|
||||
throws NoSuchAlgorithmException, InvalidKeyException {
|
||||
HKDF kdf = new HKDF(hkdfAlgorithm);
|
||||
SecretKey eae_prk = LabeledExtract(kdf, suiteId, null, EAE_PRK, dh);
|
||||
return LabeledExpand(kdf, suiteId, eae_prk, SHARED_SECRET,
|
||||
kem_context, Nsecret);
|
||||
}
|
||||
|
||||
private PublicKey getPublicKey(PrivateKey sk)
|
||||
throws InvalidKeyException {
|
||||
if (!(sk instanceof InternalPrivateKey)) {
|
||||
try {
|
||||
KeyFactory kf = KeyFactory.getInstance(keyAlgorithm, "SunEC");
|
||||
sk = (PrivateKey) kf.translateKey(sk);
|
||||
} catch (Exception e) {
|
||||
throw new InvalidKeyException("Error translating key", e);
|
||||
}
|
||||
}
|
||||
if (sk instanceof InternalPrivateKey ik) {
|
||||
try {
|
||||
return ik.calculatePublicKey();
|
||||
} catch (UnsupportedOperationException e) {
|
||||
throw new InvalidKeyException("Error retrieving key", e);
|
||||
}
|
||||
} else {
|
||||
// Should not happen, unless SunEC goes wrong
|
||||
throw new ProviderException("Unknown key");
|
||||
}
|
||||
}
|
||||
|
||||
// For KAT tests only. See RFC9180DeriveKeyPairSR.
|
||||
public KeyPair deriveKeyPair(byte[] ikm) throws Exception {
|
||||
HKDF kdf = new HKDF(hkdfAlgorithm);
|
||||
SecretKey dkp_prk = LabeledExtract(kdf, suiteId, null, DKP_PRK, ikm);
|
||||
if (isEC()) {
|
||||
NamedCurve curve = (NamedCurve) spec;
|
||||
BigInteger sk = BigInteger.ZERO;
|
||||
int counter = 0;
|
||||
while (sk.signum() == 0 || sk.compareTo(curve.getOrder()) >= 0) {
|
||||
if (counter > 255) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
byte[] bytes = LabeledExpand(kdf, suiteId, dkp_prk,
|
||||
CANDIDATE, I2OSP(counter, 1), Nsk);
|
||||
// bitmask is defined to be 0xFF for P-256 and P-384, and 0x01 for P-521
|
||||
if (this == Params.P521) {
|
||||
bytes[0] = (byte) (bytes[0] & 0x01);
|
||||
}
|
||||
sk = new BigInteger(1, (bytes));
|
||||
counter = counter + 1;
|
||||
}
|
||||
PrivateKey k = DeserializePrivateKey(sk.toByteArray());
|
||||
return new KeyPair(getPublicKey(k), k);
|
||||
} else {
|
||||
byte[] sk = LabeledExpand(kdf, suiteId, dkp_prk, SK, EMPTY, Nsk);
|
||||
PrivateKey k = DeserializePrivateKey(sk);
|
||||
return new KeyPair(getPublicKey(k), k);
|
||||
}
|
||||
}
|
||||
|
||||
private PrivateKey DeserializePrivateKey(byte[] data) throws Exception {
|
||||
KeySpec keySpec = isEC()
|
||||
? new ECPrivateKeySpec(new BigInteger(1, (data)), (NamedCurve) spec)
|
||||
: new XECPrivateKeySpec(spec, data);
|
||||
return KeyFactory.getInstance(keyAlgorithm).generatePrivate(keySpec);
|
||||
}
|
||||
}
|
||||
|
||||
private static SecureRandom getSecureRandom(SecureRandom userSR) {
|
||||
return userSR != null ? userSR : JCAUtil.getSecureRandom();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EncapsulatorSpi engineNewEncapsulator(
|
||||
PublicKey pk, AlgorithmParameterSpec spec, SecureRandom secureRandom)
|
||||
throws InvalidAlgorithmParameterException, InvalidKeyException {
|
||||
if (pk == null) {
|
||||
throw new InvalidKeyException("input key is null");
|
||||
}
|
||||
if (spec != null) {
|
||||
throw new InvalidAlgorithmParameterException("no spec needed");
|
||||
}
|
||||
Params params = paramsFromKey(pk);
|
||||
return new Handler(params, getSecureRandom(secureRandom), null, pk);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DecapsulatorSpi engineNewDecapsulator(PrivateKey sk, AlgorithmParameterSpec spec)
|
||||
throws InvalidAlgorithmParameterException, InvalidKeyException {
|
||||
if (sk == null) {
|
||||
throw new InvalidKeyException("input key is null");
|
||||
}
|
||||
if (spec != null) {
|
||||
throw new InvalidAlgorithmParameterException("no spec needed");
|
||||
}
|
||||
Params params = paramsFromKey(sk);
|
||||
return new Handler(params, null, sk, params.getPublicKey(sk));
|
||||
}
|
||||
|
||||
private Params paramsFromKey(Key k) throws InvalidKeyException {
|
||||
if (k instanceof ECKey eckey) {
|
||||
if (ECUtil.equals(eckey.getParams(), CurveDB.P_256)) {
|
||||
return Params.P256;
|
||||
} else if (ECUtil.equals(eckey.getParams(), CurveDB.P_384)) {
|
||||
return Params.P384;
|
||||
} else if (ECUtil.equals(eckey.getParams(), CurveDB.P_521)) {
|
||||
return Params.P521;
|
||||
}
|
||||
} else if (k instanceof XECKey xkey
|
||||
&& xkey.getParams() instanceof NamedParameterSpec ns) {
|
||||
if (ns.getName().equals("X25519")) {
|
||||
return Params.X25519;
|
||||
} else if (ns.getName().equals("X448")) {
|
||||
return Params.X448;
|
||||
}
|
||||
}
|
||||
throw new InvalidKeyException("Unsupported key");
|
||||
}
|
||||
|
||||
private static byte[] concat(byte[]... inputs) {
|
||||
ByteArrayOutputStream o = new ByteArrayOutputStream();
|
||||
Arrays.stream(inputs).forEach(o::writeBytes);
|
||||
return o.toByteArray();
|
||||
}
|
||||
|
||||
private static byte[] I2OSP(int n, int w) {
|
||||
assert n < 256;
|
||||
assert w == 1 || w == 2;
|
||||
if (w == 1) {
|
||||
return new byte[] { (byte) n };
|
||||
} else {
|
||||
return new byte[] { (byte) (n >> 8), (byte) n };
|
||||
}
|
||||
}
|
||||
|
||||
private static SecretKey LabeledExtract(HKDF kdf, byte[] suite_id,
|
||||
byte[] salt, byte[] label, byte[] ikm) throws InvalidKeyException {
|
||||
return kdf.extract(salt,
|
||||
new SecretKeySpec(concat(HPKE_V1, suite_id, label, ikm), "IKM"),
|
||||
"HKDF-PRK");
|
||||
}
|
||||
|
||||
private static byte[] LabeledExpand(HKDF kdf, byte[] suite_id,
|
||||
SecretKey prk, byte[] label, byte[] info, int L)
|
||||
throws InvalidKeyException {
|
||||
byte[] labeled_info = concat(I2OSP(L, 2), HPKE_V1,
|
||||
suite_id, label, info);
|
||||
return kdf.expand(prk, labeled_info, L, "NONE").getEncoded();
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2023, 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
|
||||
|
@ -74,6 +74,10 @@ import static sun.security.util.SecurityProviderConstants.*;
|
|||
*
|
||||
* - HMAC-MD5, HMAC-SHA1, HMAC with SHA2 family and SHA3 family of digests
|
||||
*
|
||||
* - JCEKS KeyStore
|
||||
*
|
||||
* - DHKEM
|
||||
*
|
||||
*/
|
||||
|
||||
public final class SunJCE extends Provider {
|
||||
|
@ -743,6 +747,15 @@ public final class SunJCE extends Provider {
|
|||
ps("KeyStore", "JCEKS",
|
||||
"com.sun.crypto.provider.JceKeyStore");
|
||||
|
||||
/*
|
||||
* KEMs
|
||||
*/
|
||||
attrs.clear();
|
||||
attrs.put("ImplementedIn", "Software");
|
||||
attrs.put("SupportedKeyClasses", "java.security.interfaces.ECKey" +
|
||||
"|java.security.interfaces.XECKey");
|
||||
ps("KEM", "DHKEM", "com.sun.crypto.provider.DHKEM", null, attrs);
|
||||
|
||||
/*
|
||||
* SSL/TLS mechanisms
|
||||
*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2023, 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
|
||||
|
@ -1599,6 +1599,7 @@ public abstract class Provider extends Properties {
|
|||
addEngine("KeyAgreement", true, null);
|
||||
addEngine("KeyGenerator", false, null);
|
||||
addEngine("SecretKeyFactory", false, null);
|
||||
addEngine("KEM", true, null);
|
||||
// JSSE
|
||||
addEngine("KeyManagerFactory", false, null);
|
||||
addEngine("SSLContext", false, null);
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (c) 2023, 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 javax.crypto;
|
||||
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
/**
|
||||
* An exception that is thrown by the
|
||||
* {@link javax.crypto.KEM.Decapsulator#decapsulate} method to denote an
|
||||
* error during decapsulation.
|
||||
*
|
||||
* @since 21
|
||||
*/
|
||||
public class DecapsulateException extends GeneralSecurityException {
|
||||
|
||||
@java.io.Serial
|
||||
private static final long serialVersionUID = 21L;
|
||||
|
||||
/**
|
||||
* Creates a {@code DecapsulateException} with the specified
|
||||
* detail message.
|
||||
*
|
||||
* @param message the detail message (which is saved for later retrieval
|
||||
* by the {@link #getMessage()} method).
|
||||
*/
|
||||
public DecapsulateException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code DecapsulateException} with the specified
|
||||
* detail message and cause.
|
||||
*
|
||||
* @param message the detail message (which is saved for later retrieval
|
||||
* by the {@link #getMessage()} method).
|
||||
* @param cause the cause (which is saved for later retrieval by the
|
||||
* {@link #getCause()} method). (A {@code null} value is permitted,
|
||||
* and indicates that the cause is nonexistent or unknown.)
|
||||
*/
|
||||
public DecapsulateException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
737
src/java.base/share/classes/javax/crypto/KEM.java
Normal file
737
src/java.base/share/classes/javax/crypto/KEM.java
Normal file
|
@ -0,0 +1,737 @@
|
|||
/*
|
||||
* Copyright (c) 2023, 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 javax.crypto;
|
||||
|
||||
import sun.security.jca.GetInstance;
|
||||
|
||||
import java.security.*;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.spec.AlgorithmParameterSpec;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* This class provides the functionality of a Key Encapsulation Mechanism (KEM).
|
||||
* A KEM can be used to secure symmetric keys using asymmetric or public key
|
||||
* cryptography between two parties. The sender calls the encapsulate method
|
||||
* to generate a secret key and a key encapsulation message, and the receiver
|
||||
* calls the decapsulate method to recover the same secret key from
|
||||
* the key encapsulation message.
|
||||
* <p>
|
||||
* The {@code getInstance} method creates a new {@code KEM} object that
|
||||
* implements the specified algorithm.
|
||||
* <p>
|
||||
* A {@code KEM} object is immutable. It is safe to call multiple
|
||||
* {@code newEncapsulator} and {@code newDecapsulator} methods on the
|
||||
* same {@code KEM} object at the same time.
|
||||
* <p>
|
||||
* If a provider is not specified in the {@code getInstance} method when
|
||||
* instantiating a {@code KEM} object, the {@code newEncapsulator} and
|
||||
* {@code newDecapsulator} methods may return encapsulators or decapsulators
|
||||
* from different providers. The provider selected is based on the parameters
|
||||
* passed to the {@code newEncapsulator} or {@code newDecapsulator} methods:
|
||||
* the private or public key and the optional {@code AlgorithmParameterSpec}.
|
||||
* The {@link Encapsulator#providerName} and {@link Decapsulator#providerName}
|
||||
* methods return the name of the selected provider.
|
||||
* <p>
|
||||
* {@code Encapsulator} and {@code Decapsulator} objects are also immutable.
|
||||
* It is safe to invoke multiple {@code encapsulate} and {@code decapsulate}
|
||||
* methods on the same {@code Encapsulator} or {@code Decapsulator} object
|
||||
* at the same time. Each invocation of {@code encapsulate} will generate a
|
||||
* new shared secret and key encapsulation message.
|
||||
* <p>
|
||||
*
|
||||
* Example:
|
||||
* {@snippet lang = java:
|
||||
* // Receiver side
|
||||
* var kpg = KeyPairGenerator.getInstance("X25519");
|
||||
* var kp = kpg.generateKeyPair();
|
||||
*
|
||||
* // Sender side
|
||||
* var kem1 = KEM.getInstance("DHKEM");
|
||||
* var sender = kem1.newEncapsulator(kp.getPublic());
|
||||
* var encapsulated = sender.encapsulate();
|
||||
* var k1 = encapsulated.key();
|
||||
*
|
||||
* // Receiver side
|
||||
* var kem2 = KEM.getInstance("DHKEM");
|
||||
* var receiver = kem2.newDecapsulator(kp.getPrivate());
|
||||
* var k2 = receiver.decapsulate(encapsulated.encapsulation());
|
||||
*
|
||||
* assert Arrays.equals(k1.getEncoded(), k2.getEncoded());
|
||||
* }
|
||||
*
|
||||
* @since 21
|
||||
*/
|
||||
public final class KEM {
|
||||
|
||||
/**
|
||||
* This class specifies the return value of the encapsulate method of
|
||||
* a Key Encapsulation Mechanism (KEM), which includes the shared secret
|
||||
* (as a {@code SecretKey}), the key encapsulation message,
|
||||
* and optional parameters.
|
||||
* <p>
|
||||
* Note: the key encapsulation message can be also referred to as ciphertext.
|
||||
*
|
||||
* @see #newEncapsulator(PublicKey, AlgorithmParameterSpec, SecureRandom)
|
||||
* @see Encapsulator#encapsulate(int, int, String)
|
||||
*
|
||||
* @since 21
|
||||
*/
|
||||
public static final class Encapsulated {
|
||||
private final SecretKey key;
|
||||
private final byte[] encapsulation;
|
||||
private final byte[] params;
|
||||
|
||||
/**
|
||||
* Constructs an {@code Encapsulated} object.
|
||||
*
|
||||
* @param key the shared secret as a key, must not be {@code null}.
|
||||
* @param encapsulation the key encapsulation message, must not
|
||||
* be {@code null}. The contents of the array are copied
|
||||
* to protect against subsequent modification.
|
||||
* @param params optional parameters, can be {@code null}.
|
||||
* The contents of the array are copied to protect
|
||||
* against subsequent modification.
|
||||
* @throws NullPointerException if {@code key} or {@code encapsulation}
|
||||
* is {@code null}
|
||||
*/
|
||||
public Encapsulated(SecretKey key, byte[] encapsulation, byte[] params) {
|
||||
Objects.requireNonNull(key);
|
||||
Objects.requireNonNull(encapsulation);
|
||||
this.key = key;
|
||||
this.encapsulation = encapsulation.clone();
|
||||
this.params = params == null ? null : params.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code SecretKey}.
|
||||
*
|
||||
* @return the secret key
|
||||
*/
|
||||
public SecretKey key() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key encapsulation message.
|
||||
*
|
||||
* @return the key encapsulation message. A new copy of the byte array
|
||||
* is returned.
|
||||
*/
|
||||
public byte[] encapsulation() {
|
||||
return encapsulation.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the optional parameters in a byte array.
|
||||
*
|
||||
* @return the optional parameters in a byte array or {@code null}
|
||||
* if not specified. A new copy of the byte array is returned.
|
||||
*/
|
||||
public byte[] params() {
|
||||
return params == null ? null : params.clone();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An encapsulator, generated by {@link #newEncapsulator} on the KEM
|
||||
* sender side.
|
||||
* <p>
|
||||
* This class represents the key encapsulation function of a KEM.
|
||||
* Each invocation of the {@code encapsulate} method generates a
|
||||
* new secret key and key encapsulation message that is returned
|
||||
* in an {@link Encapsulated} object.
|
||||
*
|
||||
* @since 21
|
||||
*/
|
||||
public static final class Encapsulator {
|
||||
|
||||
private final KEMSpi.EncapsulatorSpi e;
|
||||
private final Provider p;
|
||||
|
||||
private Encapsulator(KEMSpi.EncapsulatorSpi e, Provider p) {
|
||||
assert e != null;
|
||||
assert p != null;
|
||||
this.e = e;
|
||||
this.p = p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the provider.
|
||||
*
|
||||
* @return the name of the provider
|
||||
*/
|
||||
public String providerName() {
|
||||
return p.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* The key encapsulation function.
|
||||
* <p>
|
||||
* This method is equivalent to
|
||||
* {@code encapsulate(0, secretSize(), "Generic")}. This combination
|
||||
* of arguments must be supported by every implementation.
|
||||
* <p>
|
||||
* The generated secret key is usually passed to a key derivation
|
||||
* function (KDF) as the input keying material.
|
||||
*
|
||||
* @return a {@link Encapsulated} object containing the shared
|
||||
* secret, key encapsulation message, and optional parameters.
|
||||
* The shared secret is a {@code SecretKey} containing all of
|
||||
* the bytes of the secret, and an algorithm name of "Generic".
|
||||
*/
|
||||
public Encapsulated encapsulate() {
|
||||
return encapsulate(0, secretSize(), "Generic");
|
||||
}
|
||||
|
||||
/**
|
||||
* The key encapsulation function.
|
||||
* <p>
|
||||
* Each invocation of this method generates a new secret key and key
|
||||
* encapsulation message that is returned in an {@link Encapsulated} object.
|
||||
* <p>
|
||||
* An implementation may choose to not support arbitrary combinations
|
||||
* of {@code from}, {@code to}, and {@code algorithm}.
|
||||
*
|
||||
* @param from the initial index of the shared secret byte array
|
||||
* to be returned, inclusive
|
||||
* @param to the final index of the shared secret byte array
|
||||
* to be returned, exclusive
|
||||
* @param algorithm the algorithm name for the secret key that is returned
|
||||
* @return a {@link Encapsulated} object containing a portion of
|
||||
* the shared secret, key encapsulation message, and optional
|
||||
* parameters. The portion of the shared secret is a
|
||||
* {@code SecretKey} containing the bytes of the secret
|
||||
* ranging from {@code from} to {@code to}, exclusive,
|
||||
* and an algorithm name as specified. For example,
|
||||
* {@code encapsulate(0, 16, "AES")} uses the first 16 bytes
|
||||
* of the shared secret as a 128-bit AES key.
|
||||
* @throws IndexOutOfBoundsException if {@code from < 0},
|
||||
* {@code from > to}, or {@code to > secretSize()}
|
||||
* @throws NullPointerException if {@code algorithm} is {@code null}
|
||||
* @throws UnsupportedOperationException if the combination of
|
||||
* {@code from}, {@code to}, and {@code algorithm}
|
||||
* is not supported by the encapsulator
|
||||
*/
|
||||
public Encapsulated encapsulate(int from, int to, String algorithm) {
|
||||
return e.engineEncapsulate(from, to, algorithm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the shared secret.
|
||||
* <p>
|
||||
* This method can be called to find out the length of the shared secret
|
||||
* before {@code encapsulate} is called or if the obtained
|
||||
* {@code SecretKey} is not extractable.
|
||||
*
|
||||
* @return the size of the shared secret
|
||||
*/
|
||||
public int secretSize() {
|
||||
int result = e.engineSecretSize();
|
||||
assert result >= 0 && result != Integer.MAX_VALUE
|
||||
: "invalid engineSecretSize result";
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the key encapsulation message.
|
||||
* <p>
|
||||
* This method can be called to find out the length of the encapsulation
|
||||
* message before {@code encapsulate} is called.
|
||||
*
|
||||
* @return the size of the key encapsulation message
|
||||
*/
|
||||
public int encapsulationSize() {
|
||||
int result = e.engineEncapsulationSize();
|
||||
assert result >= 0 && result != Integer.MAX_VALUE
|
||||
: "invalid engineEncapsulationSize result";
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A decapsulator, generated by {@link #newDecapsulator} on the KEM
|
||||
* receiver side.
|
||||
* <p>
|
||||
* This class represents the key decapsulation function of a KEM.
|
||||
* An invocation of the {@code decapsulate} method recovers the
|
||||
* secret key from the key encapsulation message.
|
||||
*
|
||||
* @since 21
|
||||
*/
|
||||
public static final class Decapsulator {
|
||||
private final KEMSpi.DecapsulatorSpi d;
|
||||
private final Provider p;
|
||||
|
||||
private Decapsulator(KEMSpi.DecapsulatorSpi d, Provider p) {
|
||||
assert d != null;
|
||||
assert p != null;
|
||||
this.d = d;
|
||||
this.p = p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the provider.
|
||||
*
|
||||
* @return the name of the provider
|
||||
*/
|
||||
public String providerName() {
|
||||
return p.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* The key decapsulation function.
|
||||
* <p>
|
||||
* This method is equivalent to
|
||||
* {@code decapsulate(encapsulation, 0, secretSize(), "Generic")}. This
|
||||
* combination of arguments must be supported by every implementation.
|
||||
* <p>
|
||||
* The generated secret key is usually passed to a key derivation
|
||||
* function (KDF) as the input keying material.
|
||||
*
|
||||
* @param encapsulation the key encapsulation message from the sender.
|
||||
* The size must be equal to the value returned by
|
||||
* {@link #encapsulationSize()}, or a {@code DecapsulateException}
|
||||
* will be thrown.
|
||||
* @return the shared secret as a {@code SecretKey} with
|
||||
* an algorithm name of "Generic"
|
||||
* @throws DecapsulateException if an error occurs during the
|
||||
* decapsulation process
|
||||
* @throws NullPointerException if {@code encapsulation} is {@code null}
|
||||
*/
|
||||
public SecretKey decapsulate(byte[] encapsulation) throws DecapsulateException {
|
||||
return decapsulate(encapsulation, 0, secretSize(), "Generic");
|
||||
}
|
||||
|
||||
/**
|
||||
* The key decapsulation function.
|
||||
* <p>
|
||||
* An invocation of this method recovers the secret key from the key
|
||||
* encapsulation message.
|
||||
* <p>
|
||||
* An implementation may choose to not support arbitrary combinations
|
||||
* of {@code from}, {@code to}, and {@code algorithm}.
|
||||
*
|
||||
* @param encapsulation the key encapsulation message from the sender.
|
||||
* The size must be equal to the value returned by
|
||||
* {@link #encapsulationSize()}, or a {@code DecapsulateException}
|
||||
* will be thrown.
|
||||
* @param from the initial index of the shared secret byte array
|
||||
* to be returned, inclusive
|
||||
* @param to the final index of the shared secret byte array
|
||||
* to be returned, exclusive
|
||||
* @param algorithm the algorithm name for the secret key that is returned
|
||||
* @return a portion of the shared secret as a {@code SecretKey}
|
||||
* containing the bytes of the secret ranging from {@code from}
|
||||
* to {@code to}, exclusive, and an algorithm name as specified.
|
||||
* For example, {@code decapsulate(encapsulation, secretSize()
|
||||
* - 16, secretSize(), "AES")} uses the last 16 bytes
|
||||
* of the shared secret as a 128-bit AES key.
|
||||
* @throws DecapsulateException if an error occurs during the
|
||||
* decapsulation process
|
||||
* @throws IndexOutOfBoundsException if {@code from < 0},
|
||||
* {@code from > to}, or {@code to > secretSize()}
|
||||
* @throws NullPointerException if {@code encapsulation} or
|
||||
* {@code algorithm} is {@code null}
|
||||
* @throws UnsupportedOperationException if the combination of
|
||||
* {@code from}, {@code to}, and {@code algorithm}
|
||||
* is not supported by the decapsulator
|
||||
*/
|
||||
public SecretKey decapsulate(byte[] encapsulation,
|
||||
int from, int to, String algorithm)
|
||||
throws DecapsulateException {
|
||||
return d.engineDecapsulate(
|
||||
encapsulation,
|
||||
from, to,
|
||||
algorithm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the shared secret.
|
||||
* <p>
|
||||
* This method can be called to find out the length of the shared secret
|
||||
* before {@code decapsulate} is called or if the obtained
|
||||
* {@code SecretKey} is not extractable.
|
||||
*
|
||||
* @return the size of the shared secret
|
||||
*/
|
||||
public int secretSize() {
|
||||
int result = d.engineSecretSize();
|
||||
assert result >= 0 && result != Integer.MAX_VALUE
|
||||
: "invalid engineSecretSize result";
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the key encapsulation message.
|
||||
* <p>
|
||||
* This method can be used to extract the encapsulation message
|
||||
* from a longer byte array if no length information is provided
|
||||
* by a higher level protocol.
|
||||
*
|
||||
* @return the size of the key encapsulation message
|
||||
*/
|
||||
public int encapsulationSize() {
|
||||
int result = d.engineEncapsulationSize();
|
||||
assert result >= 0 && result != Integer.MAX_VALUE
|
||||
: "invalid engineEncapsulationSize result";
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class DelayedKEM {
|
||||
|
||||
private final Provider.Service[] list; // non empty array
|
||||
|
||||
private DelayedKEM(Provider.Service[] list) {
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
private Encapsulator newEncapsulator(PublicKey publicKey,
|
||||
AlgorithmParameterSpec spec, SecureRandom secureRandom)
|
||||
throws InvalidAlgorithmParameterException, InvalidKeyException {
|
||||
if (publicKey == null) {
|
||||
throw new InvalidKeyException("input key is null");
|
||||
}
|
||||
RuntimeException re = null;
|
||||
InvalidAlgorithmParameterException iape = null;
|
||||
InvalidKeyException ike = null;
|
||||
NoSuchAlgorithmException nsae = null;
|
||||
for (Provider.Service service : list) {
|
||||
if (!service.supportsParameter(publicKey)) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
KEMSpi spi = (KEMSpi) service.newInstance(null);
|
||||
return new Encapsulator(
|
||||
spi.engineNewEncapsulator(publicKey, spec, secureRandom),
|
||||
service.getProvider());
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
nsae = merge(nsae, e);
|
||||
} catch (InvalidAlgorithmParameterException e) {
|
||||
iape = merge(iape, e);
|
||||
} catch (InvalidKeyException e) {
|
||||
ike = merge(ike, e);
|
||||
} catch (RuntimeException e) {
|
||||
re = merge(re, e);
|
||||
}
|
||||
}
|
||||
if (iape != null) throw iape;
|
||||
if (ike != null) throw ike;
|
||||
if (nsae != null) {
|
||||
throw new InvalidKeyException("No installed provider found", nsae);
|
||||
}
|
||||
throw new InvalidKeyException("No installed provider supports this key: "
|
||||
+ publicKey.getClass().getName(), re);
|
||||
}
|
||||
|
||||
private static <T extends Exception> T merge(T e1, T e2) {
|
||||
if (e1 == null) {
|
||||
return e2;
|
||||
} else {
|
||||
e1.addSuppressed(e2);
|
||||
return e1;
|
||||
}
|
||||
}
|
||||
|
||||
private Decapsulator newDecapsulator(PrivateKey privateKey, AlgorithmParameterSpec spec)
|
||||
throws InvalidAlgorithmParameterException, InvalidKeyException {
|
||||
if (privateKey == null) {
|
||||
throw new InvalidKeyException("input key is null");
|
||||
}
|
||||
RuntimeException re = null;
|
||||
InvalidAlgorithmParameterException iape = null;
|
||||
InvalidKeyException ike = null;
|
||||
NoSuchAlgorithmException nsae = null;
|
||||
for (Provider.Service service : list) {
|
||||
if (!service.supportsParameter(privateKey)) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
KEMSpi spi = (KEMSpi) service.newInstance(null);
|
||||
return new Decapsulator(
|
||||
spi.engineNewDecapsulator(privateKey, spec),
|
||||
service.getProvider());
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
nsae = merge(nsae, e);
|
||||
} catch (InvalidAlgorithmParameterException e) {
|
||||
iape = merge(iape, e);
|
||||
} catch (InvalidKeyException e) {
|
||||
ike = merge(ike, e);
|
||||
} catch (RuntimeException e) {
|
||||
re = merge(re, e);
|
||||
}
|
||||
}
|
||||
if (iape != null) throw iape;
|
||||
if (ike != null) throw ike;
|
||||
if (nsae != null) {
|
||||
throw new InvalidKeyException("No installed provider found", nsae);
|
||||
}
|
||||
throw new InvalidKeyException("No installed provider supports this key: "
|
||||
+ privateKey.getClass().getName(), re);
|
||||
}
|
||||
}
|
||||
|
||||
// If delayed provider selection is needed
|
||||
private final DelayedKEM delayed;
|
||||
|
||||
// otherwise
|
||||
private final KEMSpi spi;
|
||||
private final Provider provider;
|
||||
|
||||
private final String algorithm;
|
||||
|
||||
private KEM(String algorithm, KEMSpi spi, Provider provider) {
|
||||
assert spi != null;
|
||||
assert provider != null;
|
||||
this.delayed = null;
|
||||
this.spi = spi;
|
||||
this.provider = provider;
|
||||
this.algorithm = algorithm;
|
||||
}
|
||||
|
||||
private KEM(String algorithm, DelayedKEM delayed) {
|
||||
assert delayed != null;
|
||||
this.delayed = delayed;
|
||||
this.spi = null;
|
||||
this.provider = null;
|
||||
this.algorithm = algorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code KEM} object that implements the specified algorithm.
|
||||
*
|
||||
* @param algorithm the name of the KEM algorithm.
|
||||
* See the {@code KEM} section in the <a href=
|
||||
* "{@docRoot}/../specs/security/standard-names.html#kem-algorithms">
|
||||
* Java Security Standard Algorithm Names Specification</a>
|
||||
* for information about standard KEM algorithm names.
|
||||
* @return the new {@code KEM} object
|
||||
* @throws NoSuchAlgorithmException if no {@code Provider} supports a
|
||||
* {@code KEM} implementation for the specified algorithm
|
||||
* @throws NullPointerException if {@code algorithm} is {@code null}
|
||||
*/
|
||||
public static KEM getInstance(String algorithm)
|
||||
throws NoSuchAlgorithmException {
|
||||
List<Provider.Service> list = GetInstance.getServices(
|
||||
"KEM",
|
||||
Objects.requireNonNull(algorithm, "null algorithm name"));
|
||||
if (list.isEmpty()) {
|
||||
throw new NoSuchAlgorithmException(algorithm + " KEM not available");
|
||||
}
|
||||
return new KEM(algorithm, new DelayedKEM(list.toArray(new Provider.Service[0])));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code KEM} object that implements the specified algorithm
|
||||
* from the specified security provider.
|
||||
*
|
||||
* @param algorithm the name of the KEM algorithm.
|
||||
* See the {@code KEM} section in the <a href=
|
||||
* "{@docRoot}/../specs/security/standard-names.html#kem-algorithms">
|
||||
* Java Security Standard Algorithm Names Specification</a>
|
||||
* for information about standard KEM algorithm names.
|
||||
* @param provider the provider. If {@code null}, this method is equivalent
|
||||
* to {@link #getInstance(String)}.
|
||||
* @return the new {@code KEM} object
|
||||
* @throws NoSuchAlgorithmException if a {@code provider} is specified and
|
||||
* it does not support the specified KEM algorithm,
|
||||
* or if {@code provider} is {@code null} and there is no provider
|
||||
* that supports a KEM implementation of the specified algorithm
|
||||
* @throws NullPointerException if {@code algorithm} is {@code null}
|
||||
*/
|
||||
public static KEM getInstance(String algorithm, Provider provider)
|
||||
throws NoSuchAlgorithmException {
|
||||
if (provider == null) {
|
||||
return getInstance(algorithm);
|
||||
}
|
||||
GetInstance.Instance instance = GetInstance.getInstance(
|
||||
"KEM",
|
||||
KEMSpi.class,
|
||||
Objects.requireNonNull(algorithm, "null algorithm name"),
|
||||
provider);
|
||||
return new KEM(algorithm, (KEMSpi) instance.impl, instance.provider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code KEM} object that implements the specified algorithm
|
||||
* from the specified security provider.
|
||||
*
|
||||
* @param algorithm the name of the KEM algorithm.
|
||||
* See the {@code KEM} section in the <a href=
|
||||
* "{@docRoot}/../specs/security/standard-names.html#kem-algorithms">
|
||||
* Java Security Standard Algorithm Names Specification</a>
|
||||
* for information about standard KEM algorithm names.
|
||||
* @param provider the provider. If {@code null}, this method is equivalent
|
||||
* to {@link #getInstance(String)}.
|
||||
* @return the new {@code KEM} object
|
||||
* @throws NoSuchAlgorithmException if a {@code provider} is specified and
|
||||
* it does not support the specified KEM algorithm,
|
||||
* or if {@code provider} is {@code null} and there is no provider
|
||||
* that supports a KEM implementation of the specified algorithm
|
||||
* @throws NoSuchProviderException if the specified provider is not
|
||||
* registered in the security provider list
|
||||
* @throws NullPointerException if {@code algorithm} is {@code null}
|
||||
*/
|
||||
public static KEM getInstance(String algorithm, String provider)
|
||||
throws NoSuchAlgorithmException, NoSuchProviderException {
|
||||
if (provider == null) {
|
||||
return getInstance(algorithm);
|
||||
}
|
||||
GetInstance.Instance instance = GetInstance.getInstance(
|
||||
"KEM",
|
||||
KEMSpi.class,
|
||||
Objects.requireNonNull(algorithm, "null algorithm name"),
|
||||
provider);
|
||||
return new KEM(algorithm, (KEMSpi) instance.impl, instance.provider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a KEM encapsulator on the KEM sender side.
|
||||
* <p>
|
||||
* This method is equivalent to {@code newEncapsulator(publicKey, null, null)}.
|
||||
*
|
||||
* @param publicKey the receiver's public key, must not be {@code null}
|
||||
* @return the encapsulator for this key
|
||||
* @throws InvalidKeyException if {@code publicKey} is {@code null} or invalid
|
||||
* @throws UnsupportedOperationException if this method is not supported
|
||||
* because an {@code AlgorithmParameterSpec} must be provided
|
||||
*/
|
||||
public Encapsulator newEncapsulator(PublicKey publicKey)
|
||||
throws InvalidKeyException {
|
||||
try {
|
||||
return newEncapsulator(publicKey, null, null);
|
||||
} catch (InvalidAlgorithmParameterException e) {
|
||||
throw new UnsupportedOperationException(
|
||||
"AlgorithmParameterSpec must be provided", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a KEM encapsulator on the KEM sender side.
|
||||
* <p>
|
||||
* This method is equivalent to {@code newEncapsulator(publicKey, null, secureRandom)}.
|
||||
*
|
||||
* @param publicKey the receiver's public key, must not be {@code null}
|
||||
* @param secureRandom the source of randomness for encapsulation.
|
||||
* If {@code} null, a default one from the
|
||||
* implementation will be used.
|
||||
* @return the encapsulator for this key
|
||||
* @throws InvalidKeyException if {@code publicKey} is {@code null} or invalid
|
||||
* @throws UnsupportedOperationException if this method is not supported
|
||||
* because an {@code AlgorithmParameterSpec} must be provided
|
||||
*/
|
||||
public Encapsulator newEncapsulator(PublicKey publicKey, SecureRandom secureRandom)
|
||||
throws InvalidKeyException {
|
||||
try {
|
||||
return newEncapsulator(publicKey, null, secureRandom);
|
||||
} catch (InvalidAlgorithmParameterException e) {
|
||||
throw new UnsupportedOperationException(
|
||||
"AlgorithmParameterSpec must be provided", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a KEM encapsulator on the KEM sender side.
|
||||
* <p>
|
||||
* An algorithm can define an {@code AlgorithmParameterSpec} child class to
|
||||
* provide extra information in this method. This is especially useful if
|
||||
* the same key can be used to derive shared secrets in different ways.
|
||||
* If any extra information inside this object needs to be transmitted along
|
||||
* with the key encapsulation message so that the receiver is able to create
|
||||
* a matching decapsulator, it will be included as a byte array in the
|
||||
* {@link Encapsulated#params} field inside the encapsulation output.
|
||||
* In this case, the security provider should provide an
|
||||
* {@code AlgorithmParameters} implementation using the same algorithm name
|
||||
* as the KEM. The receiver can initiate such an {@code AlgorithmParameters}
|
||||
* instance with the {@code params} byte array received and recover
|
||||
* an {@code AlgorithmParameterSpec} object to be used in its
|
||||
* {@link #newDecapsulator(PrivateKey, AlgorithmParameterSpec)} call.
|
||||
*
|
||||
* @param publicKey the receiver's public key, must not be {@code null}
|
||||
* @param spec the optional parameter, can be {@code null}
|
||||
* @param secureRandom the source of randomness for encapsulation.
|
||||
* If {@code} null, a default one from the
|
||||
* implementation will be used.
|
||||
* @return the encapsulator for this key
|
||||
* @throws InvalidAlgorithmParameterException if {@code spec} is invalid
|
||||
* or one is required but {@code spec} is {@code null}
|
||||
* @throws InvalidKeyException if {@code publicKey} is {@code null} or invalid
|
||||
*/
|
||||
public Encapsulator newEncapsulator(PublicKey publicKey,
|
||||
AlgorithmParameterSpec spec, SecureRandom secureRandom)
|
||||
throws InvalidAlgorithmParameterException, InvalidKeyException {
|
||||
return delayed != null
|
||||
? delayed.newEncapsulator(publicKey, spec, secureRandom)
|
||||
: new Encapsulator(spi.engineNewEncapsulator(publicKey, spec, secureRandom), provider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a KEM decapsulator on the KEM receiver side.
|
||||
* <p>
|
||||
* This method is equivalent to {@code newDecapsulator(privateKey, null)}.
|
||||
*
|
||||
* @param privateKey the receiver's private key, must not be {@code null}
|
||||
* @return the decapsulator for this key
|
||||
* @throws InvalidKeyException if {@code privateKey} is {@code null} or invalid
|
||||
* @throws UnsupportedOperationException if this method is not supported
|
||||
* because an {@code AlgorithmParameterSpec} must be provided
|
||||
*/
|
||||
public Decapsulator newDecapsulator(PrivateKey privateKey)
|
||||
throws InvalidKeyException {
|
||||
try {
|
||||
return newDecapsulator(privateKey, null);
|
||||
} catch (InvalidAlgorithmParameterException e) {
|
||||
throw new UnsupportedOperationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a KEM decapsulator on the KEM receiver side.
|
||||
*
|
||||
* @param privateKey the receiver's private key, must not be {@code null}
|
||||
* @param spec the parameter, can be {@code null}
|
||||
* @return the decapsulator for this key
|
||||
* @throws InvalidAlgorithmParameterException if {@code spec} is invalid
|
||||
* or one is required but {@code spec} is {@code null}
|
||||
* @throws InvalidKeyException if {@code privateKey} is {@code null} or invalid
|
||||
*/
|
||||
public Decapsulator newDecapsulator(PrivateKey privateKey, AlgorithmParameterSpec spec)
|
||||
throws InvalidAlgorithmParameterException, InvalidKeyException {
|
||||
return delayed != null
|
||||
? delayed.newDecapsulator(privateKey, spec)
|
||||
: new Decapsulator(spi.engineNewDecapsulator(privateKey, spec), provider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the algorithm for this {@code KEM} object.
|
||||
*
|
||||
* @return the name of the algorithm for this {@code KEM} object.
|
||||
*/
|
||||
public String getAlgorithm() {
|
||||
return this.algorithm;
|
||||
}
|
||||
}
|
256
src/java.base/share/classes/javax/crypto/KEMSpi.java
Normal file
256
src/java.base/share/classes/javax/crypto/KEMSpi.java
Normal file
|
@ -0,0 +1,256 @@
|
|||
/*
|
||||
* Copyright (c) 2023, 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 javax.crypto;
|
||||
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.spec.AlgorithmParameterSpec;
|
||||
|
||||
/**
|
||||
* This class defines the Service Provider Interface (SPI) for the {@link KEM}
|
||||
* class. A security provider implements this interface to provide an
|
||||
* implementation of a Key Encapsulation Mechanism (KEM) algorithm.
|
||||
* <p>
|
||||
* A KEM algorithm may support a family of configurations. Each configuration
|
||||
* may accept different types of keys, cryptographic primitives, and sizes of
|
||||
* shared secrets and key encapsulation messages. A configuration is defined
|
||||
* by the KEM algorithm name, the key it uses, and an optional
|
||||
* {@code AlgorithmParameterSpec} argument that is specified when creating
|
||||
* an encapsulator or decapsulator. The result of calling
|
||||
* {@link #engineNewEncapsulator} or {@link #engineNewDecapsulator} must return
|
||||
* an encapsulator or decapsulator that maps to a single configuration,
|
||||
* where its {@code engineSecretSize()} and {@code engineEncapsulationSize()}
|
||||
* methods return constant values.
|
||||
* <p>
|
||||
* A {@code KEMSpi} implementation must be immutable. It must be safe to
|
||||
* call multiple {@code engineNewEncapsulator} and {@code engineNewDecapsulator}
|
||||
* methods at the same time.
|
||||
* <p>
|
||||
* {@code EncapsulatorSpi} and {@code DecapsulatorSpi} implementations must also
|
||||
* be immutable. It must be safe to invoke multiple {@code encapsulate} and
|
||||
* {@code decapsulate} methods at the same time. Each invocation of
|
||||
* {@code encapsulate} should generate a new shared secret and key
|
||||
* encapsulation message.
|
||||
* <p>
|
||||
* For example,
|
||||
* {@snippet lang = java:
|
||||
* public static class MyKEMImpl implements KEMSpi {
|
||||
*
|
||||
* @Override
|
||||
* public KEMSpi.EncapsulatorSpi engineNewEncapsulator(PublicKey publicKey,
|
||||
* AlgorithmParameterSpec spec, SecureRandom secureRandom)
|
||||
* throws InvalidAlgorithmParameterException, InvalidKeyException {
|
||||
* if (!checkPublicKey(publicKey)) {
|
||||
* throw new InvalidKeyException("unsupported key");
|
||||
* }
|
||||
* if (!checkParameters(spec)) {
|
||||
* throw new InvalidAlgorithmParameterException("unsupported params");
|
||||
* }
|
||||
* return new MyEncapsulator(publicKey, spec, secureRandom);
|
||||
* }
|
||||
*
|
||||
* class MyEncapsulator implements KEMSpi.EncapsulatorSpi {
|
||||
* MyEncapsulator(PublicKey publicKey, AlgorithmParameterSpec spec,
|
||||
* SecureRandom secureRandom){
|
||||
* this.spec = spec != null ? spec : getDefaultParameters();
|
||||
* this.secureRandom = secureRandom != null
|
||||
* ? secureRandom
|
||||
* : getDefaultSecureRandom();
|
||||
* this.publicKey = publicKey;
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public KEM.Encapsulated encapsulate(int from, int to, String algorithm) {
|
||||
* byte[] encapsulation;
|
||||
* byte[] secret;
|
||||
* // calculating...
|
||||
* return new KEM.Encapsulated(
|
||||
* new SecretKeySpec(secret, from, to - from, algorithm),
|
||||
* encapsulation, null);
|
||||
* }
|
||||
*
|
||||
* // ...
|
||||
* }
|
||||
*
|
||||
* // ...
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @see KEM
|
||||
* @since 21
|
||||
*/
|
||||
public interface KEMSpi {
|
||||
|
||||
/**
|
||||
* The KEM encapsulator implementation, generated by
|
||||
* {@link #engineNewEncapsulator} on the KEM sender side.
|
||||
*
|
||||
* @see KEM.Encapsulator
|
||||
*
|
||||
* @since 21
|
||||
*/
|
||||
interface EncapsulatorSpi {
|
||||
/**
|
||||
* The key encapsulation function.
|
||||
* <p>
|
||||
* Each invocation of this method must generate a new secret key and key
|
||||
* encapsulation message that is returned in an {@link KEM.Encapsulated} object.
|
||||
* <p>
|
||||
* An implementation must support the case where {@code from} is 0,
|
||||
* {@code to} is the same as the return value of {@code secretSize()},
|
||||
* and {@code algorithm} is "Generic".
|
||||
*
|
||||
* @param from the initial index of the shared secret byte array
|
||||
* to be returned, inclusive
|
||||
* @param to the final index of the shared secret byte array
|
||||
* to be returned, exclusive
|
||||
* @param algorithm the algorithm name for the secret key that is returned
|
||||
* @return an {@link KEM.Encapsulated} object containing a portion of
|
||||
* the shared secret as a key with the specified algorithm,
|
||||
* key encapsulation message, and optional parameters.
|
||||
* @throws IndexOutOfBoundsException if {@code from < 0},
|
||||
* {@code from > to}, or {@code to > secretSize()}
|
||||
* @throws NullPointerException if {@code algorithm} is {@code null}
|
||||
* @throws UnsupportedOperationException if the combination of
|
||||
* {@code from}, {@code to}, and {@code algorithm}
|
||||
* is not supported by the encapsulator
|
||||
* @see KEM.Encapsulated
|
||||
* @see KEM.Encapsulator#encapsulate(int, int, String)
|
||||
*/
|
||||
KEM.Encapsulated engineEncapsulate(int from, int to, String algorithm);
|
||||
|
||||
/**
|
||||
* Returns the size of the shared secret.
|
||||
*
|
||||
* @return the size of the shared secret as a finite non-negative integer
|
||||
* @see KEM.Encapsulator#secretSize()
|
||||
*/
|
||||
int engineSecretSize();
|
||||
|
||||
/**
|
||||
* Returns the size of the key encapsulation message.
|
||||
*
|
||||
* @return the size of the key encapsulation message as a finite non-negative integer
|
||||
* @see KEM.Encapsulator#encapsulationSize()
|
||||
*/
|
||||
int engineEncapsulationSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* The KEM decapsulator implementation, generated by
|
||||
* {@link #engineNewDecapsulator} on the KEM receiver side.
|
||||
*
|
||||
* @see KEM.Decapsulator
|
||||
*
|
||||
* @since 21
|
||||
*/
|
||||
interface DecapsulatorSpi {
|
||||
/**
|
||||
* The key decapsulation function.
|
||||
* <p>
|
||||
* An invocation of this method recovers the secret key from the key
|
||||
* encapsulation message.
|
||||
* <p>
|
||||
* An implementation must support the case where {@code from} is 0,
|
||||
* {@code to} is the same as the return value of {@code secretSize()},
|
||||
* and {@code algorithm} is "Generic".
|
||||
*
|
||||
* @param encapsulation the key encapsulation message from the sender.
|
||||
* The size must be equal to the value returned by
|
||||
* {@link #engineEncapsulationSize()} ()}, or a
|
||||
* {@code DecapsulateException} must be thrown.
|
||||
* @param from the initial index of the shared secret byte array
|
||||
* to be returned, inclusive
|
||||
* @param to the final index of the shared secret byte array
|
||||
* to be returned, exclusive
|
||||
* @param algorithm the algorithm name for the secret key that is returned
|
||||
* @return a portion of the shared secret as a {@code SecretKey} with
|
||||
* the specified algorithm
|
||||
* @throws DecapsulateException if an error occurs during the
|
||||
* decapsulation process
|
||||
* @throws IndexOutOfBoundsException if {@code from < 0},
|
||||
* {@code from > to}, or {@code to > secretSize()}
|
||||
* @throws NullPointerException if {@code encapsulation} or
|
||||
* {@code algorithm} is {@code null}
|
||||
* @throws UnsupportedOperationException if the combination of
|
||||
* {@code from}, {@code to}, and {@code algorithm}
|
||||
* is not supported by the decapsulator
|
||||
* @see KEM.Decapsulator#decapsulate(byte[], int, int, String)
|
||||
*/
|
||||
SecretKey engineDecapsulate(byte[] encapsulation, int from, int to, String algorithm)
|
||||
throws DecapsulateException;
|
||||
|
||||
/**
|
||||
* Returns the size of the shared secret.
|
||||
*
|
||||
* @return the size of the shared secret as a finite non-negative integer
|
||||
* @see KEM.Decapsulator#secretSize()
|
||||
*/
|
||||
int engineSecretSize();
|
||||
|
||||
/**
|
||||
* Returns the size of the key encapsulation message.
|
||||
*
|
||||
* @return the size of the key encapsulation message as a finite non-negative integer
|
||||
* @see KEM.Decapsulator#encapsulationSize()
|
||||
*/
|
||||
int engineEncapsulationSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a KEM encapsulator on the KEM sender side.
|
||||
*
|
||||
* @param publicKey the receiver's public key, must not be {@code null}
|
||||
* @param spec the optional parameter, can be {@code null}
|
||||
* @param secureRandom the source of randomness for encapsulation.
|
||||
* If {@code null}, the implementation must provide
|
||||
* a default one.
|
||||
* @return the encapsulator for this key
|
||||
* @throws InvalidAlgorithmParameterException if {@code spec} is invalid
|
||||
* or one is required but {@code spec} is {@code null}
|
||||
* @throws InvalidKeyException if {@code publicKey} is {@code null} or invalid
|
||||
* @see KEM#newEncapsulator(PublicKey, AlgorithmParameterSpec, SecureRandom)
|
||||
*/
|
||||
EncapsulatorSpi engineNewEncapsulator(PublicKey publicKey,
|
||||
AlgorithmParameterSpec spec, SecureRandom secureRandom)
|
||||
throws InvalidAlgorithmParameterException, InvalidKeyException;
|
||||
|
||||
/**
|
||||
* Creates a KEM decapsulator on the KEM receiver side.
|
||||
*
|
||||
* @param privateKey the receiver's private key, must not be {@code null}
|
||||
* @param spec the optional parameter, can be {@code null}
|
||||
* @return the decapsulator for this key
|
||||
* @throws InvalidAlgorithmParameterException if {@code spec} is invalid
|
||||
* or one is required but {@code spec} is {@code null}
|
||||
* @throws InvalidKeyException if {@code privateKey} is {@code null} or invalid
|
||||
* @see KEM#newDecapsulator(PrivateKey, AlgorithmParameterSpec)
|
||||
*/
|
||||
DecapsulatorSpi engineNewDecapsulator(PrivateKey privateKey, AlgorithmParameterSpec spec)
|
||||
throws InvalidAlgorithmParameterException, InvalidKeyException;
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2023, 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
|
||||
|
@ -43,7 +43,7 @@ import java.util.Objects;
|
|||
* digest algorithm will be used by the HMAC function as part of the HKDF
|
||||
* derivation process.
|
||||
*/
|
||||
final class HKDF {
|
||||
public final class HKDF {
|
||||
private final Mac hmacObj;
|
||||
private final int hmacLen;
|
||||
|
||||
|
@ -57,7 +57,7 @@ final class HKDF {
|
|||
* @throws NoSuchAlgorithmException if that message digest algorithm does
|
||||
* not have an HMAC variant supported on any available provider.
|
||||
*/
|
||||
HKDF(String hashAlg) throws NoSuchAlgorithmException {
|
||||
public HKDF(String hashAlg) throws NoSuchAlgorithmException {
|
||||
Objects.requireNonNull(hashAlg,
|
||||
"Must provide underlying HKDF Digest algorithm.");
|
||||
String hmacAlg = "Hmac" + hashAlg.replace("-", "");
|
||||
|
@ -82,7 +82,7 @@ final class HKDF {
|
|||
* @throws InvalidKeyException if the {@code salt} parameter cannot be
|
||||
* used to initialize the underlying HMAC.
|
||||
*/
|
||||
SecretKey extract(SecretKey salt, SecretKey inputKey, String keyAlg)
|
||||
public SecretKey extract(SecretKey salt, SecretKey inputKey, String keyAlg)
|
||||
throws InvalidKeyException {
|
||||
if (salt == null) {
|
||||
salt = new SecretKeySpec(new byte[hmacLen], "HKDF-Salt");
|
||||
|
@ -110,7 +110,7 @@ final class HKDF {
|
|||
* @throws InvalidKeyException if the {@code salt} parameter cannot be
|
||||
* used to initialize the underlying HMAC.
|
||||
*/
|
||||
SecretKey extract(byte[] salt, SecretKey inputKey, String keyAlg)
|
||||
public SecretKey extract(byte[] salt, SecretKey inputKey, String keyAlg)
|
||||
throws InvalidKeyException {
|
||||
if (salt == null) {
|
||||
salt = new byte[hmacLen];
|
||||
|
@ -133,7 +133,7 @@ final class HKDF {
|
|||
* @throws InvalidKeyException if the underlying HMAC operation cannot
|
||||
* be initialized using the provided {@code pseudoRandKey} object.
|
||||
*/
|
||||
SecretKey expand(SecretKey pseudoRandKey, byte[] info, int outLen,
|
||||
public SecretKey expand(SecretKey pseudoRandKey, byte[] info, int outLen,
|
||||
String keyAlg) throws InvalidKeyException {
|
||||
byte[] kdfOutput;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2006, 2023, 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
|
||||
|
@ -39,6 +39,11 @@ import java.util.*;
|
|||
* @author Andreas Sterbenz
|
||||
*/
|
||||
public class CurveDB {
|
||||
|
||||
public static final NamedCurve P_256;
|
||||
public static final NamedCurve P_384;
|
||||
public static final NamedCurve P_521;
|
||||
|
||||
private static final int P = 1; // prime curve
|
||||
private static final int B = 2; // binary curve
|
||||
private static final int PD = 5; // prime curve, mark as default
|
||||
|
@ -109,7 +114,7 @@ public class CurveDB {
|
|||
return new BigInteger(s, 16);
|
||||
}
|
||||
|
||||
private static void add(KnownOIDs o, int type, String sfield,
|
||||
private static NamedCurve add(KnownOIDs o, int type, String sfield,
|
||||
String a, String b, String x, String y, String n, int h) {
|
||||
BigInteger p = bi(sfield);
|
||||
ECField field;
|
||||
|
@ -143,6 +148,8 @@ public class CurveDB {
|
|||
// the curve is marked as a default curve.
|
||||
lengthMap.put(len, params);
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
static {
|
||||
|
@ -255,7 +262,7 @@ public class CurveDB {
|
|||
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141",
|
||||
1);
|
||||
|
||||
add(KnownOIDs.secp256r1, PD,
|
||||
P_256 = add(KnownOIDs.secp256r1, PD,
|
||||
"FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
|
||||
"FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
|
||||
"5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
|
||||
|
@ -264,7 +271,7 @@ public class CurveDB {
|
|||
"FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
|
||||
1);
|
||||
|
||||
add(KnownOIDs.secp384r1, PD,
|
||||
P_384 = add(KnownOIDs.secp384r1, PD,
|
||||
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF",
|
||||
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC",
|
||||
"B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF",
|
||||
|
@ -273,7 +280,7 @@ public class CurveDB {
|
|||
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973",
|
||||
1);
|
||||
|
||||
add(KnownOIDs.secp521r1, PD,
|
||||
P_521 = add(KnownOIDs.secp521r1, PD,
|
||||
"01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
|
||||
"01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC",
|
||||
"0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue