8325506: Ensure randomness is only read from provided SecureRandom object
Reviewed-by: kdriver, valeriep
This commit is contained in:
parent
0963a4e9a1
commit
b87d9cf2c9
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -297,6 +297,9 @@ public class SignatureUtil {
|
||||
} else {
|
||||
keyAlgorithm = signatureAlgorithm.substring(with + 4);
|
||||
}
|
||||
if (keyAlgorithm.endsWith("INP1363FORMAT")) {
|
||||
keyAlgorithm = keyAlgorithm.substring(0, keyAlgorithm.length() - 13);
|
||||
}
|
||||
if (keyAlgorithm.equalsIgnoreCase("ECDSA")) {
|
||||
keyAlgorithm = "EC";
|
||||
}
|
||||
|
290
test/jdk/sun/security/provider/all/Deterministic.java
Normal file
290
test/jdk/sun/security/provider/all/Deterministic.java
Normal file
@ -0,0 +1,290 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8325506
|
||||
* @library /test/lib
|
||||
* @modules java.base/sun.security.util
|
||||
* @run main/othervm Deterministic
|
||||
* @summary confirm the output of random calculations are determined
|
||||
* by the SecureRandom parameters
|
||||
*/
|
||||
|
||||
import jdk.test.lib.Asserts;
|
||||
import jdk.test.lib.security.SeededSecureRandom;
|
||||
import sun.security.util.SignatureUtil;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.KEM;
|
||||
import javax.crypto.KeyAgreement;
|
||||
import javax.crypto.KeyGenerator;
|
||||
import javax.crypto.spec.ChaCha20ParameterSpec;
|
||||
import javax.crypto.spec.DHParameterSpec;
|
||||
import javax.crypto.spec.GCMParameterSpec;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.PBEParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.*;
|
||||
import java.security.spec.AlgorithmParameterSpec;
|
||||
import java.security.spec.DSAParameterSpec;
|
||||
import java.security.spec.PSSParameterSpec;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
public class Deterministic {
|
||||
|
||||
private static final long SEED = SeededSecureRandom.seed();
|
||||
private static int hash = 0;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
for (var p : Security.getProviders()) {
|
||||
var name = p.getName();
|
||||
if (name.equals("SunMSCAPI") || name.startsWith("SunPKCS11")) {
|
||||
System.out.println("Skipped native provider " + name);
|
||||
continue;
|
||||
}
|
||||
for (var s : p.getServices()) {
|
||||
switch (s.getType()) {
|
||||
case "KeyPairGenerator" -> testKeyPairGenerator(s);
|
||||
case "KeyGenerator" -> testKeyGenerator(s);
|
||||
case "Signature" -> testSignature(s);
|
||||
case "KEM" -> testKEM(s);
|
||||
case "KeyAgreement" -> testKeyAgreement(s);
|
||||
case "Cipher" -> testCipher(s);
|
||||
case "AlgorithmParameterGenerator" -> testAlgorithmParameterGenerator(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Run twice and this value should be the same for the same SEED
|
||||
System.out.println("Final hash: " + hash);
|
||||
}
|
||||
|
||||
static void testCipher(Provider.Service s) throws Exception {
|
||||
var alg = s.getAlgorithm();
|
||||
System.out.println(s.getProvider().getName()
|
||||
+ " " + s.getType() + "." + alg);
|
||||
if (alg.contains("Wrap") || alg.contains("KW")) {
|
||||
System.out.println(" Ignored");
|
||||
return;
|
||||
}
|
||||
Key key;
|
||||
AlgorithmParameterSpec spec;
|
||||
if (alg.startsWith("PBE")) {
|
||||
key = new SecretKeySpec("isthisakey".getBytes(StandardCharsets.UTF_8), "PBE");
|
||||
// Some cipher requires salt to be 8 byte long
|
||||
spec = new PBEParameterSpec("saltsalt".getBytes(StandardCharsets.UTF_8), 100);
|
||||
} else {
|
||||
key = generateKey(alg.split("/")[0], s.getProvider());
|
||||
if (!alg.contains("/") || alg.contains("/ECB/")) {
|
||||
spec = null;
|
||||
} else {
|
||||
if (alg.contains("/GCM/")) {
|
||||
spec = new GCMParameterSpec(128, new SeededSecureRandom(SEED + 1).generateSeed(16));
|
||||
} else if (alg.equals("ChaCha20")) {
|
||||
spec = new ChaCha20ParameterSpec(new SeededSecureRandom(SEED + 2).generateSeed(12), 128);
|
||||
} else if (alg.contains("ChaCha20")) {
|
||||
spec = new IvParameterSpec(new SeededSecureRandom(SEED + 3).generateSeed(12));
|
||||
} else {
|
||||
spec = new IvParameterSpec(new SeededSecureRandom(SEED + 4).generateSeed(16));
|
||||
}
|
||||
}
|
||||
}
|
||||
var c = Cipher.getInstance(alg, s.getProvider());
|
||||
c.init(Cipher.ENCRYPT_MODE, key, spec, new SeededSecureRandom(SEED));
|
||||
// Some cipher requires plaintext to be 16 byte long
|
||||
var ct1 = c.doFinal("asimpleplaintext".getBytes(StandardCharsets.UTF_8));
|
||||
// Some cipher requires IV to be different, so re-instantiate a cipher
|
||||
c = Cipher.getInstance(alg, s.getProvider());
|
||||
c.init(Cipher.ENCRYPT_MODE, key, spec, new SeededSecureRandom(SEED));
|
||||
var ct2 = c.doFinal("asimpleplaintext".getBytes(StandardCharsets.UTF_8));
|
||||
Asserts.assertEqualsByteArray(ct1, ct2);
|
||||
hash = Objects.hash(hash, Arrays.hashCode(ct1));
|
||||
System.out.println(" Passed");
|
||||
}
|
||||
|
||||
static void testAlgorithmParameterGenerator(Provider.Service s) throws Exception {
|
||||
System.out.println(s.getProvider().getName()
|
||||
+ " " + s.getType() + "." + s.getAlgorithm());
|
||||
var apg = AlgorithmParameterGenerator.getInstance(s.getAlgorithm(), s.getProvider());
|
||||
apg.init(1024, new SeededSecureRandom(SEED));
|
||||
var p1 = apg.generateParameters().getParameterSpec(AlgorithmParameterSpec.class);
|
||||
apg.init(1024, new SeededSecureRandom(SEED));
|
||||
var p2 = apg.generateParameters().getParameterSpec(AlgorithmParameterSpec.class);
|
||||
if (p1 instanceof DSAParameterSpec d1 && p2 instanceof DSAParameterSpec d2) {
|
||||
Asserts.assertEQ(d1.getG(), d2.getG());
|
||||
Asserts.assertEQ(d1.getP(), d2.getP());
|
||||
Asserts.assertEQ(d1.getQ(), d2.getQ());
|
||||
hash = Objects.hash(hash, d1.getG(), d1.getP(), d1.getQ());
|
||||
} else if (p1 instanceof DHParameterSpec d1 && p2 instanceof DHParameterSpec d2){
|
||||
Asserts.assertEQ(d1.getG(), d2.getG());
|
||||
Asserts.assertEQ(d1.getP(), d2.getP());
|
||||
Asserts.assertEQ(d1.getL(), d2.getL());
|
||||
hash = Objects.hash(hash, d1.getG(), d1.getP(), d1.getL());
|
||||
} else {
|
||||
Asserts.assertEQ(p1, p2);
|
||||
hash = Objects.hash(hash, p1);
|
||||
}
|
||||
System.out.println(" Passed");
|
||||
}
|
||||
|
||||
private static void testSignature(Provider.Service s) throws Exception {
|
||||
System.out.println(s.getProvider().getName()
|
||||
+ " " + s.getType() + "." + s.getAlgorithm());
|
||||
String keyAlg = SignatureUtil.extractKeyAlgFromDwithE(s.getAlgorithm());
|
||||
if (keyAlg == null) {
|
||||
if (s.getAlgorithm().equals("HSS/LMS")) {
|
||||
// We don't support HSS/LMS key generation and signing
|
||||
System.out.println(" Ignored: HSS/LMS");
|
||||
return;
|
||||
} else {
|
||||
keyAlg = s.getAlgorithm(); // EdDSA etc
|
||||
}
|
||||
}
|
||||
var sk = generateKeyPair(keyAlg, 0).getPrivate();
|
||||
var sig = Signature.getInstance(s.getAlgorithm(), s.getProvider());
|
||||
try {
|
||||
if (keyAlg.equals("RSASSA-PSS")) {
|
||||
sig.setParameter(PSSParameterSpec.DEFAULT);
|
||||
}
|
||||
sig.initSign(sk, new SeededSecureRandom(SEED));
|
||||
sig.update(new byte[20]);
|
||||
var s1 = sig.sign();
|
||||
sig.initSign(sk, new SeededSecureRandom(SEED));
|
||||
sig.update(new byte[20]);
|
||||
var s2 = sig.sign();
|
||||
Asserts.assertEqualsByteArray(s1, s2);
|
||||
hash = Objects.hash(hash, Arrays.hashCode(s1));
|
||||
System.out.println(" Passed");
|
||||
} catch (InvalidKeyException ike) {
|
||||
System.out.println(" Ignored: " + ike.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
static void testKeyPairGenerator(Provider.Service s) throws Exception {
|
||||
System.out.println(s.getProvider().getName()
|
||||
+ " " + s.getType() + "." + s.getAlgorithm());
|
||||
var kp1 = generateKeyPair(s.getAlgorithm(), 0);
|
||||
var kp2 = generateKeyPair(s.getAlgorithm(), 0);
|
||||
Asserts.assertEqualsByteArray(
|
||||
kp1.getPrivate().getEncoded(), kp2.getPrivate().getEncoded());
|
||||
Asserts.assertEqualsByteArray(
|
||||
kp1.getPublic().getEncoded(), kp2.getPublic().getEncoded());
|
||||
hash = Objects.hash(hash,
|
||||
Arrays.hashCode(kp1.getPrivate().getEncoded()),
|
||||
Arrays.hashCode(kp1.getPublic().getEncoded()));
|
||||
System.out.println(" Passed");
|
||||
}
|
||||
|
||||
static KeyPair generateKeyPair(String alg, int offset) throws Exception {
|
||||
var g = KeyPairGenerator.getInstance(alg);
|
||||
var size = switch (g.getAlgorithm()) {
|
||||
case "RSA", "RSASSA-PSS", "DSA", "DiffieHellman" -> 1024;
|
||||
case "EC" -> 256;
|
||||
case "EdDSA", "Ed25519", "XDH", "X25519" -> 255;
|
||||
case "Ed448", "X448" -> 448;
|
||||
default -> throw new UnsupportedOperationException(alg);
|
||||
};
|
||||
g.initialize(size, new SeededSecureRandom(SEED + offset));
|
||||
return g.generateKeyPair();
|
||||
}
|
||||
|
||||
static void testKeyGenerator(Provider.Service s) throws Exception {
|
||||
System.out.println(s.getProvider().getName()
|
||||
+ " " + s.getType() + "." + s.getAlgorithm());
|
||||
if (s.getAlgorithm().startsWith("SunTls")) {
|
||||
System.out.println(" Ignored");
|
||||
return;
|
||||
}
|
||||
var k1 = generateKey(s.getAlgorithm(), s.getProvider());
|
||||
var k2 = generateKey(s.getAlgorithm(), s.getProvider());
|
||||
Asserts.assertEqualsByteArray(k1.getEncoded(), k2.getEncoded());
|
||||
hash = Objects.hash(hash,
|
||||
Arrays.hashCode(k1.getEncoded()));
|
||||
System.out.println(" Passed");
|
||||
}
|
||||
|
||||
static Key generateKey(String s, Provider p) throws Exception {
|
||||
if (s.startsWith("AES_")) {
|
||||
var g = KeyGenerator.getInstance("AES", p);
|
||||
g.init(Integer.parseInt(s.substring(4)), new SeededSecureRandom(SEED + 1));
|
||||
return g.generateKey();
|
||||
} if (s.startsWith("ChaCha")) {
|
||||
var g = KeyGenerator.getInstance("ChaCha20", p);
|
||||
g.init(new SeededSecureRandom(SEED + 2));
|
||||
return g.generateKey();
|
||||
} if (s.equals("RSA")) {
|
||||
return generateKeyPair("RSA", 3).getPublic();
|
||||
} else {
|
||||
var g = KeyGenerator.getInstance(s, p);
|
||||
g.init(new SeededSecureRandom(SEED + 4));
|
||||
return g.generateKey();
|
||||
}
|
||||
}
|
||||
|
||||
static void testKEM(Provider.Service s) throws Exception {
|
||||
System.out.println(s.getProvider().getName()
|
||||
+ " " + s.getType() + "." + s.getAlgorithm());
|
||||
String keyAlg = getKeyAlgFromKEM(s.getAlgorithm());
|
||||
var kp = generateKeyPair(keyAlg, 10);
|
||||
var kem = KEM.getInstance(s.getAlgorithm(), s.getProvider());
|
||||
var e1 = kem.newEncapsulator(kp.getPublic(), null, new SeededSecureRandom(SEED));
|
||||
var enc1 = e1.encapsulate();
|
||||
var e2 = kem.newEncapsulator(kp.getPublic(), null, new SeededSecureRandom(SEED));
|
||||
var enc2 = e2.encapsulate();
|
||||
Asserts.assertEqualsByteArray(enc1.encapsulation(), enc2.encapsulation());
|
||||
Asserts.assertEqualsByteArray(enc1.key().getEncoded(), enc2.key().getEncoded());
|
||||
hash = Objects.hash(hash, Arrays.hashCode(enc1.encapsulation()),
|
||||
Arrays.hashCode(enc1.key().getEncoded()));
|
||||
System.out.println(" Passed");
|
||||
}
|
||||
|
||||
static void testKeyAgreement(Provider.Service s) throws Exception {
|
||||
System.out.println(s.getProvider().getName()
|
||||
+ " " + s.getType() + "." + s.getAlgorithm());
|
||||
String keyAlg = getKeyAlgFromKEM(s.getAlgorithm());
|
||||
var kpS = generateKeyPair(keyAlg, 11);
|
||||
var kpR = generateKeyPair(keyAlg, 12);
|
||||
var ka = KeyAgreement.getInstance(s.getAlgorithm(), s.getProvider());
|
||||
ka.init(kpS.getPrivate(), new SeededSecureRandom(SEED));
|
||||
ka.doPhase(kpR.getPublic(), true);
|
||||
var sc1 = ka.generateSecret();
|
||||
ka.init(kpS.getPrivate(), new SeededSecureRandom(SEED));
|
||||
ka.doPhase(kpR.getPublic(), true);
|
||||
var sc2 = ka.generateSecret();
|
||||
|
||||
Asserts.assertEqualsByteArray(sc1, sc2);
|
||||
hash = Objects.hash(hash, Arrays.hashCode(sc1));
|
||||
System.out.println(" Passed");
|
||||
}
|
||||
|
||||
static String getKeyAlgFromKEM(String algorithm) {
|
||||
return switch (algorithm) {
|
||||
case "DHKEM" -> "X25519";
|
||||
case "ECDH" -> "EC";
|
||||
default -> algorithm;
|
||||
};
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -21,7 +21,11 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import jdk.test.lib.Asserts;
|
||||
|
||||
import java.lang.SuppressWarnings;
|
||||
import java.util.Arrays;
|
||||
import java.util.HexFormat;
|
||||
|
||||
import static jdk.test.lib.Asserts.*;
|
||||
|
||||
@ -49,6 +53,7 @@ public class AssertsTest {
|
||||
testLessThan();
|
||||
testLessThanOrEqual();
|
||||
testEquals();
|
||||
testEqualsByteArray();
|
||||
testGreaterThanOrEqual();
|
||||
testGreaterThan();
|
||||
testNotEquals();
|
||||
@ -90,6 +95,26 @@ public class AssertsTest {
|
||||
expectFail(Assertion.LTE, 2, null);
|
||||
}
|
||||
|
||||
private static void testEqualsByteArray() throws Exception {
|
||||
byte[] b1 = new byte[1];
|
||||
byte[] b11 = new byte[1];
|
||||
byte[] b2 = new byte[2];
|
||||
|
||||
expectPass(Assertion.EQBA, b1, b1);
|
||||
expectPass(Assertion.EQBA, b1, b11);
|
||||
expectPass(Assertion.EQBA, (byte[])null, (byte[])null);
|
||||
expectPass(Assertion.NEQBA, b1, b2);
|
||||
expectPass(Assertion.NEQBA, b1, (byte[])null);
|
||||
expectPass(Assertion.NEQBA, (byte[])null, b1);
|
||||
|
||||
expectFail(Assertion.EQBA, b1, b2);
|
||||
expectFail(Assertion.EQBA, (byte[])null, b1);
|
||||
expectFail(Assertion.EQBA, b1, (byte[])null);
|
||||
expectFail(Assertion.NEQBA, b1, b1);
|
||||
expectFail(Assertion.NEQBA, b1, b11);
|
||||
expectFail(Assertion.NEQBA, (byte[])null, (byte[])null);
|
||||
}
|
||||
|
||||
private static void testGreaterThanOrEqual() throws Exception {
|
||||
expectPass(Assertion.GTE, 1, 1);
|
||||
expectPass(Assertion.GTE, 2, 1);
|
||||
@ -191,10 +216,47 @@ public class AssertsTest {
|
||||
" to throw a RuntimeException");
|
||||
}
|
||||
|
||||
private static void expectPass(Assertion assertion, byte[] b1, byte[] b2)
|
||||
throws Exception {
|
||||
if (assertion == Assertion.EQBA) {
|
||||
String msg = "Expected " + Assertion.asString("assertEqualsByteArray",
|
||||
Arrays.toString(b1), Arrays.toString(b2)) + " to pass";
|
||||
Asserts.assertEqualsByteArray(b1, b2, msg);
|
||||
} else {
|
||||
String msg = "Expected " + Assertion.asString("assertNotEqualsByteArray",
|
||||
Arrays.toString(b1), Arrays.toString(b2)) + " to pass";
|
||||
Asserts.assertNotEqualsByteArray(b1, b2, msg);
|
||||
}
|
||||
}
|
||||
|
||||
private static void expectFail(Assertion assertion, byte[] b1, byte[] b2)
|
||||
throws Exception {
|
||||
if (assertion == Assertion.EQBA) {
|
||||
try {
|
||||
Asserts.assertEqualsByteArray(b1, b2);
|
||||
} catch (RuntimeException e) {
|
||||
return;
|
||||
}
|
||||
throw new Exception("Expected "
|
||||
+ Assertion.asString("assertEqualsByteArray",
|
||||
Arrays.toString(b1), Arrays.toString(b2))
|
||||
+ " to throw a RuntimeException");
|
||||
} else {
|
||||
try {
|
||||
Asserts.assertNotEqualsByteArray(b1, b2);
|
||||
} catch (RuntimeException e) {
|
||||
return;
|
||||
}
|
||||
throw new Exception("Expected "
|
||||
+ Assertion.asString("assertNotEqualsByteArray",
|
||||
Arrays.toString(b1), Arrays.toString(b2))
|
||||
+ " to throw a RuntimeException");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum Assertion {
|
||||
LT, LTE, EQ, GTE, GT, NE, NULL, NOTNULL, FALSE, TRUE;
|
||||
LT, LTE, EQ, EQBA, NEQBA, GTE, GT, NE, NULL, NOTNULL, FALSE, TRUE;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T extends Comparable<T>> void run(Assertion assertion, T ... args) {
|
||||
@ -262,7 +324,7 @@ enum Assertion {
|
||||
}
|
||||
}
|
||||
|
||||
private static String asString(String assertion, Object ... args) {
|
||||
public static String asString(String assertion, Object ... args) {
|
||||
if (args == null) {
|
||||
return String.format("%s(null)", assertion);
|
||||
}
|
||||
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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 jdk.test.lib.security;
|
||||
|
||||
import jdk.test.lib.Asserts;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @library /test/lib
|
||||
* @run main/othervm jdk.test.lib.security.SeededSecureRandomTest
|
||||
*/
|
||||
public class SeededSecureRandomTest {
|
||||
|
||||
private static final String PROP = "secure.random.seed";
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
try {
|
||||
System.clearProperty(PROP);
|
||||
Asserts.assertNE(get(), get()); // random seed (different)
|
||||
Asserts.assertEQ(get(1L), get(1L)); // same seed
|
||||
Asserts.assertEQ(get(10L), get(10L)); // same seed
|
||||
Asserts.assertNE(get(1L), get(10L)); // different seed
|
||||
|
||||
System.setProperty(PROP, "10");
|
||||
Asserts.assertEQ(get(), get()); // seed set by system property
|
||||
Asserts.assertNE(get(), get(1L)); // seed set not system property
|
||||
Asserts.assertEQ(get(), get(10L)); // seed set same as system property
|
||||
Asserts.assertEQ(get(1L), get(1L)); // same seed
|
||||
Asserts.assertEQ(get(10L), get(10L)); // same seed
|
||||
Asserts.assertNE(get(1L), get(10L)); // different seed
|
||||
} finally {
|
||||
System.clearProperty(PROP);
|
||||
}
|
||||
}
|
||||
|
||||
static int get() {
|
||||
return new SeededSecureRandom(SeededSecureRandom.seed()).nextInt();
|
||||
}
|
||||
|
||||
static int get(long seed) {
|
||||
return new SeededSecureRandom(seed).nextInt();
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -23,6 +23,8 @@
|
||||
|
||||
package jdk.test.lib;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HexFormat;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
@ -234,6 +236,64 @@ public class Asserts {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that {@code lhs} is the same byte array as {@code rhs}.
|
||||
*
|
||||
* @param lhs The left hand side of the comparison.
|
||||
* @param rhs The right hand side of the comparison.
|
||||
* @throws RuntimeException if the assertion is not true.
|
||||
* @see #assertEqualsByteArray(byte[], byte[], String)
|
||||
*/
|
||||
public static void assertEqualsByteArray(byte[] lhs, byte[] rhs) {
|
||||
assertEqualsByteArray(lhs, rhs, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that {@code lhs} is not the same byte array as {@code rhs}.
|
||||
*
|
||||
* @param lhs The left hand side of the comparison.
|
||||
* @param rhs The right hand side of the comparison.
|
||||
* @throws RuntimeException if the assertion is not true.
|
||||
* @see #assertNotEqualsByteArray(byte[], byte[], String)
|
||||
*/
|
||||
public static void assertNotEqualsByteArray(byte[] lhs, byte[] rhs) {
|
||||
assertNotEqualsByteArray(lhs, rhs, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that {@code lhs} is the same byte array as {@code rhs}.
|
||||
*
|
||||
* @param lhs The left hand side of the comparison.
|
||||
* @param rhs The right hand side of the comparison.
|
||||
* @param msg A description of the assumption; {@code null} for a default message.
|
||||
* @throws RuntimeException if the assertion is not true.
|
||||
*/
|
||||
public static void assertEqualsByteArray(byte[] lhs, byte[] rhs, String msg) {
|
||||
if (!Arrays.equals(lhs, rhs)) {
|
||||
msg = Objects.toString(msg, "assertEqualsByteArray")
|
||||
+ ": expected " + HexFormat.of().formatHex(lhs)
|
||||
+ " to equal " + HexFormat.of().formatHex(rhs);
|
||||
fail(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that {@code lhs} is not the same byte array as {@code rhs}.
|
||||
*
|
||||
* @param lhs The left hand side of the comparison.
|
||||
* @param rhs The right hand side of the comparison.
|
||||
* @param msg A description of the assumption; {@code null} for a default message.
|
||||
* @throws RuntimeException if the assertion is not true.
|
||||
*/
|
||||
public static void assertNotEqualsByteArray(byte[] lhs, byte[] rhs, String msg) {
|
||||
if (Arrays.equals(lhs, rhs)) {
|
||||
msg = Objects.toString(msg, "assertNotEqualsByteArray")
|
||||
+ ": expected " + HexFormat.of().formatHex(lhs)
|
||||
+ " to not equal " + HexFormat.of().formatHex(rhs);
|
||||
fail(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shorthand for {@link #assertGreaterThanOrEqual(Comparable, Comparable)}.
|
||||
*
|
||||
|
68
test/lib/jdk/test/lib/security/SeededSecureRandom.java
Normal file
68
test/lib/jdk/test/lib/security/SeededSecureRandom.java
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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 jdk.test.lib.security;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* A deterministic SecureRandom with a seed.
|
||||
* <p>
|
||||
* Users can provide the seed with the system property "secure.random.seed".
|
||||
* Otherwise, it's a random value. Usually, a test runs without this system
|
||||
* property and the random seed is printed out. When it fails, set the
|
||||
* system property to this recorded seed to reproduce the failure.
|
||||
*/
|
||||
public class SeededSecureRandom extends SecureRandom {
|
||||
|
||||
private final Random rnd;
|
||||
|
||||
public static long seed() {
|
||||
String value = System.getProperty("secure.random.seed");
|
||||
long seed = value != null
|
||||
? Long.parseLong(value)
|
||||
: new Random().nextLong();
|
||||
System.out.println("SeededSecureRandom: seed = " + seed);
|
||||
return seed;
|
||||
}
|
||||
|
||||
public SeededSecureRandom(long seed) {
|
||||
rnd = new Random(seed);
|
||||
}
|
||||
|
||||
public static SeededSecureRandom one() {
|
||||
return new SeededSecureRandom(seed());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nextBytes(byte[] bytes) {
|
||||
rnd.nextBytes(bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] generateSeed(int numBytes) {
|
||||
var out = new byte[numBytes];
|
||||
rnd.nextBytes(out);
|
||||
return out;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user