3f53d57134
Reviewed-by: ascarpino, mullan
240 lines
8.3 KiB
Java
240 lines
8.3 KiB
Java
/*
|
|
* 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 8340327
|
|
* @modules java.base/sun.security.ec.ed
|
|
* java.base/sun.security.ec.point
|
|
* java.base/sun.security.jca
|
|
* java.base/sun.security.provider
|
|
* @library /test/lib
|
|
*/
|
|
|
|
import jdk.test.lib.Asserts;
|
|
import jdk.test.lib.Utils;
|
|
import sun.security.ec.ed.EdDSAOperations;
|
|
import sun.security.ec.ed.EdDSAParameters;
|
|
import sun.security.ec.point.AffinePoint;
|
|
import sun.security.jca.JCAUtil;
|
|
import sun.security.provider.NamedKeyFactory;
|
|
import sun.security.provider.NamedKeyPairGenerator;
|
|
import sun.security.provider.NamedSignature;
|
|
|
|
import java.security.*;
|
|
import java.security.spec.EdDSAParameterSpec;
|
|
import java.security.spec.NamedParameterSpec;
|
|
import java.util.Arrays;
|
|
import java.util.List;
|
|
|
|
public class NamedEdDSA {
|
|
|
|
public static class ProviderImpl extends Provider {
|
|
public ProviderImpl() {
|
|
super("Named", "0", "");
|
|
put("KeyPairGenerator.EdDSA", EdDSAKeyPairGenerator.class.getName());
|
|
put("KeyPairGenerator.Ed25519", EdDSAKeyPairGenerator.Ed25519.class.getName());
|
|
put("KeyPairGenerator.Ed448", EdDSAKeyPairGenerator.Ed448.class.getName());
|
|
put("KeyFactory.EdDSA", EdDSAKeyFactory.class.getName());
|
|
put("KeyFactory.Ed25519", EdDSAKeyFactory.Ed25519.class.getName());
|
|
put("KeyFactory.Ed448", EdDSAKeyFactory.Ed448.class.getName());
|
|
put("Signature.EdDSA", EdDSASignature.class.getName());
|
|
put("Signature.Ed25519", EdDSASignature.Ed25519.class.getName());
|
|
put("Signature.Ed448", EdDSASignature.Ed448.class.getName());
|
|
}
|
|
}
|
|
|
|
public static class EdDSASignature extends NamedSignature {
|
|
public EdDSASignature() {
|
|
super("EdDSA", "Ed25519", "Ed448");
|
|
}
|
|
|
|
protected EdDSASignature(String pname) {
|
|
super("EdDSA", pname);
|
|
}
|
|
|
|
public static class Ed25519 extends EdDSASignature {
|
|
public Ed25519() {
|
|
super("Ed25519");
|
|
}
|
|
}
|
|
|
|
public static class Ed448 extends EdDSASignature {
|
|
public Ed448() {
|
|
super("Ed448");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public byte[] implSign(String name, byte[] sk, Object sk2, byte[] msg, SecureRandom sr) throws SignatureException {
|
|
return getOps(name).sign(plain, sk, msg);
|
|
}
|
|
|
|
@Override
|
|
public boolean implVerify(String name, byte[] pk, Object pk2, byte[] msg, byte[] sig) throws SignatureException {
|
|
return getOps(name).verify(plain, (AffinePoint) pk2, pk, msg, sig);
|
|
}
|
|
|
|
@Override
|
|
public Object implCheckPublicKey(String name, byte[] pk) throws InvalidKeyException {
|
|
return getOps(name).decodeAffinePoint(InvalidKeyException::new, pk);
|
|
}
|
|
}
|
|
|
|
public static class EdDSAKeyFactory extends NamedKeyFactory {
|
|
public EdDSAKeyFactory() {
|
|
super("EdDSA", "Ed25519", "Ed448");
|
|
}
|
|
|
|
protected EdDSAKeyFactory(String pname) {
|
|
super("EdDSA", pname);
|
|
}
|
|
|
|
public static class Ed25519 extends EdDSAKeyFactory {
|
|
public Ed25519() {
|
|
super("Ed25519");
|
|
}
|
|
}
|
|
|
|
public static class Ed448 extends EdDSAKeyFactory {
|
|
public Ed448() {
|
|
super("Ed448");
|
|
}
|
|
}
|
|
}
|
|
|
|
public static class EdDSAKeyPairGenerator extends NamedKeyPairGenerator {
|
|
public EdDSAKeyPairGenerator() {
|
|
super("EdDSA", "Ed25519", "Ed448");
|
|
}
|
|
|
|
protected EdDSAKeyPairGenerator(String pname) {
|
|
super("EdDSA", pname);
|
|
}
|
|
|
|
public static class Ed25519 extends EdDSAKeyPairGenerator {
|
|
public Ed25519() {
|
|
super("Ed25519");
|
|
}
|
|
}
|
|
|
|
public static class Ed448 extends EdDSAKeyPairGenerator {
|
|
public Ed448() {
|
|
super("Ed448");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public byte[][] implGenerateKeyPair(String pname, SecureRandom sr) {
|
|
sr = sr == null ? JCAUtil.getDefSecureRandom() : sr;
|
|
var op = getOps(pname);
|
|
var sk = op.generatePrivate(sr);
|
|
var point = op.computePublic(sk);
|
|
byte[] encodedPoint = point.getY().toByteArray();
|
|
reverse(encodedPoint);
|
|
// array may be too large or too small, depending on the value
|
|
encodedPoint = Arrays.copyOf(encodedPoint, op.getParameters().getKeyLength());
|
|
// set the high-order bit of the encoded point
|
|
byte msb = (byte) (point.isXOdd() ? 0x80 : 0);
|
|
encodedPoint[encodedPoint.length - 1] |= msb;
|
|
return new byte[][] { encodedPoint, sk };
|
|
}
|
|
|
|
private static void swap(byte[] arr, int i, int j) {
|
|
byte tmp = arr[i];
|
|
arr[i] = arr[j];
|
|
arr[j] = tmp;
|
|
}
|
|
|
|
private static void reverse(byte [] arr) {
|
|
int i = 0;
|
|
int j = arr.length - 1;
|
|
|
|
while (i < j) {
|
|
swap(arr, i, j);
|
|
i++;
|
|
j--;
|
|
}
|
|
}
|
|
}
|
|
|
|
private static EdDSAOperations getOps(String pname) {
|
|
var op = switch (pname) {
|
|
case "Ed25519" -> e2;
|
|
case "Ed448" -> e4;
|
|
default -> throw new AssertionError("unknown pname " + pname);
|
|
};
|
|
return op;
|
|
}
|
|
|
|
static final EdDSAParameterSpec plain = new EdDSAParameterSpec(false);
|
|
static final EdDSAOperations e2, e4;
|
|
static {
|
|
try {
|
|
e2 = new EdDSAOperations(EdDSAParameters.getBySize(AssertionError::new, 255));
|
|
e4 = new EdDSAOperations(EdDSAParameters.getBySize(AssertionError::new, 448));
|
|
} catch (Exception e) {
|
|
throw new AssertionError(e);
|
|
}
|
|
}
|
|
|
|
public static void main(String[] args) throws Exception {
|
|
var ps = List.of(new ProviderImpl(), Security.getProvider("SunEC"));
|
|
for (var p1 : ps) {
|
|
for (var p2 : ps) {
|
|
for (var p3 : ps) {
|
|
test(p1, p2, p3);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void test(Provider p1, Provider p2, Provider p3) throws Exception {
|
|
System.out.println(p1.getName() + " " + p2.getName() + " " + p3.getName());
|
|
var g = KeyPairGenerator.getInstance("EdDSA", p1);
|
|
g.initialize(NamedParameterSpec.ED448);
|
|
var kp = g.generateKeyPair();
|
|
var s1 = Signature.getInstance("EdDSA", p2);
|
|
var s2 = Signature.getInstance("EdDSA", p3);
|
|
var f1 = KeyFactory.getInstance("EdDSA", p2);
|
|
var f2 = KeyFactory.getInstance("EdDSA", p3);
|
|
var sk = (PrivateKey) f1.translateKey(kp.getPrivate());
|
|
var pk = (PublicKey) f2.translateKey(kp.getPublic());
|
|
// sign and verify twice to make sure the key is intact
|
|
s1.initSign(sk);
|
|
var sig1 = s1.sign();
|
|
s1.initSign(sk);
|
|
var sig2 = s1.sign();
|
|
// EdDSA signing is deterministic
|
|
Asserts.assertEqualsByteArray(sig1, sig2);
|
|
s2.initVerify(pk);
|
|
Asserts.assertTrue(s2.verify(sig1));
|
|
s2.initVerify(pk);
|
|
Asserts.assertTrue(s2.verify(sig2));
|
|
// No parameters defined
|
|
s1.setParameter(null);
|
|
Utils.runAndCheckException(() -> s1.setParameter(NamedParameterSpec.ED448),
|
|
InvalidAlgorithmParameterException.class);
|
|
}
|
|
}
|