8209632: Develop new tests for EdDSA API

New Tests for EdDSA

Reviewed-by: ascarpino
This commit is contained in:
Sibabrata Sahoo 2020-05-19 02:36:17 -07:00
parent 77826c0a39
commit 13cf783154
7 changed files with 1514 additions and 0 deletions

View File

@ -0,0 +1,109 @@
/*
* Copyright (c) 2020, 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.
*/
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.spec.NamedParameterSpec;
import java.util.Date;
import sun.security.x509.X500Name;
import sun.security.x509.X509CRLImpl;
/*
* @test
* @bug 8209632
* @summary CRL Sign
* @modules java.base/sun.security.x509
* @run main EdCRLSign
*/
public class EdCRLSign {
private static final String ED25519 = "Ed25519";
private static final String ED448 = "Ed448";
private static final String OIDN25519 = "1.3.101.112";
private static final String OID25519 = "OID.1.3.101.112";
private static final String OIDN448 = "1.3.101.113";
private static final String OID448 = "OID.1.3.101.113";
private static final String PROVIDER = "SunEC";
private static final SecureRandom S_RND = new SecureRandom(new byte[]{0x1});
public static void main(String[] args) throws Exception {
for (boolean initWithRandom : new boolean[]{true, false}) {
// Default Parameter
test(PROVIDER, ED25519, null, initWithRandom);
test(PROVIDER, ED448, null, initWithRandom);
// With named parameter
test(PROVIDER, ED25519, ED25519, initWithRandom);
test(PROVIDER, OIDN25519, ED25519, initWithRandom);
test(PROVIDER, OID25519, ED25519, initWithRandom);
test(PROVIDER, ED448, ED448, initWithRandom);
test(PROVIDER, OIDN448, ED448, initWithRandom);
test(PROVIDER, OID448, ED448, initWithRandom);
// With size parameter
test(PROVIDER, ED25519, 255, initWithRandom);
test(PROVIDER, OIDN25519, 255, initWithRandom);
test(PROVIDER, OID25519, 255, initWithRandom);
test(PROVIDER, ED448, 448, initWithRandom);
test(PROVIDER, OIDN448, 448, initWithRandom);
test(PROVIDER, OID448, 448, initWithRandom);
}
}
// Test CRL signature using a KeyPair.
private static void test(String provider, String name, Object param,
boolean initWithRandom) throws Exception {
System.out.printf("Case Algo:%s, Param:%s, Intitiate with random:%s%n",
name, param, initWithRandom);
KeyPair kp = genKeyPair(provider, name, param, initWithRandom);
X509CRLImpl crl = new X509CRLImpl(
new X500Name("CN=Issuer"), new Date(), new Date());
crl.sign(kp.getPrivate(), name);
crl.verify(kp.getPublic());
System.out.println("Passed.");
}
private static KeyPair genKeyPair(String provider, String name,
Object param, boolean initWithRandom) throws Exception {
KeyPairGenerator kpg = KeyPairGenerator.getInstance(name, provider);
if (initWithRandom) {
if (param instanceof Integer) {
kpg.initialize((Integer) param, S_RND);
} else if (param instanceof String) {
kpg.initialize(new NamedParameterSpec((String) param), S_RND);
}
} else {
if (param instanceof Integer) {
kpg.initialize((Integer) param);
} else if (param instanceof String) {
kpg.initialize(new NamedParameterSpec((String) param));
}
}
return kpg.generateKeyPair();
}
}

View File

