Path: blob/master/test/jdk/sun/security/ec/ed/EdDSATest.java
41152 views
/*1* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223import static javax.crypto.Cipher.PRIVATE_KEY;24import static javax.crypto.Cipher.PUBLIC_KEY;25import java.io.ByteArrayInputStream;26import java.io.ByteArrayOutputStream;27import java.io.IOException;28import java.io.ObjectInputStream;29import java.io.ObjectOutputStream;30import java.security.InvalidKeyException;31import java.security.Key;32import java.security.KeyFactory;33import java.security.KeyPair;34import java.security.KeyPairGenerator;35import java.security.NoSuchAlgorithmException;36import java.security.NoSuchProviderException;37import java.security.PrivateKey;38import java.security.PublicKey;39import java.security.SecureRandom;40import java.security.Signature;41import java.security.interfaces.EdECPrivateKey;42import java.security.interfaces.EdECPublicKey;43import java.security.spec.PKCS8EncodedKeySpec;44import java.security.spec.X509EncodedKeySpec;45import java.security.spec.EdECPrivateKeySpec;46import java.security.spec.EdECPublicKeySpec;47import java.security.spec.InvalidKeySpecException;48import java.security.spec.NamedParameterSpec;49import java.security.spec.EdDSAParameterSpec;50import java.util.Arrays;51import java.util.HexFormat;5253/*54* @test55* @bug 820963256* @summary Test Signature with variation of serialized EDDSA Keys.57* @library /test/lib58* @build jdk.test.lib.Convert59* @run main EdDSATest60*/61public class EdDSATest {6263private static final String EDDSA = "EdDSA";64private static final String ED25519 = "Ed25519";65private static final String ED448 = "Ed448";66private static final String OIDN25519 = "1.3.101.112";67private static final String OID25519 = "OID.1.3.101.112";68private static final String OIDN448 = "1.3.101.113";69private static final String OID448 = "OID.1.3.101.113";70private static final String PROVIDER = "SunEC";71private static final byte[] MSG = "TEST".getBytes();72private static final SecureRandom S_RND = new SecureRandom(new byte[]{0x1});7374public static void main(String[] args) throws Exception {7576for (boolean random : new boolean[]{true, false}) {7778// Default Parameter79test(PROVIDER, EDDSA, null, random);80test(PROVIDER, ED25519, null, random);81test(PROVIDER, ED448, null, random);8283// With named parameter84test(PROVIDER, EDDSA, ED25519, random);85test(PROVIDER, ED25519, ED25519, random);86test(PROVIDER, OIDN25519, ED25519, random);87test(PROVIDER, OID25519, ED25519, random);88test(PROVIDER, ED448, ED448, random);89test(PROVIDER, OIDN448, ED448, random);90test(PROVIDER, OID448, ED448, random);9192// With size parameter93test(PROVIDER, EDDSA, 255, random);94test(PROVIDER, ED25519, 255, random);95test(PROVIDER, OIDN25519, 255, random);96test(PROVIDER, OID25519, 255, random);97test(PROVIDER, ED448, 448, random);98test(PROVIDER, OIDN448, 448, random);99test(PROVIDER, OID448, 448, random);100}101}102103// Test signature using a KeyPair and the corresponding transformed one.104private static void test(String provider, String name, Object param,105boolean random) throws Exception {106107System.out.printf("Case Algo:%s, Param:%s, Intitiate with random:%s%n",108name, param, random);109KeyPair origkp = genKeyPair(provider, name, param, random);110testSignature(provider, name, origkp, origkp);111NamedParameterSpec namedSpec = namedParamSpec(name);112// Test all possible transformed private/public keys113for (Key priKey : manipulateKey(provider, name, PRIVATE_KEY,114origkp.getPrivate(), namedSpec)) {115for (Key pubKey : manipulateKey(provider, name, PUBLIC_KEY,116origkp.getPublic(), namedSpec)) {117EdECPrivateKey pri = (EdECPrivateKey) priKey;118EdECPublicKey pub = (EdECPublicKey) pubKey;119// Test the keys are serializable.120testSerialize(origkp, new KeyPair(pub, pri));121// Test signature122testSignature(provider, name, origkp, new KeyPair(pub, pri));123}124}125System.out.println("Passed.");126}127128private static KeyPair genKeyPair(String provider, String name,129Object param, boolean random) throws Exception {130131KeyPairGenerator kpg = KeyPairGenerator.getInstance(name, provider);132if (random) {133if (param instanceof Integer) {134kpg.initialize((Integer) param, S_RND);135} else if (param instanceof String) {136kpg.initialize(new NamedParameterSpec((String) param), S_RND);137}138} else {139if (param instanceof Integer) {140kpg.initialize((Integer) param);141} else if (param instanceof String) {142kpg.initialize(new NamedParameterSpec((String) param));143}144}145equals(kpg.getProvider().getName(), provider);146equals(kpg.getAlgorithm(), name);147return kpg.generateKeyPair();148}149150private static NamedParameterSpec namedParamSpec(String algo) {151NamedParameterSpec namedSpec = switch (algo) {152case EDDSA153, OIDN25519, OID25519 -> new NamedParameterSpec(ED25519);154case OIDN448155, OID448 -> new NamedParameterSpec(ED448);156default->157new NamedParameterSpec(algo);158};159return namedSpec;160}161162private static Key[] manipulateKey(String provider, String name, int type,163Key key, NamedParameterSpec namedSpec)164throws NoSuchAlgorithmException, InvalidKeySpecException,165NoSuchProviderException, InvalidKeyException {166167KeyFactory kf = KeyFactory.getInstance(name, provider);168switch (type) {169case PUBLIC_KEY:170return new Key[]{171kf.generatePublic(new X509EncodedKeySpec(key.getEncoded())),172kf.generatePublic(kf.getKeySpec(173key, EdECPublicKeySpec.class)),174kf.generatePublic(new EdECPublicKeySpec(namedSpec,175((EdECPublicKey) key).getPoint())),176kf.translateKey(key)177};178case PRIVATE_KEY:179return new Key[]{180kf.generatePrivate(new PKCS8EncodedKeySpec(key.getEncoded())),181kf.generatePrivate(182kf.getKeySpec(key, EdECPrivateKeySpec.class)),183kf.generatePrivate(new EdECPrivateKeySpec(namedSpec,184((EdECPrivateKey) key).getBytes().get())),185kf.translateKey(key)186};187}188throw new RuntimeException("We shouldn't reach here");189}190191/**192* Test Signature with a set of parameter combination.193*/194private static void testSignature(String provider, String name,195KeyPair origkp, KeyPair kp) throws Exception {196197signAndVerify(provider, name, origkp, kp, null);198// Test Case with Pre-Hash enabled and disabled.199for (boolean preHash : new boolean[]{true, false}) {200signAndVerify(provider, name, origkp, kp,201new EdDSAParameterSpec(preHash));202// Test Case with Context combined.203for (byte[] context : new byte[][]{204{}, "a".getBytes(), new byte[255]}) {205signAndVerify(provider, name, origkp, kp,206new EdDSAParameterSpec(preHash, context));207}208}209}210211private static void signAndVerify(String provider, String name,212KeyPair origkp, KeyPair kp, EdDSAParameterSpec params)213throws Exception {214215Signature sig = Signature.getInstance(name, provider);216if (params != null) {217sig.setParameter(params);218}219sig.initSign(origkp.getPrivate());220sig.update(MSG);221byte[] origSign = sig.sign();222223sig.update(MSG);224byte[] computedSig = sig.sign();225equals(origSign, computedSig);226// EdDSA signatures size (64 and 114 bytes) for Ed25519 and Ed448.227int expectedSigSize = edSignatureSize(name);228equals(origSign.length, expectedSigSize);229sig.initSign(kp.getPrivate());230sig.update(MSG);231equals(computedSig, sig.sign());232// Use same signature instance to verify with transformed PublicKey.233sig.initVerify(kp.getPublic());234sig.update(MSG);235if (!sig.verify(origSign)) {236throw new RuntimeException(String.format("Signature did not verify"237+ " for name:%s, prehash:%s, context:%s", name,238(params == null) ? null : params.isPrehash(),239(params == null) ? null : params.getContext().get()));240}241242// Create a new signature to re-verify.243sig = Signature.getInstance(name, provider);244if (params != null) {245sig.setParameter(params);246}247// Verify the signature with transformed PublicKey.248sig.initVerify(kp.getPublic());249sig.update(MSG);250if (!sig.verify(origSign)) {251throw new RuntimeException(String.format("Signature did not verify"252+ " for name:%s, prehash:%s, context:%s",253name, (params == null) ? null : params.isPrehash(),254(params == null) ? null : params.getContext().get()));255}256equals(sig.getAlgorithm(), name);257equals(sig.getProvider().getName(), provider);258}259260private static int edSignatureSize(String algo) {261int size = switch (algo) {262case EDDSA263, ED25519, OIDN25519, OID25519 -> 64;264case ED448265, OIDN448, OID448 -> 114;266default->267-1;268};269return size;270}271272/**273* Compare original KeyPair with transformed ones.274*/275private static void testKeyEquals(KeyPair origkp, PublicKey pubKey,276PrivateKey priKey) {277278if (!origkp.getPrivate().equals(priKey)279&& !Arrays.equals(origkp.getPrivate().getEncoded(),280priKey.getEncoded())281&& origkp.getPrivate().hashCode() != priKey.hashCode()) {282throw new RuntimeException(283"PrivateKey is not equal with transformed one");284}285if (!origkp.getPublic().equals(pubKey)286&& !Arrays.equals(origkp.getPublic().getEncoded(),287pubKey.getEncoded())288&& origkp.getPublic().hashCode() != pubKey.hashCode()) {289throw new RuntimeException(290"PublicKey is not equal with transformed one");291}292}293294/**295* Test serialization of KeyPair and Keys.296*/297private static void testSerialize(KeyPair origkp, KeyPair kp)298throws Exception {299300testKeyEquals(origkp, kp.getPublic(), kp.getPrivate());301PrivateKey priv = deserializedCopy(kp.getPrivate(), PrivateKey.class);302PublicKey pub = deserializedCopy(kp.getPublic(), PublicKey.class);303testKeyEquals(origkp, pub, priv);304// Verify Serialized KeyPair instance.305KeyPair copy = deserializedCopy(kp, KeyPair.class);306testKeyEquals(origkp, copy.getPublic(), copy.getPrivate());307}308309private static <T extends Object> T deserializedCopy(T origkp, Class<T> type)310throws IOException, ClassNotFoundException {311return deserialize(serialize(origkp), type);312}313314/**315* Deserialize the Key object.316*/317private static <T extends Object> T deserialize(byte[] serialized,318Class<T> type) throws IOException, ClassNotFoundException {319320T key = null;321try (ByteArrayInputStream bis = new ByteArrayInputStream(serialized);322ObjectInputStream ois = new ObjectInputStream(bis)) {323key = (T) ois.readObject();324}325return key;326}327328/**329* Serialize the given Key object.330*/331private static <T extends Object> byte[] serialize(T key)332throws IOException {333334try (ByteArrayOutputStream bos = new ByteArrayOutputStream();335ObjectOutputStream oos = new ObjectOutputStream(bos)) {336oos.writeObject(key);337return bos.toByteArray();338}339}340341private static void equals(Object actual, Object expected) {342if (!actual.equals(expected)) {343throw new RuntimeException(String.format("Actual: %s, Expected: %s",344actual, expected));345}346}347348private static void equals(byte[] actual, byte[] expected) {349if (!Arrays.equals(actual, expected)) {350throw new RuntimeException(String.format("Actual array: %s, "351+ "Expected array:%s", HexFormat.of().withUpperCase().formatHex(actual),352HexFormat.of().withUpperCase().formatHex(expected)));353}354}355}356357358