jdk-24/test/jdk/sun/security/provider/NamedEdDSA.java
2024-10-11 21:16:41 +00:00

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);
}
}