@ -0,0 +1,222 @@
/*
* Copyright (c) 2020, 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.
*/
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.util.Base64;
import sun.security.util.DerValue;
import java.security.interfaces.EdECPrivateKey;
import java.security.interfaces.EdECPublicKey;
import java.security.spec.EdECPrivateKeySpec;
import java.security.spec.EdECPublicKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.NamedParameterSpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
/*
* @test
* @bug 8209632
* @summary OpenSSL generated compatibility test with EDDSA Java.
* @modules java.base/sun.security.util
* @run main EdDSAKeyCompatibility
*/
public class EdDSAKeyCompatibility {
private static final String EDDSA = "EdDSA";
private static final String ED25519 = "Ed25519";
private static final String ED448 = "Ed448";
private static final String PROVIDER = "SunEC";
public static void main(String[] args) throws Exception {
boolean result = true;
result &= validateCert(EDDSA, PROVIDER, ED25519CERT);
result &= validateCert(EDDSA, PROVIDER, ED448CERT);
result &= validateCert(ED25519, PROVIDER, ED25519CERT);
result &= validateCert(ED448, PROVIDER, ED448CERT);
result &= validatePrivate(ED25519, PROVIDER, ED25519KEY);
result &= validatePrivate(ED448, PROVIDER, ED448KEY);
if (!result) {
throw new RuntimeException("Some test cases failed");
}
}
private static boolean validatePrivate(String algorithm, String provider,
String key) {
try {
KeyFactory kf = KeyFactory.getInstance(algorithm, provider);
PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(
Base64.getMimeDecoder().decode(key));
EdECPrivateKey privKey
= (EdECPrivateKey) kf.generatePrivate(privSpec);
checkPrivKeyFormat(privKey.getEncoded());
NamedParameterSpec namedSpec = new NamedParameterSpec(algorithm);
EdECPrivateKeySpec edprivSpec = new EdECPrivateKeySpec(
namedSpec, privKey.getBytes().get());
EdECPrivateKey privKey1
= (EdECPrivateKey) kf.generatePrivate(edprivSpec);
checkPrivKeyFormat(privKey1.getEncoded());
EdECPrivateKey privKey2 = (EdECPrivateKey) kf.translateKey(privKey);
checkPrivKeyFormat(privKey2.getEncoded());
equals(privKey, privKey1);
equals(privKey, privKey2);
} catch (NoSuchAlgorithmException | InvalidKeySpecException | IOException
| NoSuchProviderException | InvalidKeyException e) {
e.printStackTrace(System.out);
return false;
}
System.out.println("PASSED - validatePrivate");
return true;
}
private static boolean validateCert(String algorithm, String provider,
String certificate) {
try {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate cert = cf.generateCertificate(
new ByteArrayInputStream(certificate.getBytes()));
System.out.println(cert);
KeyFactory kf = KeyFactory.getInstance(algorithm, provider);
X509EncodedKeySpec pubSpec = kf.getKeySpec(
cert.getPublicKey(), X509EncodedKeySpec.class);
EdECPublicKey pubKey = (EdECPublicKey) kf.generatePublic(pubSpec);
EdECPublicKeySpec edpubSpec = kf.getKeySpec(
cert.getPublicKey(), EdECPublicKeySpec.class);
EdECPublicKey pubKey1 = (EdECPublicKey) kf.generatePublic(edpubSpec);
EdECPublicKey pubKey2 = (EdECPublicKey) kf.translateKey(pubKey);
equals(pubKey, pubKey1);
equals(pubKey, pubKey2);
equals(pubKey, cert.getPublicKey());
} catch (CertificateException | NoSuchAlgorithmException
| InvalidKeySpecException | NoSuchProviderException
| InvalidKeyException e) {
e.printStackTrace(System.out);
return false;
}
System.out.println("PASSED - validateCert");
return true;
}
private static void checkPrivKeyFormat(byte[] key) throws IOException {
// key value should be nested octet strings
DerValue val = new DerValue(new ByteArrayInputStream(key));
BigInteger version = val.data.getBigInteger();
DerValue algId = val.data.getDerValue();
byte[] keyValue = val.data.getOctetString();
val = new DerValue(new ByteArrayInputStream(keyValue));
if (val.tag != DerValue.tag_OctetString) {
throw new RuntimeException("incorrect format");
}
}
private static void equals(Object actual, Object expected) {
if (!actual.equals(expected)) {
throw new RuntimeException(String.format("Actual: %s, Expected: %s",
actual, expected));
}
}
// Following EdDSA Certificates/Keys are generated through openssl_1.1.1d
/*
* Certificate:
* Data:
* Version: 3 (0x2)
* Serial Number:
* 1d:d3:87:b9:e4:c6:9e:4a:5c:78:a8:f0:c7:9b:37:be:1e:31:dd:20
* Signature Algorithm: ED25519
* Issuer: C = US, ST = CA, L = SCA, O = test, OU = test, CN = localhost
* Validity
* Not Before: Mar 6 05:55:31 2020 GMT
* Not After : Mar 1 05:55:31 2040 GMT
* Subject: C = US, ST = CA, L = SCA, O = test, OU = test, CN = localhost
* Subject Public Key Info:
* Public Key Algorithm: ED25519
*/
private static final String ED25519KEY
= "MC4CAQAwBQYDK2VwBCIEIP8xGaQTMh+I+59I66AaN+B4qnY1oWGjPwbSY4r+D08f";
private static final String ED25519CERT
= "-----BEGIN CERTIFICATE-----\n"
+ "MIIByTCCAXugAwIBAgIUHdOHueTGnkpceKjwx5s3vh4x3SAwBQYDK2VwMFoxCzAJ\n"
+ "BgNVBAYTAlVTMQswCQYDVQQIDAJDQTEMMAoGA1UEBwwDU0NBMQ0wCwYDVQQKDAR0\n"
+ "ZXN0MQ0wCwYDVQQLDAR0ZXN0MRIwEAYDVQQDDAlsb2NhbGhvc3QwHhcNMjAwMzA2\n"
+ "MDU1NTMxWhcNNDAwMzAxMDU1NTMxWjBaMQswCQYDVQQGEwJVUzELMAkGA1UECAwC\n"
+ "Q0ExDDAKBgNVBAcMA1NDQTENMAsGA1UECgwEdGVzdDENMAsGA1UECwwEdGVzdDES\n"
+ "MBAGA1UEAwwJbG9jYWxob3N0MCowBQYDK2VwAyEAdqQ4Nduhbl+ShGeKdOryVMKy\n"
+ "1t1LjyjPyCBC+gSk0eCjUzBRMB0GA1UdDgQWBBS01/VQEzwkFNRW/esQxaB6+uId\n"
+ "8jAfBgNVHSMEGDAWgBS01/VQEzwkFNRW/esQxaB6+uId8jAPBgNVHRMBAf8EBTAD\n"
+ "AQH/MAUGAytlcANBAEJkLuNfyVws7HKqHL7oDqQkp5DSwh+bGjrr2p4zSvs5PZ8o\n"
+ "jRXWV0SMt/MB+90ubMD5tL7H7J6DR5PUFBIwGwc=\n"
+ "-----END CERTIFICATE-----";
/*
* Certificate:
* Data:
* Version: 3 (0x2)
* Serial Number:
* 42:eb:8c:a2:a0:6f:8e:5a:a5:f8:7c:72:c1:f1:8b:7e:44:1b:37:80
* Signature Algorithm: ED448
* Issuer: C = US, ST = CA, L = SCA, O = test, OU = test, CN = localhost
* Validity
* Not Before: Mar 6 05:57:42 2020 GMT
* Not After : Mar 1 05:57:42 2040 GMT
* Subject: C = US, ST = CA, L = SCA, O = test, OU = test, CN = localhost
* Subject Public Key Info:
* Public Key Algorithm: ED448
*/
private static final String ED448KEY
= "MEcCAQAwBQYDK2VxBDsEOdG4lrYO0xBaf3aJWYMZ8XAxitA1zV4/ghG8wPBag8HQ"
+ "XN+3OmS8wR1KfeGQysHQr3JHco3Mwiaz8w==";
private static final String ED448CERT
= "-----BEGIN CERTIFICATE-----\n"
+ "MIICFDCCAZSgAwIBAgIUQuuMoqBvjlql+HxywfGLfkQbN4AwBQYDK2VxMFoxCzAJ\n"
+ "BgNVBAYTAlVTMQswCQYDVQQIDAJDQTEMMAoGA1UEBwwDU0NBMQ0wCwYDVQQKDAR0\n"
+ "ZXN0MQ0wCwYDVQQLDAR0ZXN0MRIwEAYDVQQDDAlsb2NhbGhvc3QwHhcNMjAwMzA2\n"
+ "MDU1NzQyWhcNNDAwMzAxMDU1NzQyWjBaMQswCQYDVQQGEwJVUzELMAkGA1UECAwC\n"
+ "Q0ExDDAKBgNVBAcMA1NDQTENMAsGA1UECgwEdGVzdDENMAsGA1UECwwEdGVzdDES\n"
+ "MBAGA1UEAwwJbG9jYWxob3N0MEMwBQYDK2VxAzoAfKlXpT0ymcvz2Gp+8HLzBpaz\n"
+ "5mQqMaDbGmcq8gSIdeEUtVmv4OplE+4GSnrbJnEn99LQdbanL/MAo1MwUTAdBgNV\n"
+ "HQ4EFgQUXkm9LVUkB0f/1MiPFjQPHGJ8THIwHwYDVR0jBBgwFoAUXkm9LVUkB0f/\n"
+ "1MiPFjQPHGJ8THIwDwYDVR0TAQH/BAUwAwEB/zAFBgMrZXEDcwDvE3LKCg1bTjHi\n"
+ "MI1EiMqZN3PJYVBsztecBXm3ELDlT+F0Z1H2vjaROkJc8PdpUOxyed1xDjwq3IB/\n"
+ "nYYJNVyt6Dy3d12kl77ev+YMD83OuqM6F5O6MdDUxYQu9u3NasZAU5FQ6zklWWpI\n"
+ "8jCPtOvcAQA=\n"
+ "-----END CERTIFICATE-----";
}

