diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DHKEM.java b/src/java.base/share/classes/com/sun/crypto/provider/DHKEM.java
index 3fa6b14762ac2..e07e73f7baf8b 100644
--- a/src/java.base/share/classes/com/sun/crypto/provider/DHKEM.java
+++ b/src/java.base/share/classes/com/sun/crypto/provider/DHKEM.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2025, 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
@@ -26,21 +26,49 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.io.Serial;
import java.math.BigInteger;
-import java.security.*;
-import java.security.interfaces.ECKey;
+import java.security.AsymmetricKey;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.ProviderException;
+import java.security.PublicKey;
+import java.security.SecureRandom;
import java.security.interfaces.ECPublicKey;
-import java.security.interfaces.XECKey;
import java.security.interfaces.XECPublicKey;
-import java.security.spec.*;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPrivateKeySpec;
+import java.security.spec.ECPublicKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.NamedParameterSpec;
+import java.security.spec.XECPrivateKeySpec;
+import java.security.spec.XECPublicKeySpec;
import java.util.Arrays;
import java.util.Objects;
-import javax.crypto.*;
+import javax.crypto.DecapsulateException;
+import javax.crypto.KDF;
+import javax.crypto.KEM;
+import javax.crypto.KEMSpi;
+import javax.crypto.KeyAgreement;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.HKDFParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import sun.security.jca.JCAUtil;
-import sun.security.ssl.HKDF;
-import sun.security.util.*;
+import sun.security.util.ArrayUtil;
+import sun.security.util.CurveDB;
+import sun.security.util.ECUtil;
+import sun.security.util.InternalPrivateKey;
+import sun.security.util.NamedCurve;
+import sun.security.util.SliceableSecretKey;
// Implementing DHKEM defined inside https://www.rfc-editor.org/rfc/rfc9180.html,
// without the AuthEncap and AuthDecap functions
@@ -77,11 +105,11 @@ public KEM.Encapsulated engineEncapsulate(int from, int to, String algorithm) {
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);
+ SecretKey key = params.deriveKey(algorithm, from, to, kem_context,
+ params.DH(skE, pkR));
+ return new KEM.Encapsulated(key, pkEm, null);
+ } catch (UnsupportedOperationException e) {
+ throw e;
} catch (Exception e) {
throw new ProviderException("internal error", e);
}
@@ -98,11 +126,12 @@ public SecretKey engineDecapsulate(byte[] encapsulation,
}
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);
+ return params.deriveKey(algorithm, from, to, kem_context,
+ params.DH(skR, pkE));
+ } catch (UnsupportedOperationException e) {
+ throw e;
} catch (IOException | InvalidKeyException e) {
throw new DecapsulateException("Cannot decapsulate", e);
} catch (Exception e) {
@@ -124,7 +153,8 @@ public int engineEncapsulationSize() {
// 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;
+ @Serial
+ private static final long serialVersionUID = 0L;
private final byte[] ikm;
@@ -133,7 +163,7 @@ public RFC9180DeriveKeyPairSR(byte[] ikm) {
this.ikm = ikm;
}
- public KeyPair derive(Params params) {
+ private KeyPair derive(Params params) {
try {
return params.deriveKeyPair(ikm);
} catch (Exception e) {
@@ -153,19 +183,19 @@ public KeyPair derive(int kem_id) {
private enum Params {
P256(0x10, 32, 32, 2 * 32 + 1,
- "ECDH", "EC", CurveDB.P_256, "SHA-256"),
+ "ECDH", "EC", CurveDB.P_256, "HKDF-SHA256"),
P384(0x11, 48, 48, 2 * 48 + 1,
- "ECDH", "EC", CurveDB.P_384, "SHA-384"),
+ "ECDH", "EC", CurveDB.P_384, "HKDF-SHA384"),
P521(0x12, 64, 66, 2 * 66 + 1,
- "ECDH", "EC", CurveDB.P_521, "SHA-512"),
+ "ECDH", "EC", CurveDB.P_521, "HKDF-SHA512"),
X25519(0x20, 32, 32, 32,
- "XDH", "XDH", NamedParameterSpec.X25519, "SHA-256"),
+ "XDH", "XDH", NamedParameterSpec.X25519, "HKDF-SHA256"),
X448(0x21, 64, 56, 56,
- "XDH", "XDH", NamedParameterSpec.X448, "SHA-512"),
+ "XDH", "XDH", NamedParameterSpec.X448, "HKDF-SHA512"),
;
private final int kem_id;
@@ -237,20 +267,53 @@ private PublicKey DeserializePublicKey(byte[] data)
return KeyFactory.getInstance(keyAlgorithm).generatePublic(keySpec);
}
- private byte[] DH(PrivateKey skE, PublicKey pkR)
+ private SecretKey DH(PrivateKey skE, PublicKey pkR)
throws NoSuchAlgorithmException, InvalidKeyException {
KeyAgreement ka = KeyAgreement.getInstance(kaAlgorithm);
ka.init(skE);
ka.doPhase(pkR, true);
- return ka.generateSecret();
+ return ka.generateSecret("Generic");
}
- 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);
+ // The final shared secret derivation of either the encapsulator
+ // or the decapsulator. The key slicing is implemented inside.
+ // Throws UOE if a slice of the key cannot be found.
+ private SecretKey deriveKey(String alg, int from, int to,
+ byte[] kem_context, SecretKey dh)
+ throws NoSuchAlgorithmException {
+ if (from == 0 && to == Nsecret) {
+ return ExtractAndExpand(kem_context, alg, dh);
+ } else {
+ // First get shared secrets in "Generic" and then get a slice
+ // of it in the requested algorithm.
+ var fullKey = ExtractAndExpand(kem_context, "Generic", dh);
+ if ("RAW".equalsIgnoreCase(fullKey.getFormat())) {
+ byte[] km = fullKey.getEncoded();
+ if (km == null) {
+ // Should not happen if format is "RAW"
+ throw new UnsupportedOperationException("Key extract failed");
+ } else {
+ return new SecretKeySpec(km, from, to - from, alg);
+ }
+ } else if (fullKey instanceof SliceableSecretKey ssk) {
+ return ssk.slice(alg, from, to);
+ } else {
+ throw new UnsupportedOperationException("Cannot extract key");
+ }
+ }
+ }
+
+ private SecretKey ExtractAndExpand(byte[] kem_context, String alg, SecretKey dh)
+ throws NoSuchAlgorithmException {
+ var kdf = KDF.getInstance(hkdfAlgorithm);
+ var builder = labeledExtract(suiteId, EAE_PRK);
+ builder.addIKM(dh);
+ try {
+ return kdf.deriveKey(alg,
+ labeledExpand(builder, suiteId, SHARED_SECRET, kem_context, Nsecret));
+ } catch (InvalidAlgorithmParameterException e) {
+ throw new ProviderException(e);
+ }
}
private PublicKey getPublicKey(PrivateKey sk)
@@ -277,18 +340,19 @@ private PublicKey getPublicKey(PrivateKey sk)
// 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);
+ var kdf = KDF.getInstance(hkdfAlgorithm);
+ var builder = labeledExtract(suiteId, DKP_PRK).addIKM(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();
+ // So unlucky and should not happen
+ throw new ProviderException("DeriveKeyPairError");
}
- byte[] bytes = LabeledExpand(kdf, suiteId, dkp_prk,
- CANDIDATE, I2OSP(counter, 1), Nsk);
+ byte[] bytes = kdf.deriveData(labeledExpand(builder,
+ suiteId, 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);
@@ -299,7 +363,8 @@ public KeyPair deriveKeyPair(byte[] ikm) throws Exception {
PrivateKey k = DeserializePrivateKey(sk.toByteArray());
return new KeyPair(getPublicKey(k), k);
} else {
- byte[] sk = LabeledExpand(kdf, suiteId, dkp_prk, SK, EMPTY, Nsk);
+ byte[] sk = kdf.deriveData(labeledExpand(builder,
+ suiteId, SK, EMPTY, Nsk));
PrivateKey k = DeserializePrivateKey(sk);
return new KeyPair(getPublicKey(k), k);
}
@@ -344,17 +409,17 @@ public DecapsulatorSpi engineNewDecapsulator(PrivateKey sk, AlgorithmParameterSp
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)) {
+ private Params paramsFromKey(AsymmetricKey k) throws InvalidKeyException {
+ var p = k.getParams();
+ if (p instanceof ECParameterSpec ecp) {
+ if (ECUtil.equals(ecp, CurveDB.P_256)) {
return Params.P256;
- } else if (ECUtil.equals(eckey.getParams(), CurveDB.P_384)) {
+ } else if (ECUtil.equals(ecp, CurveDB.P_384)) {
return Params.P384;
- } else if (ECUtil.equals(eckey.getParams(), CurveDB.P_521)) {
+ } else if (ECUtil.equals(ecp, CurveDB.P_521)) {
return Params.P521;
}
- } else if (k instanceof XECKey xkey
- && xkey.getParams() instanceof NamedParameterSpec ns) {
+ } else if (p instanceof NamedParameterSpec ns) {
if (ns.getName().equalsIgnoreCase("X25519")) {
return Params.X25519;
} else if (ns.getName().equalsIgnoreCase("X448")) {
@@ -370,8 +435,11 @@ private static byte[] concat(byte[]... inputs) {
return o.toByteArray();
}
- private static byte[] I2OSP(int n, int w) {
- assert n < 256;
+ // I2OSP(n, w) as defined in RFC 9180 Section 3.
+ // In DHKEM and HPKE, number is always <65536
+ // and converted to at most 2 bytes.
+ public static byte[] I2OSP(int n, int w) {
+ assert n < 65536;
assert w == 1 || w == 2;
if (w == 1) {
return new byte[] { (byte) n };
@@ -380,18 +448,32 @@ private static byte[] I2OSP(int n, int w) {
}
}
- 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");
+ // Create a LabeledExtract builder with labels.
+ // You can add more IKM and salt into the result.
+ public static HKDFParameterSpec.Builder labeledExtract(
+ byte[] suiteId, byte[] label) {
+ return HKDFParameterSpec.ofExtract()
+ .addIKM(HPKE_V1).addIKM(suiteId).addIKM(label);
+ }
+
+ // Create a labeled info from info and labels
+ private static byte[] labeledInfo(
+ byte[] suiteId, byte[] label, byte[] info, int L) {
+ return concat(I2OSP(L, 2), HPKE_V1, suiteId, label, info);
+ }
+
+ // LabeledExpand from a builder
+ public static HKDFParameterSpec labeledExpand(
+ HKDFParameterSpec.Builder builder,
+ byte[] suiteId, byte[] label, byte[] info, int L) {
+ return builder.thenExpand(
+ labeledInfo(suiteId, label, info, L), L);
}
- 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();
+ // LabeledExpand from a prk
+ public static HKDFParameterSpec labeledExpand(
+ SecretKey prk, byte[] suiteId, byte[] label, byte[] info, int L) {
+ return HKDFParameterSpec.expandOnly(
+ prk, labeledInfo(suiteId, label, info, L), L);
}
}
diff --git a/src/java.base/share/classes/sun/security/ec/ECPrivateKeyImpl.java b/src/java.base/share/classes/sun/security/ec/ECPrivateKeyImpl.java
index b1b8b2d188f2c..1ec3e21b8c197 100644
--- a/src/java.base/share/classes/sun/security/ec/ECPrivateKeyImpl.java
+++ b/src/java.base/share/classes/sun/security/ec/ECPrivateKeyImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2025, 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
@@ -35,8 +35,6 @@
import java.security.spec.*;
import java.util.Arrays;
-import sun.security.ec.point.AffinePoint;
-import sun.security.ec.point.MutablePoint;
import sun.security.util.*;
import sun.security.x509.AlgorithmId;
import sun.security.pkcs.PKCS8Key;
@@ -207,15 +205,8 @@ private void parseKeyBits() throws InvalidKeyException {
@Override
public PublicKey calculatePublicKey() {
- ECParameterSpec ecParams = getParams();
- ECOperations ops = ECOperations.forParameters(ecParams)
- .orElseThrow(ProviderException::new);
- MutablePoint pub = ops.multiply(ecParams.getGenerator(), getArrayS0());
- AffinePoint affPub = pub.asAffine();
- ECPoint w = new ECPoint(affPub.getX().asBigInteger(),
- affPub.getY().asBigInteger());
try {
- return new ECPublicKeyImpl(w, ecParams);
+ return ECUtil.sArrayToPublicKey(getArrayS0(), getParams());
} catch (InvalidKeyException e) {
throw new ProviderException(
"Unexpected error calculating public key", e);
diff --git a/src/java.base/share/classes/sun/security/ec/ECPublicKeyImpl.java b/src/java.base/share/classes/sun/security/ec/ECPublicKeyImpl.java
index 29894038a1d49..b057f0a749106 100644
--- a/src/java.base/share/classes/sun/security/ec/ECPublicKeyImpl.java
+++ b/src/java.base/share/classes/sun/security/ec/ECPublicKeyImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2025, 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
@@ -58,9 +58,9 @@ public final class ECPublicKeyImpl extends X509Key implements ECPublicKey {
/**
* Construct a key from its components. Used by the
- * ECKeyFactory.
+ * ECKeyFactory and ECUtil.
*/
- ECPublicKeyImpl(ECPoint w, ECParameterSpec params)
+ public ECPublicKeyImpl(ECPoint w, ECParameterSpec params)
throws InvalidKeyException {
this.w = w;
this.params = params;
@@ -142,4 +142,4 @@ private void readObject(ObjectInputStream stream)
throw new InvalidObjectException(
"ECPublicKeyImpl keys are not directly deserializable");
}
-}
\ No newline at end of file
+}
diff --git a/src/java.base/share/classes/sun/security/util/ECUtil.java b/src/java.base/share/classes/sun/security/util/ECUtil.java
index bcda2d7832cbe..24bd4a714c211 100644
--- a/src/java.base/share/classes/sun/security/util/ECUtil.java
+++ b/src/java.base/share/classes/sun/security/util/ECUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2025, 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
@@ -26,6 +26,10 @@
package sun.security.util;
import jdk.internal.access.SharedSecrets;
+import sun.security.ec.ECOperations;
+import sun.security.ec.ECPublicKeyImpl;
+import sun.security.ec.point.AffinePoint;
+import sun.security.ec.point.MutablePoint;
import java.io.IOException;
import java.math.BigInteger;
@@ -375,5 +379,17 @@ public static void validatePublicKey(ECPoint point, ECParameterSpec spec)
}
}
+ // Calculate an ECPublicKey from the private sArray component
+ public static ECPublicKey sArrayToPublicKey(byte[] sArray, ECParameterSpec params)
+ throws InvalidKeyException {
+ ECOperations ops = ECOperations.forParameters(params)
+ .orElseThrow(ProviderException::new);
+ MutablePoint pub = ops.multiply(params.getGenerator(), sArray);
+ AffinePoint affPub = pub.asAffine();
+ ECPoint w = new ECPoint(affPub.getX().asBigInteger(),
+ affPub.getY().asBigInteger());
+ return new ECPublicKeyImpl(w, params);
+ }
+
private ECUtil() {}
}
diff --git a/src/java.base/share/classes/sun/security/util/SliceableSecretKey.java b/src/java.base/share/classes/sun/security/util/SliceableSecretKey.java
new file mode 100644
index 0000000000000..0de16be1a2b7c
--- /dev/null
+++ b/src/java.base/share/classes/sun/security/util/SliceableSecretKey.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2025, 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.util;
+
+import javax.crypto.SecretKey;
+
+/**
+ * An interface for SecretKeys that support using its slice as a new
+ * SecretKey
+ *
+ * This is mainly used by PKCS #11 implementations that support the
+ * EXTRACT_KEY_FROM_KEY mechanism even if the key itself is sensitive
+ * and non-extractable.
+ */
+public interface SliceableSecretKey {
+
+ /**
+ * Returns a slice as a new SecretKey.
+ *
+ * @param alg the new algorithm name
+ * @param from the byte offset of the new key in the full key
+ * @param to the to offset (exclusive) of the new key in the full key
+ * @return the new key
+ * @throws ArrayIndexOutOfBoundsException for improper from
+ * and to values
+ * @throws UnsupportedOperationException if slicing is not supported
+ */
+ SecretKey slice(String alg, int from, int to);
+}
diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11ECKeyFactory.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11ECKeyFactory.java
index 9896cb738bb32..874205adb3258 100644
--- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11ECKeyFactory.java
+++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11ECKeyFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2025, 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
@@ -267,8 +267,14 @@ private PrivateKey generatePrivate(BigInteger s, ECParameterSpec params)
try {
session = token.getObjSession();
long keyID = token.p11.C_CreateObject(session.id(), attributes);
+ PublicKey pk = null;
+ try {
+ pk = ECUtil.sArrayToPublicKey(ECUtil.sArray(s, params), params);
+ } catch (Exception e) {
+ // Happens when params is not supported. Ignore it.
+ }
return P11Key.privateKey
- (session, keyID, "EC", params.getCurve().getField().getFieldSize(), attributes);
+ (session, keyID, "EC", params.getCurve().getField().getFieldSize(), attributes, pk);
} finally {
token.releaseSession(session);
}
diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java
index bb2211ab9c16c..b5a9c45e51385 100644
--- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java
+++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java
@@ -49,9 +49,11 @@
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
import sun.security.util.DerValue;
+import sun.security.util.InternalPrivateKey;
import sun.security.util.Length;
import sun.security.util.ECUtil;
import sun.security.jca.JCAUtil;
+import sun.security.util.SliceableSecretKey;
/**
* Key implementation classes.
@@ -399,6 +401,13 @@ static PublicKey publicKey(Session session, long keyID, String algorithm,
static PrivateKey privateKey(Session session, long keyID, String algorithm,
int keyLength, CK_ATTRIBUTE[] attrs) {
+ return privateKey(session, keyID, algorithm, keyLength, attrs, null);
+ }
+
+ // Create a PrivateKey with an optional PublicKey. The PublicKey is only
+ // added to EC keys at the moment.
+ static PrivateKey privateKey(Session session, long keyID, String algorithm,
+ int keyLength, CK_ATTRIBUTE[] attrs, PublicKey pk) {
attrs = getAttributes(session, keyID, attrs, new CK_ATTRIBUTE[] {
new CK_ATTRIBUTE(CKA_TOKEN),
new CK_ATTRIBUTE(CKA_SENSITIVE),
@@ -417,7 +426,7 @@ static PrivateKey privateKey(Session session, long keyID, String algorithm,
case "DH" -> P11DHPrivateKeyInternal.of(session, keyID, algorithm,
keyLength, attrs, keySensitive);
case "EC" -> P11ECPrivateKeyInternal.of(session, keyID, algorithm,
- keyLength, attrs, keySensitive);
+ keyLength, attrs, keySensitive, pk);
default -> throw new ProviderException
("Unknown private key algorithm " + algorithm);
};
@@ -446,7 +455,7 @@ byte[] getEncodedInternal() {
}
}
- static class P11SecretKey extends P11Key implements SecretKey {
+ static class P11SecretKey extends P11Key implements SecretKey, SliceableSecretKey {
@Serial
private static final long serialVersionUID = -7828241727014329084L;
@@ -486,6 +495,42 @@ byte[] getEncodedInternal() {
}
return b;
}
+
+ @Override
+ public P11SecretKey slice(String alg, int from, int to) {
+ Objects.checkFromToIndex(from, to, length() / 8);
+ try {
+ CK_MECHANISM mechanism = new CK_MECHANISM(CKM_EXTRACT_KEY_FROM_KEY,
+ new CK_KEY_EXTRACT_FROM_KEY(from * 8));
+
+ P11SecretKeyFactory.KeyInfo ki = P11SecretKeyFactory.getKeyInfo(alg);
+ if (ki == null) {
+ throw new UnsupportedOperationException("A PKCS #11 key " +
+ "type (CKK_*) was not found for a key of the algorithm '" +
+ alg + "'.");
+ }
+ CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] {
+ new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY),
+ new CK_ATTRIBUTE(CKA_KEY_TYPE, ki.keyType),
+ new CK_ATTRIBUTE(CKA_VALUE_LEN, to - from),
+ };
+
+ var session = token.getOpSession();
+ attrs = token.getAttributes(O_GENERATE, CKO_SECRET_KEY,
+ ki.keyType, attrs);
+ long newKeyHandle = token.p11.C_DeriveKey(
+ session.id(),
+ mechanism,
+ getKeyID(),
+ attrs
+ );
+
+ return (P11Key.P11SecretKey) P11Key.secretKey(session,
+ newKeyHandle, alg, (to - from) * 8, null);
+ } catch (PKCS11Exception e) {
+ throw new UnsupportedOperationException(e);
+ }
+ }
}
// base class for all PKCS11 public keys
@@ -1201,28 +1246,31 @@ public boolean equals(Object obj) {
}
}
- static class P11ECPrivateKeyInternal extends P11PrivateKey {
+ static class P11ECPrivateKeyInternal extends P11PrivateKey
+ implements ECKey, InternalPrivateKey {
@Serial
private static final long serialVersionUID = 1L;
+ private final PublicKey pk;
protected transient ECParameterSpec params;
static P11ECPrivateKeyInternal of(Session session, long keyID,
String algorithm, int keyLength, CK_ATTRIBUTE[] attrs,
- boolean keySensitive) {
+ boolean keySensitive, PublicKey pk) {
if (keySensitive) {
return new P11ECPrivateKeyInternal(session, keyID, algorithm,
- keyLength, attrs);
+ keyLength, attrs, pk);
} else {
return new P11ECPrivateKey(session, keyID, algorithm,
- keyLength, attrs);
+ keyLength, attrs, pk);
}
}
private P11ECPrivateKeyInternal(Session session, long keyID,
- String algorithm, int keyLength, CK_ATTRIBUTE[] attrs) {
+ String algorithm, int keyLength, CK_ATTRIBUTE[] attrs, PublicKey pk) {
super(session, keyID, algorithm, keyLength, attrs);
+ this.pk = pk;
}
private synchronized void fetchValues() {
@@ -1245,6 +1293,11 @@ public ECParameterSpec getParams() {
fetchValues();
return params;
}
+
+ @Override
+ public PublicKey calculatePublicKey() {
+ return pk;
+ }
}
private static final class P11ECPrivateKey extends P11ECPrivateKeyInternal
@@ -1255,8 +1308,8 @@ private static final class P11ECPrivateKey extends P11ECPrivateKeyInternal
private transient BigInteger s; // params in P11ECPrivateKeyInternal
P11ECPrivateKey(Session session, long keyID, String algorithm,
- int keyLength, CK_ATTRIBUTE[] attrs) {
- super(session, keyID, algorithm, keyLength, attrs);
+ int keyLength, CK_ATTRIBUTE[] attrs, PublicKey pk) {
+ super(session, keyID, algorithm, keyLength, attrs, pk);
}
private synchronized void fetchValues() {
diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyPairGenerator.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyPairGenerator.java
index d32ebc81ba1ed..81771205a8b94 100644
--- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyPairGenerator.java
+++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyPairGenerator.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2025, 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
@@ -427,7 +427,7 @@ public KeyPair generateKeyPair() {
PublicKey publicKey = P11Key.publicKey
(session, keyIDs[0], algorithm, keySize, publicKeyTemplate);
PrivateKey privateKey = P11Key.privateKey
- (session, keyIDs[1], algorithm, keySize, privateKeyTemplate);
+ (session, keyIDs[1], algorithm, keySize, privateKeyTemplate, publicKey);
return new KeyPair(publicKey, privateKey);
} catch (PKCS11Exception e) {
throw new ProviderException(e);
diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyStore.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyStore.java
index d1377b807fedf..d76562d1b61f0 100644
--- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyStore.java
+++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyStore.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2025, 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
@@ -313,7 +313,7 @@ public synchronized Key engineGetKey(String alias, char[] password)
aliasInfo.id,
null);
if (h.type == ATTR_CLASS_PKEY) {
- return loadPkey(session, h.handle);
+ return loadPkey(session, h.handle, aliasInfo.cert.getPublicKey());
}
} else {
THandle h = getTokenObject(session,
@@ -968,8 +968,8 @@ public synchronized KeyStore.Entry engineGetEntry(String alias,
throw new KeyStoreException
("expected but could not find private key");
} else {
- PrivateKey pkey = loadPkey(session, h.handle);
Certificate[] chain = aliasInfo.chain;
+ PrivateKey pkey = loadPkey(session, h.handle, chain[0].getPublicKey());
if ((pkey != null) && (chain != null)) {
return new KeyStore.PrivateKeyEntry(pkey, chain);
} else {
@@ -1305,7 +1305,7 @@ private SecretKey loadSkey(Session session, long oHandle)
return P11Key.secretKey(session, oHandle, keyType, keyLength, null);
}
- private PrivateKey loadPkey(Session session, long oHandle)
+ private PrivateKey loadPkey(Session session, long oHandle, PublicKey pk)
throws PKCS11Exception, KeyStoreException {
CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] {
@@ -1385,7 +1385,7 @@ private PrivateKey loadPkey(Session session, long oHandle)
throw new KeyStoreException("Unsupported parameters", e);
}
- return P11Key.privateKey(session, oHandle, "EC", keyLength, null);
+ return P11Key.privateKey(session, oHandle, "EC", keyLength, null, pk);
} else {
if (debug != null) {
diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyWrapCipher.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyWrapCipher.java
index 75b28d3eaabcf..d817cc4f1080d 100644
--- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyWrapCipher.java
+++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyWrapCipher.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2025, 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
@@ -795,6 +795,7 @@ protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgo,
return (switch(wrappedKeyType) {
case Cipher.PRIVATE_KEY -> P11Key.privateKey
(session, unwrappedKeyID, wrappedKeyAlgo, -1, attributes);
+ // in this case, there is no way to get the associated public key
case Cipher.SECRET_KEY -> P11Key.secretKey
(session, unwrappedKeyID, wrappedKeyAlgo, -1, attributes);
default -> null;
diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/CK_KEY_EXTRACT_FROM_KEY.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/CK_KEY_EXTRACT_FROM_KEY.java
new file mode 100644
index 0000000000000..0a12d3d8b9b09
--- /dev/null
+++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/CK_KEY_EXTRACT_FROM_KEY.java
@@ -0,0 +1,9 @@
+package sun.security.pkcs11.wrapper;
+
+public class CK_KEY_EXTRACT_FROM_KEY {
+ private final int fromBit;
+
+ public CK_KEY_EXTRACT_FROM_KEY(int fromBit) {
+ this.fromBit = fromBit;
+ }
+}
diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/CK_MECHANISM.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/CK_MECHANISM.java
index 4d518b7a167ae..e760c0747994e 100644
--- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/CK_MECHANISM.java
+++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/CK_MECHANISM.java
@@ -135,6 +135,10 @@ public CK_MECHANISM(long mechanism, CK_KEY_DERIVATION_STRING_DATA params) {
init(mechanism, params);
}
+ public CK_MECHANISM(long mechanism, CK_KEY_EXTRACT_FROM_KEY params) {
+ init(mechanism, params);
+ }
+
public CK_MECHANISM(long mechanism, CK_ECDH1_DERIVE_PARAMS params) {
init(mechanism, params);
}
diff --git a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_convert.c b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_convert.c
index f88477681b71c..2a269980a5333 100644
--- a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_convert.c
+++ b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_convert.c
@@ -875,6 +875,40 @@ jKeyDerivationStringDataToCKKeyDerivationStringDataPtr(JNIEnv *env, jobject jPar
return NULL;
}
+CK_EXTRACT_PARAMS_PTR
+jKeyExtractKeyFromKeyToExtractKeyFromKeyPtr(JNIEnv *env, jobject jParam, CK_ULONG *pLength)
+{
+ CK_EXTRACT_PARAMS_PTR ckParamPtr = NULL;
+ jclass jKeyDerivationStringDataClass;
+ jfieldID fieldID;
+ jint jpData;
+
+ if (pLength != NULL) {
+ *pLength = 0L;
+ }
+
+ jKeyDerivationStringDataClass = (*env)->FindClass(env, CLASS_KEY_EXTRACT_FROM_KEY);
+ if (jKeyDerivationStringDataClass == NULL) {
+ return NULL;
+ }
+ fieldID = (*env)->GetFieldID(env, jKeyDerivationStringDataClass, "fromBit", "I");
+ if (fieldID == NULL) {
+ return NULL;
+ }
+ jpData = (*env)->GetIntField(env, jParam, fieldID);
+ ckParamPtr = calloc(1, sizeof(CK_EXTRACT_PARAMS));
+ if (ckParamPtr == NULL) {
+ p11ThrowOutOfMemoryError(env, 0);
+ return NULL;
+ }
+ *ckParamPtr = jpData;
+
+ if (pLength != NULL) {
+ *pLength = sizeof(CK_EXTRACT_PARAMS);
+ }
+ return ckParamPtr;
+}
+
void keyMatParamToCKKeyMatParam(JNIEnv *env, jobject jParam,
jclass jKeyMatParamClass,
CK_ULONG* cKKeyMatParamUlMacSizeInBits,
@@ -1650,6 +1684,10 @@ CK_VOID_PTR jMechParamToCKMechParamPtrSlow(JNIEnv *env, jobject jParam,
ckpParamPtr = jKeyDerivationStringDataToCKKeyDerivationStringDataPtr(env, jParam,
ckpLength);
break;
+ case CKM_EXTRACT_KEY_FROM_KEY:
+ ckpParamPtr = jKeyExtractKeyFromKeyToExtractKeyFromKeyPtr(env, jParam,
+ ckpLength);
+ break;
case CKM_AES_CTR:
ckpParamPtr = jAesCtrParamsToCKAesCtrParamPtr(env, jParam,
ckpLength);
diff --git a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_util.c b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_util.c
index 9c854e09141b4..2bde64ad0f5c4 100644
--- a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_util.c
+++ b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_util.c
@@ -416,6 +416,7 @@ void freeCKMechanismPtr(CK_MECHANISM_PTR mechPtr) {
case CKM_AES_CTR:
case CKM_RSA_PKCS_PSS:
case CKM_CAMELLIA_CTR:
+ case CKM_EXTRACT_KEY_FROM_KEY:
// params do not contain pointers
break;
case CKM_PKCS5_PBKD2:
diff --git a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11wrapper.h b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11wrapper.h
index 347ef00c93a15..0c341991fd61b 100644
--- a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11wrapper.h
+++ b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11wrapper.h
@@ -220,7 +220,6 @@
//#define TRACE2d(s, p1, p2) { printf(s, p1, p2); fflush(stdout); }
//#define TRACE3d(s, p1, p2, p3) { printf(s, p1, p2, p3); fflush(stdout); }
//#define TRACE4d(s, p1, p2, p3, p4) { printf(s, p1, p2, p3, p4); fflush(stdout); }
-
#ifdef P11_DEBUG
#define TRACE0(s) { printf(s); fflush(stdout); }
#define TRACE1(s, p1) { printf(s, p1); fflush(stdout); }
@@ -300,6 +299,7 @@ void printDebug(const char *format, ...);
*/
#define CLASS_KEY_DERIVATION_STRING_DATA "sun/security/pkcs11/wrapper/CK_KEY_DERIVATION_STRING_DATA"
+#define CLASS_KEY_EXTRACT_FROM_KEY "sun/security/pkcs11/wrapper/CK_KEY_EXTRACT_FROM_KEY"
#define CLASS_SSL3_RANDOM_DATA "sun/security/pkcs11/wrapper/CK_SSL3_RANDOM_DATA"
// CLASS_SSL3_RANDOM_DATA is used by CLASS_SSL3_MASTER_KEY_DERIVE_PARAMS
#define CLASS_SSL3_KEY_MAT_OUT "sun/security/pkcs11/wrapper/CK_SSL3_KEY_MAT_OUT"
diff --git a/test/jdk/com/sun/crypto/provider/DHKEM/Compliance.java b/test/jdk/com/sun/crypto/provider/DHKEM/Compliance.java
index 22c5c89b57be2..d8814513b1268 100644
--- a/test/jdk/com/sun/crypto/provider/DHKEM/Compliance.java
+++ b/test/jdk/com/sun/crypto/provider/DHKEM/Compliance.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2025, 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
@@ -31,7 +31,6 @@
* @run main/othervm Compliance
*/
import jdk.test.lib.Asserts;
-import jdk.test.lib.Utils;
import javax.crypto.DecapsulateException;
import javax.crypto.KEM;
@@ -41,9 +40,7 @@
import java.security.interfaces.ECPublicKey;
import java.security.spec.*;
import java.util.Arrays;
-import java.util.Objects;
import java.util.Random;
-import java.util.function.Consumer;
import com.sun.crypto.provider.DHKEM;
@@ -66,12 +63,10 @@ public static void main(String[] args) throws Exception {
private static void conform() {
new KEM.Encapsulated(new SecretKeySpec(new byte[1], "X"), new byte[0], new byte[0]);
new KEM.Encapsulated(new SecretKeySpec(new byte[1], "X"), new byte[0], null);
- Utils.runAndCheckException(
- () -> new KEM.Encapsulated(null, new byte[0], null),
- NullPointerException.class);
- Utils.runAndCheckException(
- () -> new KEM.Encapsulated(new SecretKeySpec(new byte[1], "X"), null, null),
- NullPointerException.class);
+ Asserts.assertThrows(NullPointerException.class,
+ () -> new KEM.Encapsulated(null, new byte[0], null));
+ Asserts.assertThrows(NullPointerException.class,
+ () -> new KEM.Encapsulated(new SecretKeySpec(new byte[1], "X"), null, null));
}
// basic should and shouldn't behaviors
@@ -86,37 +81,33 @@ static void basic() throws Exception {
KEM.getInstance("DHKEM", (String) null);
KEM.getInstance("DHKEM", (Provider) null);
KEM kem = KEM.getInstance("DHKEM");
- Utils.runAndCheckException(
- () -> KEM.getInstance("OLALA"),
- NoSuchAlgorithmException.class);
- Utils.runAndCheckException(
- () -> KEM.getInstance("DHKEM", "NoWhere"),
- NoSuchProviderException.class);
- Utils.runAndCheckException(
- () -> KEM.getInstance("DHKEM", "SunRsaSign"),
- NoSuchAlgorithmException.class);
-
- Utils.runAndCheckException(
- () -> kem.newEncapsulator(null),
- InvalidKeyException.class);
- Utils.runAndCheckException(
- () -> kem.newDecapsulator(null),
- InvalidKeyException.class);
+ Asserts.assertThrows(NoSuchAlgorithmException.class,
+ () -> KEM.getInstance("OLALA"));
+ Asserts.assertThrows(NoSuchProviderException.class,
+ () -> KEM.getInstance("DHKEM", "NoWhere"));
+ Asserts.assertThrows(NoSuchAlgorithmException.class,
+ () -> KEM.getInstance("DHKEM", "SunRsaSign"));
+
+ Asserts.assertThrows(InvalidKeyException.class,
+ () -> kem.newEncapsulator(null));
+ Asserts.assertThrows(InvalidKeyException.class,
+ () -> kem.newDecapsulator(null));
// Still an EC key, rejected by implementation
- Utils.runAndCheckException(
- () -> kem.newEncapsulator(badECKey()),
- ExChecker.of(InvalidKeyException.class).by(DHKEM.class));
+ checkThrownBy(Asserts.assertThrows(
+ InvalidKeyException.class,
+ () -> kem.newEncapsulator(badECKey())),
+ DHKEM.class.getName());
// Not an EC key at all, rejected by framework coz it's not
// listed in "SupportedKeyClasses" in SunJCE.java.
- Utils.runAndCheckException(
- () -> kem.newEncapsulator(kpRSA.getPublic()),
- ExChecker.of(InvalidKeyException.class).by(KEM.class.getName() + "$DelayedKEM"));
+ checkThrownBy(Asserts.assertThrows(
+ InvalidKeyException.class,
+ () -> kem.newEncapsulator(kpRSA.getPublic())),
+ KEM.class.getName() + "$DelayedKEM");
- Utils.runAndCheckException(
- () -> kem.newDecapsulator(kpRSA.getPrivate()),
- InvalidKeyException.class);
+ Asserts.assertThrows(InvalidKeyException.class,
+ () -> kem.newDecapsulator(kpRSA.getPrivate()));
kem.newEncapsulator(kpX.getPublic(), null);
kem.newEncapsulator(kpX.getPublic(), null, null);
@@ -125,15 +116,12 @@ static void basic() throws Exception {
Asserts.assertEQ(enc1.key().getEncoded().length, e2.secretSize());
Asserts.assertEQ(enc1.key().getAlgorithm(), "AES");
- Utils.runAndCheckException(
- () -> e2.encapsulate(-1, 12, "AES"),
- IndexOutOfBoundsException.class);
- Utils.runAndCheckException(
- () -> e2.encapsulate(0, e2.secretSize() + 1, "AES"),
- IndexOutOfBoundsException.class);
- Utils.runAndCheckException(
- () -> e2.encapsulate(0, e2.secretSize(), null),
- NullPointerException.class);
+ Asserts.assertThrows(IndexOutOfBoundsException.class,
+ () -> e2.encapsulate(-1, 12, "AES"));
+ Asserts.assertThrows(IndexOutOfBoundsException.class,
+ () -> e2.encapsulate(0, e2.secretSize() + 1, "AES"));
+ Asserts.assertThrows(NullPointerException.class,
+ () -> e2.encapsulate(0, e2.secretSize(), null));
KEM.Encapsulated enc = e2.encapsulate();
Asserts.assertEQ(enc.key().getEncoded().length, e2.secretSize());
@@ -162,29 +150,23 @@ static void basic() throws Exception {
d.secretSize() - 16, d.secretSize(), "AES");
Asserts.assertEQ(encTail.key(), decTail);
- Utils.runAndCheckException(
- () -> d.decapsulate(null),
- NullPointerException.class);
- Utils.runAndCheckException(
- () -> d.decapsulate(enc.encapsulation(), -1, 12, "AES"),
- IndexOutOfBoundsException.class);
- Utils.runAndCheckException(
- () -> d.decapsulate(enc.encapsulation(), 0, d.secretSize() + 1, "AES"),
- IndexOutOfBoundsException.class);
- Utils.runAndCheckException(
- () -> d.decapsulate(enc.encapsulation(), 0, d.secretSize(), null),
- NullPointerException.class);
+ Asserts.assertThrows(NullPointerException.class,
+ () -> d.decapsulate(null));
+ Asserts.assertThrows(IndexOutOfBoundsException.class,
+ () -> d.decapsulate(enc.encapsulation(), -1, 12, "AES"));
+ Asserts.assertThrows(IndexOutOfBoundsException.class,
+ () -> d.decapsulate(enc.encapsulation(), 0, d.secretSize() + 1, "AES"));
+ Asserts.assertThrows(NullPointerException.class,
+ () -> d.decapsulate(enc.encapsulation(), 0, d.secretSize(), null));
KEM.Encapsulator e3 = kem.newEncapsulator(kpEC.getPublic());
KEM.Encapsulated enc2 = e3.encapsulate();
KEM.Decapsulator d3 = kem.newDecapsulator(kpX.getPrivate());
- Utils.runAndCheckException(
- () -> d3.decapsulate(enc2.encapsulation()),
- DecapsulateException.class);
+ Asserts.assertThrows(DecapsulateException.class,
+ () -> d3.decapsulate(enc2.encapsulation()));
- Utils.runAndCheckException(
- () -> d3.decapsulate(new byte[100]),
- DecapsulateException.class);
+ Asserts.assertThrows(DecapsulateException.class,
+ () -> d3.decapsulate(new byte[100]));
}
static class MySecureRandom extends SecureRandom {
@@ -273,34 +255,8 @@ public ECParameterSpec getParams() {
};
}
- // Used by Utils.runAndCheckException. Checks for type and final thrower.
- record ExChecker(Class extends Throwable> ex, String caller)
- implements Consumer