View File

@ -0,0 +1,221 @@
/*
* Copyright (c) 2020, 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.
*/
import static javax.crypto.Cipher.PRIVATE_KEY;
import static javax.crypto.Cipher.PUBLIC_KEY;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.interfaces.EdECPrivateKey;
import java.security.interfaces.EdECPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.security.spec.EdECPrivateKeySpec;
import java.security.spec.EdECPublicKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.NamedParameterSpec;
import java.util.Arrays;
import jdk.test.lib.Convert;
/*
* @test
* @bug 8209632
* @summary Verify KeyLength for EDDSA, ED25519, ED448.
* @library /test/lib
* @build jdk.test.lib.Convert
* @run main EdDSAKeySize
*/
public class EdDSAKeySize {
private static final String EDDSA = "EDDSA";
private static final String ED25519 = "ED25519";
private static final String ED448 = "ED448";
private static final String OIDN25519 = "1.3.101.112";
private static final String OID25519 = "OID.1.3.101.112";
private static final String OIDN448 = "1.3.101.113";
private static final String OID448 = "OID.1.3.101.113";
private static final String PROVIDER = "SunEC";
private static final SecureRandom RND = new SecureRandom(new byte[]{0x1});
public static void main(String[] args) throws Exception {
for (boolean initWithRandom : new boolean[]{true, false}) {
// As per rfc8032 the generated keysize for ED25519 is
// 32 octets(256 bits) and ED448 is 57 octets(456 bits).
// Case with default parameter
testKeyAttributes(PROVIDER, EDDSA, initWithRandom, null, 256);
testKeyAttributes(PROVIDER, ED25519, initWithRandom, null, 256);
testKeyAttributes(PROVIDER, ED448, initWithRandom, null, 456);
// With named parameter
testKeyAttributes(PROVIDER, EDDSA, initWithRandom, ED25519, 256);
testKeyAttributes(PROVIDER, ED25519, initWithRandom, ED25519, 256);
testKeyAttributes(PROVIDER, OIDN25519, initWithRandom, ED25519, 256);
testKeyAttributes(PROVIDER, OID25519, initWithRandom, ED25519, 256);
testKeyAttributes(PROVIDER, ED448, initWithRandom, ED448, 456);
testKeyAttributes(PROVIDER, OIDN448, initWithRandom, ED448, 456);
testKeyAttributes(PROVIDER, OID448, initWithRandom, ED448, 456);
// With size parameter
testKeyAttributes(PROVIDER, EDDSA, initWithRandom, 255, 256);
testKeyAttributes(PROVIDER, ED25519, initWithRandom, 255, 256);
testKeyAttributes(PROVIDER, OIDN25519, initWithRandom, 255, 256);
testKeyAttributes(PROVIDER, OID25519, initWithRandom, 255, 256);
testKeyAttributes(PROVIDER, ED448, initWithRandom, 448, 456);
testKeyAttributes(PROVIDER, OIDN448, initWithRandom, 448, 456);
testKeyAttributes(PROVIDER, OID448, initWithRandom, 448, 456);
}
}
/**
* Test standard Key attributes.
*/
private static void testKeyAttributes(String provider, String name,
boolean initWithRandom, Object param, int keySize) throws Exception {
System.out.printf("Case name: %s, param: %s, Expected keysize: %s, "
+ "Initiate with random: %s%n", name, param, keySize,
initWithRandom);
KeyPairGenerator kpg = KeyPairGenerator.getInstance(name, provider);
if (initWithRandom) {
if (param instanceof Integer) {
kpg.initialize((Integer) param, RND);
} else if (param instanceof String) {
kpg.initialize(new NamedParameterSpec((String) param), RND);
}
} else {
if (param instanceof Integer) {
kpg.initialize((Integer) param);
} else if (param instanceof String) {
kpg.initialize(new NamedParameterSpec((String) param));
}
}
KeyPair kp = kpg.generateKeyPair();
NamedParameterSpec namedSpec = getNamedParamSpec(name);
// Verify original PrivateKey with it's different representation
Key[] privs = manipulateKey(provider, name, PRIVATE_KEY,
kp.getPrivate(), namedSpec);
Arrays.stream(privs).forEach(
priv -> testPrivateKey((EdECPrivateKey) kp.getPrivate(),
(EdECPrivateKey) priv, keySize));
// Verify original PublicKey with it's different representation
Key[] pubs = manipulateKey(provider, name, PUBLIC_KEY,
kp.getPublic(), namedSpec);
Arrays.stream(pubs).forEach(
pub -> testPublicKey((EdECPublicKey) kp.getPublic(),
(EdECPublicKey) pub));
System.out.println("Passed.");
}
private static NamedParameterSpec getNamedParamSpec(String algo) {
NamedParameterSpec namedSpec = switch (algo) {
case EDDSA
, OIDN25519, OID25519 -> new NamedParameterSpec(ED25519);
case OIDN448
, OID448 -> new NamedParameterSpec(ED448);
default->
new NamedParameterSpec(algo);
};
return namedSpec;
}
private static Key[] manipulateKey(String provider, String algo, int type,
Key key, NamedParameterSpec namedSpec)
throws NoSuchAlgorithmException, InvalidKeySpecException,
NoSuchProviderException, InvalidKeyException {
KeyFactory kf = KeyFactory.getInstance(algo, provider);
switch (type) {
case PUBLIC_KEY:
return new Key[]{
kf.generatePublic(new X509EncodedKeySpec(key.getEncoded())),
kf.generatePublic(kf.getKeySpec(
key, EdECPublicKeySpec.class)),
kf.generatePublic(new EdECPublicKeySpec(namedSpec,
((EdECPublicKey) key).getPoint())),
kf.translateKey(key)
};
case PRIVATE_KEY:
return new Key[]{
kf.generatePrivate(new PKCS8EncodedKeySpec(key.getEncoded())),
kf.generatePrivate(
kf.getKeySpec(key, EdECPrivateKeySpec.class)),
kf.generatePrivate(new EdECPrivateKeySpec(namedSpec,
((EdECPrivateKey) key).getBytes().get())),
kf.translateKey(key)
};
}
throw new RuntimeException("We shouldn't reach here");
}
/**
* Basic PrivateKey Test cases
*/
private static void testPrivateKey(EdECPrivateKey orig,
EdECPrivateKey generated, int size) {
equals(orig.getBytes().get().length * 8, size);
equals(generated.getBytes().get().length * 8, size);
equals(orig.getBytes().get(), generated.getBytes().get());
equals(orig.getFormat(), generated.getFormat());
equals(orig.getEncoded(), generated.getEncoded());
equals(((NamedParameterSpec) orig.getParams()).getName(),
((NamedParameterSpec) generated.getParams()).getName());
}
/**
* Basic PublicKey Test cases
*/
private static void testPublicKey(EdECPublicKey orig,
EdECPublicKey generated) {
equals(orig.getPoint().getY(), generated.getPoint().getY());
equals(orig.getPoint().isXOdd(), generated.getPoint().isXOdd());
equals(orig.getFormat(), generated.getFormat());
equals(orig.getEncoded(), generated.getEncoded());
equals(((NamedParameterSpec) orig.getParams()).getName(),
((NamedParameterSpec) generated.getParams()).getName());
}
private static void equals(Object actual, Object expected) {
if (!actual.equals(expected)) {
throw new RuntimeException(String.format("Actual: %s, Expected: %s",
actual, expected));
}
}
private static void equals(byte[] actual, byte[] expected) {
if (!Arrays.equals(actual, expected)) {
throw new RuntimeException(String.format("Actual array: %s, "
+ "Expected array:%s", Convert.byteArrayToHexString(actual),
Convert.byteArrayToHexString(expected)));
}
}
}

View File

@ -0,0 +1,299 @@
/*
* Copyright (c) 2020, 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.
*/
import java.security.InvalidKeyException;
import java.security.InvalidParameterException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.EdECPrivateKey;
import java.security.interfaces.EdECPublicKey;
import java.security.spec.EdDSAParameterSpec;
import java.util.Arrays;
import jdk.test.lib.Convert;
/*
* @test
* @bug 8209632
* @summary Negative cases for EDDSA.
* @library /test/lib
* @build jdk.test.lib.Convert
* @run main EdDSANegativeTest
*/
public class EdDSANegativeTest {
private static final String EDDSA = "EdDSA";
private static final String ED25519 = "Ed25519";
private static final String ED448 = "Ed448";
private static final String PROVIDER = "SunEC";
private static final String OTHER = "other";
private static final byte[] MSG = "TEST".getBytes();
public static void main(String[] args) throws Exception {
byName();
byParam();
byInvalidKey();
byInvalidKeyType();
}
private static void byName() throws Exception {
for (String name : new String[]{null, "", "EDDSA", "eddsa", "EDdsa",
EDDSA, ED25519, "ed25519", "ED25519", ED448, "eD448", "ED448",
"ed448", OTHER}) {
try {
KeyPair kp = genKeyPair(name);
KeyFactory kf = KeyFactory.getInstance(name, PROVIDER);
EdECPrivateKey edPri
= (EdECPrivateKey) kf.translateKey(kp.getPrivate());
EdECPublicKey edPub
= (EdECPublicKey) kf.translateKey(kp.getPublic());
Signature sig = Signature.getInstance(name, PROVIDER);
byte[] computedSig = sign(sig, edPri, MSG);
if (!verify(sig, edPub, MSG, computedSig)) {
throw new RuntimeException("Signature verification failed");
}
if (name == null || "".equals(name)) {
throw new RuntimeException(
"Should not reach here for algo: " + name);
}
System.out.println("Passed: byName: " + name);
} catch (NullPointerException e) {
if (name != null) {
throw new RuntimeException(
"Unknown issue with algo name: " + name, e);
}
} catch (NoSuchAlgorithmException e) {
if (!("".equals(name) || OTHER.equals(name))) {
throw new RuntimeException(
"Unknown issue with algo name: " + name, e);
}
}
}
}
private static void byParam() throws Exception {
testParam(EDDSA);
testParam(ED25519);
testParam(ED448);
}
private static void byInvalidKey() throws Exception {
testInvalidKey(EDDSA);
testInvalidKey(ED25519);
testInvalidKey(ED448);
}
private static void byInvalidKeyType() throws Exception {
testInvalidKeyType(EDDSA);
testInvalidKeyType(ED25519);
testInvalidKeyType(ED448);
}
/**
* Test Signature.
*/
private static void testParam(String name) throws Exception {
KeyPair kp = genKeyPair(name);
Signature sig = Signature.getInstance(name, PROVIDER);
// Set initial paramter to generate a signature
EdDSAParameterSpec initParam
= new EdDSAParameterSpec(true, "testContext".getBytes());
sig.setParameter(initParam);
byte[] computedSig = sign(sig, kp.getPrivate(), MSG);
// Signature should not get verified other than same parameter
// which is set through the signature instance.
for (boolean preHash : new boolean[]{true, false}) {
// Test case with prehash as parameter without context set.
verify(sig, kp.getPublic(), MSG, new EdDSAParameterSpec(preHash),
initParam, computedSig);
// Test Case with Context combined of different sizes.
// As per rfc8032, value of context is maximum of 255 octet
for (byte[] context : new byte[][]{{}, "other".getBytes(),
new byte[255], new byte[500]}) {
System.out.printf("Testing signature for name: %s, algorithm "
+ "spec: (prehash:%s, context:%s)%n", name, preHash,
Convert.byteArrayToHexString(context));
try {
verify(sig, kp.getPublic(), MSG,
new EdDSAParameterSpec(preHash, context),
initParam, computedSig);
} catch (InvalidParameterException e) {
if (context.length <= 255) {
throw new RuntimeException("Should not throw exception "
+ "when context size <= 255 octet: "
+ context.length);
}
}
}
}
}
private static void testInvalidKey(String name) throws Exception {
KeyPair kp = genKeyPair(name);
KeyPair kp1 = genKeyPair(name);
Signature sig = Signature.getInstance(name, PROVIDER);
byte[] computedSig = sign(sig, kp.getPrivate(), MSG);
if (verify(sig, kp1.getPublic(), MSG, computedSig)) {
throw new RuntimeException("Signature verification failed "
+ "for unpaired key.");
}
System.out.println("Passed: testInvalidKey: " + name);
}
private static void testInvalidKeyType(String name) throws Exception {
KeyFactory kf = KeyFactory.getInstance(name, PROVIDER);
try {
kf.translateKey(new InvalidPrivateKey());
} catch (InvalidKeyException e) {
// Expected exception and not to be handled
}
try {
kf.translateKey(new InvalidPublicKey());
} catch (InvalidKeyException e) {
// Expected exception and not to be handled
}
System.out.println("Passed: testInvalidKeyType: " + name);
}
private static KeyPair genKeyPair(String name) throws Exception {
KeyPairGenerator kpg = KeyPairGenerator.getInstance(name, PROVIDER);
return kpg.generateKeyPair();
}
private static byte[] sign(Signature sig, PrivateKey priKey, byte[] msg)
throws Exception {
sig.initSign(priKey);
sig.update(msg);
return sig.sign();
}
private static boolean verify(Signature sig, PublicKey pubKey, byte[] msg,
byte[] sign) throws Exception {
sig.initVerify(pubKey);
sig.update(msg);
return sig.verify(sign);
}
private static void verify(Signature sig, PublicKey pubKey, byte[] msg,
EdDSAParameterSpec params, EdDSAParameterSpec initParam,
byte[] computedSig) throws Exception {
sig.setParameter(params);
if (verify(sig, pubKey, msg, computedSig)) {
byte[] context = params.getContext().isPresent()
? params.getContext().get() : null;
byte[] initContext = initParam.getContext().isPresent()
? initParam.getContext().get() : null;
boolean preHash = params.isPrehash();
boolean initPreHash = initParam.isPrehash();
// The signature should not get verified with other parameters
// set through signature instance.
if (!(equals(context, initContext) && equals(preHash, initPreHash))) {
throw new RuntimeException(String.format("Signature verification"
+ " success with different param context(actual:%s, "
+ "expected:%s), Prehash(actual:%s, expected:%s)",
Convert.byteArrayToHexString(context),
Convert.byteArrayToHexString(initContext),
preHash, initPreHash));
} else {
System.out.println("Atleast a case matched");
}
}
}
private static boolean equals(Object actual, Object expected) {
if (actual == expected) {
return true;
}
if (actual == null || expected == null) {
return false;
}
boolean equals = actual.equals(expected);
if (!equals) {
throw new RuntimeException(String.format("Actual: %s, Expected: %s",
actual, expected));
}
return equals;
}
private static boolean equals(byte[] actual, byte[] expected) {
if (actual == expected) {
return true;
}
if (actual == null || expected == null) {
return false;
}
boolean equals = Arrays.equals(actual, expected);
if (!equals) {
throw new RuntimeException(String.format("Actual array: %s, "
+ "Expected array:%s", Convert.byteArrayToHexString(actual),
Convert.byteArrayToHexString(expected)));
}
return equals;
}
private static class InvalidPrivateKey implements PrivateKey {
@Override
public String getAlgorithm() {
return "test";
}
@Override
public String getFormat() {
return "test";
}
@Override
public byte[] getEncoded() {
return "test".getBytes();
}
}
private static class InvalidPublicKey implements PublicKey {
@Override
public String getAlgorithm() {
return "test";
}
@Override
public String getFormat() {
return "test";
}
@Override
public byte[] getEncoded() {
return "test".getBytes();
}
}
}

View File

@ -0,0 +1,174 @@
/*
* Copyright (c) 2020, 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.
*/
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.spec.EdDSAParameterSpec;
import java.util.Arrays;
import jdk.test.lib.Convert;
/*
* @test
* @bug 8209632
* @summary Test EdDSAParameterSpec.
* @library /test/lib
* @build jdk.test.lib.Convert
* @run main EdDSAParamSpec
*/
public class EdDSAParamSpec {
private static final String EDDSA = "EdDSA";
private static final String ED25519 = "Ed25519";
private static final String ED448 = "Ed448";
private static final String PROVIDER = "SunEC";
private static final byte[] MSG = "TEST".getBytes();
private static final SecureRandom RND = new SecureRandom(new byte[]{0x1});
public static void main(String[] args) throws Exception {
testParam(PROVIDER, EDDSA);
testParam(PROVIDER, ED25519);
testParam(PROVIDER, ED448);
}
/**
* Test Signature.
*/
private static void testParam(String provider, String name)
throws Exception {
KeyPair kp = genKeyPair(provider, name);
Signature sig = Signature.getInstance(name, provider);
EdDSAParameterSpec initParam
= new EdDSAParameterSpec(true, "testContext".getBytes());
sig.setParameter(initParam);
byte[] origSign = sign(sig, kp.getPrivate(), MSG);
for (boolean preHash : new boolean[]{true, false}) {
System.out.printf("Testing signature for name: %s,"
+ " algorithm spec: (prehash:%s)%n", name, preHash);
verifyPublic(sig, kp.getPublic(), MSG,
new EdDSAParameterSpec(preHash), initParam, origSign);
// Test Case with Context size combined.
// As per rfc8032, value of context is maximum of 255 octet
byte[] maxCtx = new byte[255];
RND.nextBytes(maxCtx);
for (byte[] context : new byte[][]{"others".getBytes(), maxCtx}) {
System.out.printf("Testing signature for name: %s,"
+ " algorithm spec: (prehash:%s, context:%s)%n",
name, preHash, Convert.byteArrayToHexString(context));
EdDSAParameterSpec params
= new EdDSAParameterSpec(preHash, context);
verifyPublic(sig, kp.getPublic(), MSG, params, initParam,
origSign);
}
}
System.out.println("Passed.");
}
private static KeyPair genKeyPair(String provider, String name)
throws Exception {
KeyPairGenerator kpg = KeyPairGenerator.getInstance(name, provider);
return kpg.generateKeyPair();
}
private static byte[] sign(Signature sig, PrivateKey priKey, byte[] msg)
throws Exception {
sig.initSign(priKey);
sig.update(msg);
return sig.sign();
}
private static boolean verify(Signature sig, PublicKey pubKey, byte[] msg,
byte[] sign) throws Exception {
sig.initVerify(pubKey);
sig.update(msg);
return sig.verify(sign);
}
private static void verifyPublic(Signature sig, PublicKey pubKey,
byte[] msg, EdDSAParameterSpec params, EdDSAParameterSpec initParam,
byte[] origSign) throws Exception {
sig.setParameter(params);
if (verify(sig, pubKey, msg, origSign)) {
byte[] context = params.getContext().isPresent()
? params.getContext().get() : null;
byte[] initContext = initParam.getContext().isPresent()
? initParam.getContext().get() : null;
boolean preHash = params.isPrehash();
boolean initPreHash = initParam.isPrehash();
// The signature should not get verified other than same parameter
// which is set through the signature instance.
if (!(equals(context, initContext) && equals(preHash, initPreHash))) {
throw new RuntimeException(String.format("Signature verification"
+ " success with different param context(actual:%s, "
+ "expected:%s), Prehash(actual:%s, expected:%s)",
Convert.byteArrayToHexString(context),
Convert.byteArrayToHexString(initContext),
preHash, initPreHash));
} else {
System.out.println("Atleast a case matched");
}
}
}
private static boolean equals(Object actual, Object expected) {
if (actual == expected) {
return true;
}
if (actual == null || expected == null) {
return false;
}
boolean equals = actual.equals(expected);
if (!equals) {
throw new RuntimeException(String.format("Actual: %s, Expected: %s",
actual, expected));
}
return equals;
}
private static boolean equals(byte[] actual, byte[] expected) {
if (actual == expected) {
return true;
}
if (actual == null || expected == null) {
return false;
}
boolean equals = Arrays.equals(actual, expected);
if (!equals) {
throw new RuntimeException(String.format("Actual array: %s, "
+ "Expected array:%s", Convert.byteArrayToHexString(actual),
Convert.byteArrayToHexString(expected)));
}
return equals;
}
}

View File

@ -0,0 +1,133 @@
/*
* Copyright (c) 2020, 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.
*/
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.NamedParameterSpec;
import java.util.ArrayList;
import java.util.List;
/*
* @test
* @bug 8209632
* @summary Test behaviour of Signature instance by re-using it multiple times
* in different way.
* @run main EdDSAReuseTest
*/
public class EdDSAReuseTest {
private static final String EDDSA = "EdDSA";
private static final String ED25519 = "Ed25519";
private static final String ED448 = "Ed448";
private static final String PROVIDER = "SunEC";
private static final String MSG = "TEST";
private static final int REUSE = 20;
private static final int ONCE = 1;
private static final int TENTH = 10;
private static final int FIFTH = 5;
public static void main(String[] args) throws Exception {
for (boolean initKey : new boolean[]{true, false}) {
// Sign and Verify with data update once
test(PROVIDER, EDDSA, null, initKey, ONCE, ONCE);
test(PROVIDER, ED25519, ED25519, initKey, ONCE, ONCE);
test(PROVIDER, ED448, ED448, initKey, ONCE, ONCE);
// Sign and Verify with data update 10 times
test(PROVIDER, EDDSA, null, initKey, TENTH, TENTH);
test(PROVIDER, ED25519, ED25519, initKey, TENTH, TENTH);
test(PROVIDER, ED448, ED448, initKey, TENTH, TENTH);
// Sign and Verify with data update unmatched number of times
test(PROVIDER, EDDSA, null, initKey, TENTH, FIFTH);
test(PROVIDER, ED25519, ED25519, initKey, TENTH, FIFTH);
test(PROVIDER, ED448, ED448, initKey, TENTH, FIFTH);
}
}
private static void test(String provider, String name, Object param,
boolean initKey, int signUpdate, int verifyUpdate)
throws Exception {
System.out.printf("Case for signature name: %s, param: %s,"
+ " initialize signature instance before each operation: %s%n",
name, param, initKey);
KeyPairGenerator kpg = KeyPairGenerator.getInstance(name, provider);
if (param != null) {
kpg.initialize(new NamedParameterSpec((String) param));
}
KeyPair kp = kpg.generateKeyPair();
Signature sig = Signature.getInstance(name, provider);
testAPI(sig, kp, initKey, signUpdate, verifyUpdate);
System.out.println("Passed.");
}
private static void testAPI(Signature sig, KeyPair kp, boolean initKey,
int signUpdate, int verifyUpdate) throws Exception {
sig.initSign(kp.getPrivate());
List<byte[]> signatures = new ArrayList<>();
// Re-use the signature instance 20 times
for (int i = 0; i < REUSE; i++) {
signatures.add(sign(sig, kp.getPrivate(), MSG, initKey, signUpdate));
}
System.out.printf("Generated signatures %s times%n", signatures.size());
sig.initVerify(kp.getPublic());
for (byte[] sign : signatures) {
// Verification will pass when message update matches with
// the same used for sign
if (verify(sig, kp.getPublic(), MSG, sign, initKey, verifyUpdate)
!= (signUpdate == verifyUpdate)) {
throw new RuntimeException(
"Verification succed with unmatched message");
}
}
System.out.printf("Verified signatures %s times%n", signatures.size());
}
private static byte[] sign(Signature sig, PrivateKey priKey, String msg,
boolean initKey, int signUpdate) throws Exception {
if (initKey) {
sig.initSign(priKey);
}
for (int update = 0; update < signUpdate; update++) {
sig.update(msg.getBytes());
}
return sig.sign();
}
private static boolean verify(Signature sig, PublicKey pubKey, String msg,
byte[] sign, boolean initKey, int verifyUpdate) throws Exception {
if (initKey) {
sig.initVerify(pubKey);
}
for (int update = 0; update < verifyUpdate; update++) {
sig.update(msg.getBytes());
}
return sig.verify(sign);
}
}

View File

@ -0,0 +1,356 @@
/*
* Copyright (c) 2020, 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.
*/
import static javax.crypto.Cipher.PRIVATE_KEY;
import static javax.crypto.Cipher.PUBLIC_KEY;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.interfaces.EdECPrivateKey;
import java.security.interfaces.EdECPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.security.spec.EdECPrivateKeySpec;
import java.security.spec.EdECPublicKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.NamedParameterSpec;
import java.security.spec.EdDSAParameterSpec;
import java.util.Arrays;
import jdk.test.lib.Convert;
/*
* @test
* @bug 8209632
* @summary Test Signature with variation of serialized EDDSA Keys.
* @library /test/lib
* @build jdk.test.lib.Convert
* @run main EdDSATest
*/
public class EdDSATest {
private static final String EDDSA = "EdDSA";
private static final String ED25519 = "Ed25519";
private static final String ED448 = "Ed448";
private static final String OIDN25519 = "1.3.101.112";
private static final String OID25519 = "OID.1.3.101.112";
private static final String OIDN448 = "1.3.101.113";
private static final String OID448 = "OID.1.3.101.113";
private static final String PROVIDER = "SunEC";
private static final byte[] MSG = "TEST".getBytes();
private static final SecureRandom S_RND = new SecureRandom(new byte[]{0x1});
public static void main(String[] args) throws Exception {
for (boolean random : new boolean[]{true, false}) {
// Default Parameter
test(PROVIDER, EDDSA, null, random);
test(PROVIDER, ED25519, null, random);
test(PROVIDER, ED448, null, random);
// With named parameter
test(PROVIDER, EDDSA, ED25519, random);
test(PROVIDER, ED25519, ED25519, random);
test(PROVIDER, OIDN25519, ED25519, random);
test(PROVIDER, OID25519, ED25519, random);
test(PROVIDER, ED448, ED448, random);
test(PROVIDER, OIDN448, ED448, random);
test(PROVIDER, OID448, ED448, random);
// With size parameter
test(PROVIDER, EDDSA, 255, random);
test(PROVIDER, ED25519, 255, random);
test(PROVIDER, OIDN25519, 255, random);
test(PROVIDER, OID25519, 255, random);
test(PROVIDER, ED448, 448, random);
test(PROVIDER, OIDN448, 448, random);
test(PROVIDER, OID448, 448, random);
}
}
// Test signature using a KeyPair and the corresponding transformed one.
private static void test(String provider, String name, Object param,
boolean random) throws Exception {
System.out.printf("Case Algo:%s, Param:%s, Intitiate with random:%s%n",
name, param, random);
KeyPair origkp = genKeyPair(provider, name, param, random);
testSignature(provider, name, origkp, origkp);
NamedParameterSpec namedSpec = namedParamSpec(name);
// Test all possible transformed private/public keys
for (Key priKey : manipulateKey(provider, name, PRIVATE_KEY,
origkp.getPrivate(), namedSpec)) {
for (Key pubKey : manipulateKey(provider, name, PUBLIC_KEY,
origkp.getPublic(), namedSpec)) {
EdECPrivateKey pri = (EdECPrivateKey) priKey;
EdECPublicKey pub = (EdECPublicKey) pubKey;
// Test the keys are serializable.
testSerialize(origkp, new KeyPair(pub, pri));
// Test signature
testSignature(provider, name, origkp, new KeyPair(pub, pri));
}
}
System.out.println("Passed.");
}
private static KeyPair genKeyPair(String provider, String name,
Object param, boolean random) throws Exception {
KeyPairGenerator kpg = KeyPairGenerator.getInstance(name, provider);
if (random) {
if (param instanceof Integer) {
kpg.initialize((Integer) param, S_RND);
} else if (param instanceof String) {
kpg.initialize(new NamedParameterSpec((String) param), S_RND);
}
} else {
if (param instanceof Integer) {
kpg.initialize((Integer) param);
} else if (param instanceof String) {
kpg.initialize(new NamedParameterSpec((String) param));
}
}
equals(kpg.getProvider().getName(), provider);
equals(kpg.getAlgorithm(), name);
return kpg.generateKeyPair();
}
private static NamedParameterSpec namedParamSpec(String algo) {
NamedParameterSpec namedSpec = switch (algo) {
case EDDSA
, OIDN25519, OID25519 -> new NamedParameterSpec(ED25519);
case OIDN448
, OID448 -> new NamedParameterSpec(ED448);
default->
new NamedParameterSpec(algo);
};
return namedSpec;
}
private static Key[] manipulateKey(String provider, String name, int type,
Key key, NamedParameterSpec namedSpec)
throws NoSuchAlgorithmException, InvalidKeySpecException,
NoSuchProviderException, InvalidKeyException {
KeyFactory kf = KeyFactory.getInstance(name, provider);
switch (type) {
case PUBLIC_KEY:
return new Key[]{
kf.generatePublic(new X509EncodedKeySpec(key.getEncoded())),
kf.generatePublic(kf.getKeySpec(
key, EdECPublicKeySpec.class)),
kf.generatePublic(new EdECPublicKeySpec(namedSpec,
((EdECPublicKey) key).getPoint())),
kf.translateKey(key)
};
case PRIVATE_KEY:
return new Key[]{
kf.generatePrivate(new PKCS8EncodedKeySpec(key.getEncoded())),
kf.generatePrivate(
kf.getKeySpec(key, EdECPrivateKeySpec.class)),
kf.generatePrivate(new EdECPrivateKeySpec(namedSpec,
((EdECPrivateKey) key).getBytes().get())),
kf.translateKey(key)
};
}
throw new RuntimeException("We shouldn't reach here");
}
/**
* Test Signature with a set of parameter combination.
*/
private static void testSignature(String provider, String name,
KeyPair origkp, KeyPair kp) throws Exception {
signAndVerify(provider, name, origkp, kp, null);
// Test Case with Pre-Hash enabled and disabled.
for (boolean preHash : new boolean[]{true, false}) {
signAndVerify(provider, name, origkp, kp,
new EdDSAParameterSpec(preHash));
// Test Case with Context combined.
for (byte[] context : new byte[][]{
{}, "a".getBytes(), new byte[255]}) {
signAndVerify(provider, name, origkp, kp,
new EdDSAParameterSpec(preHash, context));
}
}
}
private static void signAndVerify(String provider, String name,
KeyPair origkp, KeyPair kp, EdDSAParameterSpec params)
throws Exception {
Signature sig = Signature.getInstance(name, provider);
if (params != null) {
sig.setParameter(params);
}
sig.initSign(origkp.getPrivate());
sig.update(MSG);
byte[] origSign = sig.sign();
sig.update(MSG);
byte[] computedSig = sig.sign();
equals(origSign, computedSig);
// EdDSA signatures size (64 and 114 bytes) for Ed25519 and Ed448.
int expectedSigSize = edSignatureSize(name);
equals(origSign.length, expectedSigSize);
sig.initSign(kp.getPrivate());
sig.update(MSG);
equals(computedSig, sig.sign());
// Use same signature instance to verify with transformed PublicKey.
sig.initVerify(kp.getPublic());
sig.update(MSG);
if (!sig.verify(origSign)) {
throw new RuntimeException(String.format("Signature did not verify"
+ " for name:%s, prehash:%s, context:%s", name,
(params == null) ? null : params.isPrehash(),
(params == null) ? null : params.getContext().get()));
}
// Create a new signature to re-verify.
sig = Signature.getInstance(name, provider);
if (params != null) {
sig.setParameter(params);
}
// Verify the signature with transformed PublicKey.
sig.initVerify(kp.getPublic());
sig.update(MSG);
if (!sig.verify(origSign)) {
throw new RuntimeException(String.format("Signature did not verify"
+ " for name:%s, prehash:%s, context:%s",
name, (params == null) ? null : params.isPrehash(),
(params == null) ? null : params.getContext().get()));
}
equals(sig.getAlgorithm(), name);
equals(sig.getProvider().getName(), provider);
}
private static int edSignatureSize(String algo) {
int size = switch (algo) {
case EDDSA
, ED25519, OIDN25519, OID25519 -> 64;
case ED448
, OIDN448, OID448 -> 114;
default->
-1;
};
return size;
}
/**
* Compare original KeyPair with transformed ones.
*/
private static void testKeyEquals(KeyPair origkp, PublicKey pubKey,
PrivateKey priKey) {
if (!origkp.getPrivate().equals(priKey)
&& !Arrays.equals(origkp.getPrivate().getEncoded(),
priKey.getEncoded())
&& origkp.getPrivate().hashCode() != priKey.hashCode()) {
throw new RuntimeException(
"PrivateKey is not equal with transformed one");
}
if (!origkp.getPublic().equals(pubKey)
&& !Arrays.equals(origkp.getPublic().getEncoded(),
pubKey.getEncoded())
&& origkp.getPublic().hashCode() != pubKey.hashCode()) {
throw new RuntimeException(
"PublicKey is not equal with transformed one");
}
}
/**
* Test serialization of KeyPair and Keys.
*/
private static void testSerialize(KeyPair origkp, KeyPair kp)
throws Exception {
testKeyEquals(origkp, kp.getPublic(), kp.getPrivate());
PrivateKey priv = deserializedCopy(kp.getPrivate(), PrivateKey.class);
PublicKey pub = deserializedCopy(kp.getPublic(), PublicKey.class);
testKeyEquals(origkp, pub, priv);
// Verify Serialized KeyPair instance.
KeyPair copy = deserializedCopy(kp, KeyPair.class);
testKeyEquals(origkp, copy.getPublic(), copy.getPrivate());
}
private static <T extends Object> T deserializedCopy(T origkp, Class<T> type)
throws IOException, ClassNotFoundException {
return deserialize(serialize(origkp), type);
}
/**
* Deserialize the Key object.
*/
private static <T extends Object> T deserialize(byte[] serialized,
Class<T> type) throws IOException, ClassNotFoundException {
T key = null;
try (ByteArrayInputStream bis = new ByteArrayInputStream(serialized);
ObjectInputStream ois = new ObjectInputStream(bis)) {
key = (T) ois.readObject();
}
return key;
}
/**
* Serialize the given Key object.
*/
private static <T extends Object> byte[] serialize(T key)
throws IOException {
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos)) {
oos.writeObject(key);
return bos.toByteArray();
}
}
private static void equals(Object actual, Object expected) {
if (!actual.equals(expected)) {
throw new RuntimeException(String.format("Actual: %s, Expected: %s",
actual, expected));
}
}
private static void equals(byte[] actual, byte[] expected) {
if (!Arrays.equals(actual, expected)) {
throw new RuntimeException(String.format("Actual array: %s, "
+ "Expected array:%s", Convert.byteArrayToHexString(actual),
Convert.byteArrayToHexString(expected)));
}
}
}