mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 22:34:27 +02:00
8166597: Crypto support for the EdDSA Signature Algorithm
Reviewed-by: weijun, mullan, wetmore
This commit is contained in:
parent
02293daa64
commit
fd28aad72d
47 changed files with 4697 additions and 155 deletions
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -21,7 +21,6 @@
|
||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file is used to generated optimized finite field implementations.
|
* This file is used to generated optimized finite field implementations.
|
||||||
*/
|
*/
|
||||||
|
@ -170,6 +169,19 @@ public class FieldGen {
|
||||||
o521crSequence(19), orderFieldSmallCrSequence(19)
|
o521crSequence(19), orderFieldSmallCrSequence(19)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
static FieldParams O25519 = new FieldParams(
|
||||||
|
"Curve25519OrderField", 26, 10, 1, 252,
|
||||||
|
"1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed",
|
||||||
|
orderFieldCrSequence(10), orderFieldSmallCrSequence(10)
|
||||||
|
);
|
||||||
|
|
||||||
|
static FieldParams O448 = new FieldParams(
|
||||||
|
"Curve448OrderField", 28, 16, 1, 446,
|
||||||
|
"3fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f3",
|
||||||
|
//"ffffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f3",
|
||||||
|
orderFieldCrSequence(16), orderFieldSmallCrSequence(16)
|
||||||
|
);
|
||||||
|
|
||||||
private static List<CarryReduce> o521crSequence(int numLimbs) {
|
private static List<CarryReduce> o521crSequence(int numLimbs) {
|
||||||
|
|
||||||
// split the full reduce in half, with a carry in between
|
// split the full reduce in half, with a carry in between
|
||||||
|
@ -212,7 +224,8 @@ public class FieldGen {
|
||||||
}
|
}
|
||||||
|
|
||||||
static final FieldParams[] ALL_FIELDS = {
|
static final FieldParams[] ALL_FIELDS = {
|
||||||
P256, P384, P521, O256, O384, O521,
|
Curve25519, Curve448,
|
||||||
|
P256, P384, P521, O256, O384, O521, O25519, O448
|
||||||
};
|
};
|
||||||
|
|
||||||
public static class Term {
|
public static class Term {
|
||||||
|
@ -322,6 +335,11 @@ public class FieldGen {
|
||||||
private Iterable<Term> buildTerms(BigInteger sub) {
|
private Iterable<Term> buildTerms(BigInteger sub) {
|
||||||
// split a large subtrahend into smaller terms
|
// split a large subtrahend into smaller terms
|
||||||
// that are aligned with limbs
|
// that are aligned with limbs
|
||||||
|
boolean negate = false;
|
||||||
|
if (sub.compareTo(BigInteger.ZERO) < 0) {
|
||||||
|
negate = true;
|
||||||
|
sub = sub.negate();
|
||||||
|
}
|
||||||
List<Term> result = new ArrayList<Term>();
|
List<Term> result = new ArrayList<Term>();
|
||||||
BigInteger mod = BigInteger.valueOf(1 << bitsPerLimb);
|
BigInteger mod = BigInteger.valueOf(1 << bitsPerLimb);
|
||||||
int termIndex = 0;
|
int termIndex = 0;
|
||||||
|
@ -332,6 +350,9 @@ public class FieldGen {
|
||||||
coef = coef - (1 << bitsPerLimb);
|
coef = coef - (1 << bitsPerLimb);
|
||||||
plusOne = true;
|
plusOne = true;
|
||||||
}
|
}
|
||||||
|
if (negate) {
|
||||||
|
coef = 0 - coef;
|
||||||
|
}
|
||||||
if (coef != 0) {
|
if (coef != 0) {
|
||||||
int pow = termIndex * bitsPerLimb;
|
int pow = termIndex * bitsPerLimb;
|
||||||
result.add(new Term(pow, -coef));
|
result.add(new Term(pow, -coef));
|
||||||
|
@ -619,6 +640,14 @@ public class FieldGen {
|
||||||
result.appendLine();
|
result.appendLine();
|
||||||
result.appendLine("}");
|
result.appendLine("}");
|
||||||
|
|
||||||
|
StringBuilder coqTerms = new StringBuilder("//");
|
||||||
|
for (Term t : params.getTerms()) {
|
||||||
|
coqTerms.append("(" + t.getPower() + "%nat,");
|
||||||
|
coqTerms.append(t.getCoefficient() + ")::");
|
||||||
|
}
|
||||||
|
coqTerms.append("nil.");
|
||||||
|
result.appendLine(coqTerms.toString());
|
||||||
|
|
||||||
result.appendLine("private static BigInteger evaluateModulus() {");
|
result.appendLine("private static BigInteger evaluateModulus() {");
|
||||||
result.incrIndent();
|
result.incrIndent();
|
||||||
result.appendLine("BigInteger result = BigInteger.valueOf(2).pow("
|
result.appendLine("BigInteger result = BigInteger.valueOf(2).pow("
|
||||||
|
@ -650,6 +679,41 @@ public class FieldGen {
|
||||||
result.decrIndent();
|
result.decrIndent();
|
||||||
result.appendLine("}");
|
result.appendLine("}");
|
||||||
|
|
||||||
|
result.appendLine("@Override");
|
||||||
|
result.appendLine("protected void reduceIn(long[] limbs, long v, int i) {");
|
||||||
|
result.incrIndent();
|
||||||
|
String c = "v";
|
||||||
|
for (Term t : params.getTerms()) {
|
||||||
|
int reduceBits = params.getPower() - t.getPower();
|
||||||
|
int coefficient = -1 * t.getCoefficient();
|
||||||
|
|
||||||
|
String x = coefficient + " * " + c;
|
||||||
|
String accOp = "+=";
|
||||||
|
String temp = null;
|
||||||
|
if (coefficient == 1) {
|
||||||
|
x = c;
|
||||||
|
} else if (coefficient == -1) {
|
||||||
|
x = c;
|
||||||
|
accOp = "-=";
|
||||||
|
} else {
|
||||||
|
temp = result.getTemporary("long", x);
|
||||||
|
x = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reduceBits % params.getBitsPerLimb() == 0) {
|
||||||
|
int pos = reduceBits / params.getBitsPerLimb();
|
||||||
|
result.appendLine("limbs[i - " + pos + "] " + accOp + " " + x + ";");
|
||||||
|
} else {
|
||||||
|
int secondPos = reduceBits / params.getBitsPerLimb();
|
||||||
|
int bitOffset = (secondPos + 1) * params.getBitsPerLimb() - reduceBits;
|
||||||
|
int rightBitOffset = params.getBitsPerLimb() - bitOffset;
|
||||||
|
result.appendLine("limbs[i - " + (secondPos + 1) + "] " + accOp + " (" + x + " << " + bitOffset + ") & LIMB_MASK;");
|
||||||
|
result.appendLine("limbs[i - " + secondPos + "] " + accOp + " " + x + " >> " + rightBitOffset + ";");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.decrIndent();
|
||||||
|
result.appendLine("}");
|
||||||
|
|
||||||
result.appendLine("@Override");
|
result.appendLine("@Override");
|
||||||
result.appendLine("protected void finalCarryReduceLast(long[] limbs) {");
|
result.appendLine("protected void finalCarryReduceLast(long[] limbs) {");
|
||||||
result.incrIndent();
|
result.incrIndent();
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* 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. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* 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 java.security.interfaces;
|
||||||
|
|
||||||
|
import java.security.spec.NamedParameterSpec;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface for an elliptic curve public/private key as defined by
|
||||||
|
* <a href="https://tools.ietf.org/html/rfc8032">RFC 8032: Edwards-Curve
|
||||||
|
* Digital Signature Algorithm (EdDSA)</a>. These keys are distinct from the
|
||||||
|
* keys represented by {@code ECKey}, and they are intended for use with
|
||||||
|
* algorithms based on RFC 8032 such as the EdDSA {@code Signature} algorithm.
|
||||||
|
* This interface allows access to the algorithm parameters associated with
|
||||||
|
* the key.
|
||||||
|
*
|
||||||
|
* @since 15
|
||||||
|
*/
|
||||||
|
public interface EdECKey {
|
||||||
|
/**
|
||||||
|
* Returns the algorithm parameters associated with the key.
|
||||||
|
*
|
||||||
|
* @return the associated algorithm parameters.
|
||||||
|
*/
|
||||||
|
NamedParameterSpec getParams();
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* 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. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* 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 java.security.interfaces;
|
||||||
|
|
||||||
|
import java.security.PrivateKey;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface for an elliptic curve private key as defined by
|
||||||
|
* <a href="https://tools.ietf.org/html/rfc8032">RFC 8032: Edwards-Curve
|
||||||
|
* Digital Signature Algorithm (EdDSA)</a>. These keys are distinct from the
|
||||||
|
* keys represented by {@code ECPrivateKey}, and they are intended for use
|
||||||
|
* with algorithms based on RFC 8032 such as the EdDSA {@code Signature}
|
||||||
|
* algorithm.
|
||||||
|
* <p>
|
||||||
|
* An Edwards-Curve private key is a bit string. This interface only supports bit
|
||||||
|
* string lengths that are a multiple of 8, and the key is represented using
|
||||||
|
* a byte array.
|
||||||
|
*
|
||||||
|
* @since 15
|
||||||
|
*/
|
||||||
|
public interface EdECPrivateKey extends EdECKey, PrivateKey {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a copy of the byte array representing the private key. This method
|
||||||
|
* may return an empty {@code Optional} if the implementation is not
|
||||||
|
* willing to produce the private key value.
|
||||||
|
*
|
||||||
|
* @return an {@code Optional} containing the private key byte array.
|
||||||
|
* If the key is not available, then an empty {@code Optional}.
|
||||||
|
*/
|
||||||
|
Optional<byte[]> getBytes();
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* 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. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* 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 java.security.interfaces;
|
||||||
|
|
||||||
|
import java.security.PublicKey;
|
||||||
|
import java.security.spec.EdECPoint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface for an elliptic curve public key as defined by
|
||||||
|
* <a href="https://tools.ietf.org/html/rfc8032">RFC 8032: Edwards-Curve
|
||||||
|
* Digital Signature Algorithm (EdDSA)</a>. These keys are distinct from the
|
||||||
|
* keys represented by {@code ECPublicKey}, and they are intended for use with
|
||||||
|
* algorithms based on RFC 8032 such as the EdDSA {@code Signature} algorithm.
|
||||||
|
* <p>
|
||||||
|
* An Edwards-Curve public key is a point on the curve, which is represented using an
|
||||||
|
* EdECPoint.
|
||||||
|
*
|
||||||
|
* @since 15
|
||||||
|
*/
|
||||||
|
public interface EdECPublicKey extends EdECKey, PublicKey {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the point representing the public key.
|
||||||
|
*
|
||||||
|
* @return the {@code EdECPoint} representing the public key.
|
||||||
|
*/
|
||||||
|
EdECPoint getPoint();
|
||||||
|
}
|
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
* 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. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* 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 java.security.spec;
|
||||||
|
|
||||||
|
import java.security.InvalidParameterException;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class used to specify EdDSA signature and verification parameters. All
|
||||||
|
* algorithm modes in <a href="https://tools.ietf.org/html/rfc8032">RFC 8032:
|
||||||
|
* Edwards-Curve Digital Signature Algorithm (EdDSA)</a> can be specified using
|
||||||
|
* combinations of the settings in this class.
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>If prehash is true, then the mode is Ed25519ph or Ed448ph</li>
|
||||||
|
* <li>Otherwise, if a context is present, the mode is Ed25519ctx or Ed448</li>
|
||||||
|
* <li>Otherwise, the mode is Ed25519 or Ed448</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @since 15
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class EdDSAParameterSpec implements AlgorithmParameterSpec {
|
||||||
|
|
||||||
|
private final boolean prehash;
|
||||||
|
private final byte[] context;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct an {@code EdDSAParameterSpec} by specifying whether the prehash mode
|
||||||
|
* is used. No context is provided so this constructor specifies a mode
|
||||||
|
* in which the context is null. Note that this mode may be different
|
||||||
|
* than the mode in which an empty array is used as the context.
|
||||||
|
*
|
||||||
|
* @param prehash whether the prehash mode is specified.
|
||||||
|
*/
|
||||||
|
public EdDSAParameterSpec(boolean prehash) {
|
||||||
|
this.prehash = prehash;
|
||||||
|
this.context = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct an {@code EdDSAParameterSpec} by specifying a context and whether the
|
||||||
|
* prehash mode is used. The context may not be null, but it may be an
|
||||||
|
* empty array. The mode used when the context is an empty array may not be
|
||||||
|
* the same as the mode used when the context is absent.
|
||||||
|
*
|
||||||
|
* @param prehash whether the prehash mode is specified.
|
||||||
|
* @param context the context is copied and bound to the signature.
|
||||||
|
* @throws NullPointerException if context is null.
|
||||||
|
* @throws InvalidParameterException if context length is greater than 255.
|
||||||
|
*/
|
||||||
|
public EdDSAParameterSpec(boolean prehash, byte[] context) {
|
||||||
|
|
||||||
|
Objects.requireNonNull(context, "context may not be null");
|
||||||
|
if (context.length > 255) {
|
||||||
|
throw new InvalidParameterException("context length cannot be " +
|
||||||
|
"greater than 255");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.prehash = prehash;
|
||||||
|
this.context = context.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get whether the prehash mode is specified.
|
||||||
|
*
|
||||||
|
* @return whether the prehash mode is specified.
|
||||||
|
*/
|
||||||
|
public boolean isPrehash() {
|
||||||
|
return prehash;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the context that the signature will use.
|
||||||
|
*
|
||||||
|
* @return {@code Optional} contains a copy of the context or empty
|
||||||
|
* if context is null.
|
||||||
|
*/
|
||||||
|
public Optional<byte[]> getContext() {
|
||||||
|
if (context == null) {
|
||||||
|
return Optional.empty();
|
||||||
|
} else {
|
||||||
|
return Optional.of(context.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
* 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. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* 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 java.security.spec;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An elliptic curve point used to specify keys as defined by
|
||||||
|
* <a href="https://tools.ietf.org/html/rfc8032">RFC 8032: Edwards-Curve
|
||||||
|
* Digital Signature Algorithm (EdDSA)</a>. These points are distinct from the
|
||||||
|
* points represented by {@code ECPoint}, and they are intended for use with
|
||||||
|
* algorithms based on RFC 8032 such as the EdDSA {@code Signature} algorithm.
|
||||||
|
* <p>
|
||||||
|
* An EdEC point is specified by its y-coordinate value and a boolean that
|
||||||
|
* indicates whether the x-coordinate is odd. The y-coordinate is an
|
||||||
|
* element of the field of integers modulo some value p that is determined by
|
||||||
|
* the algorithm parameters. This field element is represented by a
|
||||||
|
* {@code BigInteger}, and implementations that consume objects of this class
|
||||||
|
* may reject integer values which are not in the range [0, p).
|
||||||
|
*
|
||||||
|
* @since 15
|
||||||
|
*/
|
||||||
|
|
||||||
|
public final class EdECPoint {
|
||||||
|
|
||||||
|
private final boolean xOdd;
|
||||||
|
private final BigInteger y;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct an EdECPoint.
|
||||||
|
*
|
||||||
|
* @param xOdd whether the x-coordinate is odd.
|
||||||
|
* @param y the y-coordinate, represented using a {@code BigInteger}.
|
||||||
|
*
|
||||||
|
* @throws NullPointerException if {@code y} is null.
|
||||||
|
*/
|
||||||
|
public EdECPoint(boolean xOdd, BigInteger y) {
|
||||||
|
|
||||||
|
Objects.requireNonNull(y, "y must not be null");
|
||||||
|
|
||||||
|
this.xOdd = xOdd;
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get whether the x-coordinate of the point is odd.
|
||||||
|
*
|
||||||
|
* @return a boolean indicating whether the x-coordinate is odd.
|
||||||
|
*/
|
||||||
|
public boolean isXOdd() {
|
||||||
|
return xOdd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the y-coordinate of the point.
|
||||||
|
*
|
||||||
|
* @return the y-coordinate, represented using a {@code BigInteger}.
|
||||||
|
*/
|
||||||
|
public BigInteger getY() {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
/*
|
||||||
|
* 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. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* 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 java.security.spec;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class representing elliptic curve private keys as defined in
|
||||||
|
* <a href="https://tools.ietf.org/html/rfc8032">RFC 8032: Edwards-Curve
|
||||||
|
* Digital Signature Algorithm (EdDSA)</a>, including the curve and other
|
||||||
|
* algorithm parameters. The private key is a bit string represented using
|
||||||
|
* a byte array. This class only supports bit string lengths that are a
|
||||||
|
* multiple of 8.
|
||||||
|
*
|
||||||
|
* @since 15
|
||||||
|
*/
|
||||||
|
public final class EdECPrivateKeySpec implements KeySpec {
|
||||||
|
|
||||||
|
private final NamedParameterSpec params;
|
||||||
|
private final byte[] bytes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a private key spec using the supplied parameters and
|
||||||
|
* bit string.
|
||||||
|
*
|
||||||
|
* @param params the algorithm parameters.
|
||||||
|
* @param bytes the key as a byte array. This array is copied
|
||||||
|
* to protect against subsequent modification.
|
||||||
|
*
|
||||||
|
* @throws NullPointerException if {@code params} or {@code bytes}
|
||||||
|
* is null.
|
||||||
|
*/
|
||||||
|
public EdECPrivateKeySpec(NamedParameterSpec params, byte[] bytes) {
|
||||||
|
Objects.requireNonNull(params, "params must not be null");
|
||||||
|
Objects.requireNonNull(bytes, "bytes must not be null");
|
||||||
|
|
||||||
|
this.params = params;
|
||||||
|
this.bytes = bytes.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the algorithm parameters that define the curve and other settings.
|
||||||
|
*
|
||||||
|
* @return the algorithm parameters.
|
||||||
|
*/
|
||||||
|
public NamedParameterSpec getParams() {
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the byte array representing the private key. A new copy of the array
|
||||||
|
* is returned each time this method is called.
|
||||||
|
*
|
||||||
|
* @return the private key as a byte array.
|
||||||
|
*/
|
||||||
|
public byte[] getBytes() {
|
||||||
|
return bytes.clone();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
* 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. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* 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 java.security.spec;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class representing elliptic curve public keys as defined in
|
||||||
|
* <a href="https://tools.ietf.org/html/rfc8032">RFC 8032: Edwards-Curve
|
||||||
|
* Digital Signature Algorithm (EdDSA)</a>, including the curve and other
|
||||||
|
* algorithm parameters. The public key is a point on the curve, which is
|
||||||
|
* represented using an {@code EdECPoint}.
|
||||||
|
*
|
||||||
|
* @since 15
|
||||||
|
*/
|
||||||
|
public final class EdECPublicKeySpec implements KeySpec {
|
||||||
|
|
||||||
|
private final NamedParameterSpec params;
|
||||||
|
private final EdECPoint point;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a public key spec using the supplied parameters and
|
||||||
|
* point.
|
||||||
|
*
|
||||||
|
* @param params the algorithm parameters.
|
||||||
|
* @param point the point representing the public key.
|
||||||
|
*
|
||||||
|
* @throws NullPointerException if {@code params} or {@code point}
|
||||||
|
* is null.
|
||||||
|
*/
|
||||||
|
public EdECPublicKeySpec(NamedParameterSpec params, EdECPoint point) {
|
||||||
|
Objects.requireNonNull(params, "params must not be null");
|
||||||
|
Objects.requireNonNull(point, "point must not be null");
|
||||||
|
|
||||||
|
this.params = params;
|
||||||
|
this.point = point;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the algorithm parameters that define the curve and other settings.
|
||||||
|
*
|
||||||
|
* @return the parameters.
|
||||||
|
*/
|
||||||
|
public NamedParameterSpec getParams() {
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the point representing the public key.
|
||||||
|
*
|
||||||
|
* @return the {@code EdECPoint} representing the public key.
|
||||||
|
*/
|
||||||
|
public EdECPoint getPoint() {
|
||||||
|
return point;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -52,6 +52,22 @@ public class NamedParameterSpec implements AlgorithmParameterSpec {
|
||||||
public static final NamedParameterSpec X448
|
public static final NamedParameterSpec X448
|
||||||
= new NamedParameterSpec("X448");
|
= new NamedParameterSpec("X448");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Ed25519 parameters
|
||||||
|
*
|
||||||
|
* @since 15
|
||||||
|
*/
|
||||||
|
public static final NamedParameterSpec ED25519
|
||||||
|
= new NamedParameterSpec("Ed25519");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Ed448 parameters
|
||||||
|
*
|
||||||
|
* @since 15
|
||||||
|
*/
|
||||||
|
public static final NamedParameterSpec ED448
|
||||||
|
= new NamedParameterSpec("Ed448");
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -294,6 +294,7 @@ module java.base {
|
||||||
java.rmi,
|
java.rmi,
|
||||||
java.security.jgss,
|
java.security.jgss,
|
||||||
jdk.crypto.cryptoki,
|
jdk.crypto.cryptoki,
|
||||||
|
jdk.crypto.ec,
|
||||||
jdk.security.auth;
|
jdk.security.auth;
|
||||||
exports sun.security.provider.certpath to
|
exports sun.security.provider.certpath to
|
||||||
java.naming;
|
java.naming;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -829,6 +829,10 @@ public class PKCS7 {
|
||||||
BigInteger serialNumber = signerChain[0].getSerialNumber();
|
BigInteger serialNumber = signerChain[0].getSerialNumber();
|
||||||
String encAlg = AlgorithmId.getEncAlgFromSigAlg(signatureAlgorithm);
|
String encAlg = AlgorithmId.getEncAlgFromSigAlg(signatureAlgorithm);
|
||||||
String digAlg = AlgorithmId.getDigAlgFromSigAlg(signatureAlgorithm);
|
String digAlg = AlgorithmId.getDigAlgFromSigAlg(signatureAlgorithm);
|
||||||
|
if (digAlg == null) {
|
||||||
|
throw new UnsupportedOperationException("Unable to determine " +
|
||||||
|
"the digest algorithm from the signature algorithm.");
|
||||||
|
}
|
||||||
SignerInfo signerInfo = new SignerInfo(issuerName, serialNumber,
|
SignerInfo signerInfo = new SignerInfo(issuerName, serialNumber,
|
||||||
AlgorithmId.get(digAlg), null,
|
AlgorithmId.get(digAlg), null,
|
||||||
AlgorithmId.get(encAlg),
|
AlgorithmId.get(encAlg),
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -61,14 +61,16 @@ abstract class SHA3 extends DigestBase {
|
||||||
0x8000000000008080L, 0x80000001L, 0x8000000080008008L,
|
0x8000000000008080L, 0x80000001L, 0x8000000080008008L,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private final byte suffix;
|
||||||
private byte[] state = new byte[WIDTH];
|
private byte[] state = new byte[WIDTH];
|
||||||
private long[] lanes = new long[DM*DM];
|
private long[] lanes = new long[DM*DM];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new SHA-3 object.
|
* Creates a new SHA-3 object.
|
||||||
*/
|
*/
|
||||||
SHA3(String name, int digestLength) {
|
SHA3(String name, int digestLength, byte suffix, int c) {
|
||||||
super(name, digestLength, (WIDTH - (2 * digestLength)));
|
super(name, digestLength, (WIDTH - c));
|
||||||
|
this.suffix = suffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -88,7 +90,7 @@ abstract class SHA3 extends DigestBase {
|
||||||
*/
|
*/
|
||||||
void implDigest(byte[] out, int ofs) {
|
void implDigest(byte[] out, int ofs) {
|
||||||
int numOfPadding =
|
int numOfPadding =
|
||||||
setPaddingBytes(buffer, (int)(bytesProcessed % buffer.length));
|
setPaddingBytes(suffix, buffer, (int)(bytesProcessed % buffer.length));
|
||||||
if (numOfPadding < 1) {
|
if (numOfPadding < 1) {
|
||||||
throw new ProviderException("Incorrect pad size: " + numOfPadding);
|
throw new ProviderException("Incorrect pad size: " + numOfPadding);
|
||||||
}
|
}
|
||||||
|
@ -112,13 +114,13 @@ abstract class SHA3 extends DigestBase {
|
||||||
* pad10*1 algorithm (section 5.1) and the 2-bit suffix "01" required
|
* pad10*1 algorithm (section 5.1) and the 2-bit suffix "01" required
|
||||||
* for SHA-3 hash (section 6.1).
|
* for SHA-3 hash (section 6.1).
|
||||||
*/
|
*/
|
||||||
private static int setPaddingBytes(byte[] in, int len) {
|
private static int setPaddingBytes(byte suffix, byte[] in, int len) {
|
||||||
if (len != in.length) {
|
if (len != in.length) {
|
||||||
// erase leftover values
|
// erase leftover values
|
||||||
Arrays.fill(in, len, in.length, (byte)0);
|
Arrays.fill(in, len, in.length, (byte)0);
|
||||||
// directly store the padding bytes into the input
|
// directly store the padding bytes into the input
|
||||||
// as the specified buffer is allocated w/ size = rateR
|
// as the specified buffer is allocated w/ size = rateR
|
||||||
in[len] |= (byte) 0x06;
|
in[len] |= suffix;
|
||||||
in[in.length - 1] |= (byte) 0x80;
|
in[in.length - 1] |= (byte) 0x80;
|
||||||
}
|
}
|
||||||
return (in.length - len);
|
return (in.length - len);
|
||||||
|
@ -268,7 +270,7 @@ abstract class SHA3 extends DigestBase {
|
||||||
*/
|
*/
|
||||||
public static final class SHA224 extends SHA3 {
|
public static final class SHA224 extends SHA3 {
|
||||||
public SHA224() {
|
public SHA224() {
|
||||||
super("SHA3-224", 28);
|
super("SHA3-224", 28, (byte)0x06, 56);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,7 +279,7 @@ abstract class SHA3 extends DigestBase {
|
||||||
*/
|
*/
|
||||||
public static final class SHA256 extends SHA3 {
|
public static final class SHA256 extends SHA3 {
|
||||||
public SHA256() {
|
public SHA256() {
|
||||||
super("SHA3-256", 32);
|
super("SHA3-256", 32, (byte)0x06, 64);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,7 +288,7 @@ abstract class SHA3 extends DigestBase {
|
||||||
*/
|
*/
|
||||||
public static final class SHA384 extends SHA3 {
|
public static final class SHA384 extends SHA3 {
|
||||||
public SHA384() {
|
public SHA384() {
|
||||||
super("SHA3-384", 48);
|
super("SHA3-384", 48, (byte)0x06, 96);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,7 +297,7 @@ abstract class SHA3 extends DigestBase {
|
||||||
*/
|
*/
|
||||||
public static final class SHA512 extends SHA3 {
|
public static final class SHA512 extends SHA3 {
|
||||||
public SHA512() {
|
public SHA512() {
|
||||||
super("SHA3-512", 64);
|
super("SHA3-512", 64, (byte)0x06, 128);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* 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. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* 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 sun.security.provider;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The SHAKE256 extendable output function.
|
||||||
|
*/
|
||||||
|
public final class SHAKE256 extends SHA3 {
|
||||||
|
public SHAKE256(int d) {
|
||||||
|
super("SHAKE256", d, (byte) 0x1F, 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(byte in) {
|
||||||
|
engineUpdate(in);
|
||||||
|
}
|
||||||
|
public void update(byte[] in, int off, int len) {
|
||||||
|
engineUpdate(in, off, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] digest() {
|
||||||
|
return engineDigest();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1870,6 +1870,12 @@ public final class Main {
|
||||||
keysize = SecurityProviderConstants.DEF_RSA_KEY_SIZE;
|
keysize = SecurityProviderConstants.DEF_RSA_KEY_SIZE;
|
||||||
} else if ("DSA".equalsIgnoreCase(keyAlgName)) {
|
} else if ("DSA".equalsIgnoreCase(keyAlgName)) {
|
||||||
keysize = SecurityProviderConstants.DEF_DSA_KEY_SIZE;
|
keysize = SecurityProviderConstants.DEF_DSA_KEY_SIZE;
|
||||||
|
} else if ("EdDSA".equalsIgnoreCase(keyAlgName)) {
|
||||||
|
keysize = SecurityProviderConstants.DEF_ED_KEY_SIZE;
|
||||||
|
} else if ("Ed25519".equalsIgnoreCase(keyAlgName)) {
|
||||||
|
keysize = 255;
|
||||||
|
} else if ("Ed448".equalsIgnoreCase(keyAlgName)) {
|
||||||
|
keysize = 448;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ("EC".equalsIgnoreCase(keyAlgName)) {
|
if ("EC".equalsIgnoreCase(keyAlgName)) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -27,10 +27,10 @@ package sun.security.util;
|
||||||
|
|
||||||
import java.security.AlgorithmParameters;
|
import java.security.AlgorithmParameters;
|
||||||
import java.security.Key;
|
import java.security.Key;
|
||||||
import java.security.PrivilegedAction;
|
|
||||||
import java.security.AccessController;
|
|
||||||
import java.security.InvalidKeyException;
|
import java.security.InvalidKeyException;
|
||||||
import java.security.interfaces.ECKey;
|
import java.security.interfaces.ECKey;
|
||||||
|
import java.security.interfaces.EdECKey;
|
||||||
|
import java.security.interfaces.EdECPublicKey;
|
||||||
import java.security.interfaces.RSAKey;
|
import java.security.interfaces.RSAKey;
|
||||||
import java.security.interfaces.DSAKey;
|
import java.security.interfaces.DSAKey;
|
||||||
import java.security.interfaces.DSAParams;
|
import java.security.interfaces.DSAParams;
|
||||||
|
@ -44,6 +44,7 @@ import javax.crypto.interfaces.DHPublicKey;
|
||||||
import javax.crypto.spec.DHParameterSpec;
|
import javax.crypto.spec.DHParameterSpec;
|
||||||
import javax.crypto.spec.DHPublicKeySpec;
|
import javax.crypto.spec.DHPublicKeySpec;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
import java.security.spec.NamedParameterSpec;
|
||||||
|
|
||||||
import sun.security.jca.JCAUtil;
|
import sun.security.jca.JCAUtil;
|
||||||
|
|
||||||
|
@ -96,6 +97,16 @@ public final class KeyUtil {
|
||||||
} else if (key instanceof DHKey) {
|
} else if (key instanceof DHKey) {
|
||||||
DHKey pubk = (DHKey)key;
|
DHKey pubk = (DHKey)key;
|
||||||
size = pubk.getParams().getP().bitLength();
|
size = pubk.getParams().getP().bitLength();
|
||||||
|
} else if (key instanceof EdECKey) {
|
||||||
|
String nc = ((EdECKey) key).getParams().getName();
|
||||||
|
if (nc.equalsIgnoreCase(NamedParameterSpec.ED25519.getName())) {
|
||||||
|
size = 255;
|
||||||
|
} else if (nc.equalsIgnoreCase(
|
||||||
|
NamedParameterSpec.ED448.getName())) {
|
||||||
|
size = 448;
|
||||||
|
} else {
|
||||||
|
size = -1;
|
||||||
|
}
|
||||||
} // Otherwise, it may be a unextractable key of PKCS#11, or
|
} // Otherwise, it may be a unextractable key of PKCS#11, or
|
||||||
// a key we are not able to handle.
|
// a key we are not able to handle.
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -59,6 +59,7 @@ public final class SecurityProviderConstants {
|
||||||
public static final int DEF_RSASSA_PSS_KEY_SIZE;
|
public static final int DEF_RSASSA_PSS_KEY_SIZE;
|
||||||
public static final int DEF_DH_KEY_SIZE;
|
public static final int DEF_DH_KEY_SIZE;
|
||||||
public static final int DEF_EC_KEY_SIZE;
|
public static final int DEF_EC_KEY_SIZE;
|
||||||
|
public static final int DEF_ED_KEY_SIZE;
|
||||||
|
|
||||||
private static final String KEY_LENGTH_PROP =
|
private static final String KEY_LENGTH_PROP =
|
||||||
"jdk.security.defaultKeySize";
|
"jdk.security.defaultKeySize";
|
||||||
|
@ -70,6 +71,7 @@ public final class SecurityProviderConstants {
|
||||||
int rsaSsaPssKeySize = rsaKeySize; // default to same value as RSA
|
int rsaSsaPssKeySize = rsaKeySize; // default to same value as RSA
|
||||||
int dhKeySize = 2048;
|
int dhKeySize = 2048;
|
||||||
int ecKeySize = 256;
|
int ecKeySize = 256;
|
||||||
|
int edKeySize = 255;
|
||||||
|
|
||||||
if (keyLengthStr != null) {
|
if (keyLengthStr != null) {
|
||||||
try {
|
try {
|
||||||
|
@ -106,6 +108,8 @@ public final class SecurityProviderConstants {
|
||||||
dhKeySize = value;
|
dhKeySize = value;
|
||||||
} else if (algoName.equals("EC")) {
|
} else if (algoName.equals("EC")) {
|
||||||
ecKeySize = value;
|
ecKeySize = value;
|
||||||
|
} else if (algoName.equalsIgnoreCase("EdDSA")) {
|
||||||
|
edKeySize = value;
|
||||||
} else {
|
} else {
|
||||||
if (debug != null) {
|
if (debug != null) {
|
||||||
debug.println("Ignoring unsupported algo in " +
|
debug.println("Ignoring unsupported algo in " +
|
||||||
|
@ -132,5 +136,6 @@ public final class SecurityProviderConstants {
|
||||||
DEF_RSASSA_PSS_KEY_SIZE = rsaSsaPssKeySize;
|
DEF_RSASSA_PSS_KEY_SIZE = rsaSsaPssKeySize;
|
||||||
DEF_DH_KEY_SIZE = dhKeySize;
|
DEF_DH_KEY_SIZE = dhKeySize;
|
||||||
DEF_EC_KEY_SIZE = ecKeySize;
|
DEF_EC_KEY_SIZE = ecKeySize;
|
||||||
|
DEF_ED_KEY_SIZE = edKeySize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -157,12 +157,34 @@ public abstract class IntegerPolynomial implements IntegerFieldModuloP {
|
||||||
public SmallValue getSmallValue(int value) {
|
public SmallValue getSmallValue(int value) {
|
||||||
int maxMag = 1 << (bitsPerLimb - 1);
|
int maxMag = 1 << (bitsPerLimb - 1);
|
||||||
if (Math.abs(value) >= maxMag) {
|
if (Math.abs(value) >= maxMag) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException("max magnitude is " + maxMag);
|
||||||
"max magnitude is " + maxMag);
|
|
||||||
}
|
}
|
||||||
return new Limb(value);
|
return new Limb(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected abstract void reduceIn(long[] c, long v, int i);
|
||||||
|
|
||||||
|
private void reduceHigh(long[] limbs) {
|
||||||
|
|
||||||
|
// conservatively calculate how many reduce operations can be done
|
||||||
|
// before a carry is needed
|
||||||
|
int extraBits = 63 - 2 * bitsPerLimb;
|
||||||
|
int allowedAdds = 1 << extraBits;
|
||||||
|
int carryPeriod = allowedAdds / numLimbs;
|
||||||
|
int reduceCount = 0;
|
||||||
|
for (int i = limbs.length - 1; i >= numLimbs; i--) {
|
||||||
|
reduceIn(limbs, limbs[i], i);
|
||||||
|
limbs[i] = 0;
|
||||||
|
|
||||||
|
reduceCount++;
|
||||||
|
if (reduceCount % carryPeriod == 0) {
|
||||||
|
carry(limbs, 0, i);
|
||||||
|
reduceIn(limbs, limbs[i], i);
|
||||||
|
limbs[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This version of encode takes a ByteBuffer that is properly ordered, and
|
* This version of encode takes a ByteBuffer that is properly ordered, and
|
||||||
* may extract larger values (e.g. long) from the ByteBuffer for better
|
* may extract larger values (e.g. long) from the ByteBuffer for better
|
||||||
|
@ -179,10 +201,12 @@ public abstract class IntegerPolynomial implements IntegerFieldModuloP {
|
||||||
if (requiredLimbs > numLimbs) {
|
if (requiredLimbs > numLimbs) {
|
||||||
long[] temp = new long[requiredLimbs];
|
long[] temp = new long[requiredLimbs];
|
||||||
encodeSmall(buf, length, highByte, temp);
|
encodeSmall(buf, length, highByte, temp);
|
||||||
// encode does a full carry/reduce
|
reduceHigh(temp);
|
||||||
System.arraycopy(temp, 0, result, 0, result.length);
|
System.arraycopy(temp, 0, result, 0, result.length);
|
||||||
|
reduce(result);
|
||||||
} else {
|
} else {
|
||||||
encodeSmall(buf, length, highByte, result);
|
encodeSmall(buf, length, highByte, result);
|
||||||
|
postEncodeCarry(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,8 +250,6 @@ public abstract class IntegerPolynomial implements IntegerFieldModuloP {
|
||||||
result[limbIndex++] = curLimbValue;
|
result[limbIndex++] = curLimbValue;
|
||||||
}
|
}
|
||||||
Arrays.fill(result, limbIndex, result.length, 0);
|
Arrays.fill(result, limbIndex, result.length, 0);
|
||||||
|
|
||||||
postEncodeCarry(result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void encode(byte[] v, int offset, int length, byte highByte,
|
protected void encode(byte[] v, int offset, int length, byte highByte,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -156,7 +156,8 @@ public class IntegerPolynomial1305 extends IntegerPolynomial {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void modReduceIn(long[] limbs, int index, long x) {
|
@Override
|
||||||
|
protected void reduceIn(long[] limbs, long x, int index) {
|
||||||
// this only works when BITS_PER_LIMB * NUM_LIMBS = POWER exactly
|
// this only works when BITS_PER_LIMB * NUM_LIMBS = POWER exactly
|
||||||
long reducedValue = (x * SUBTRAHEND);
|
long reducedValue = (x * SUBTRAHEND);
|
||||||
limbs[index - NUM_LIMBS] += reducedValue;
|
limbs[index - NUM_LIMBS] += reducedValue;
|
||||||
|
@ -166,13 +167,13 @@ public class IntegerPolynomial1305 extends IntegerPolynomial {
|
||||||
protected void finalCarryReduceLast(long[] limbs) {
|
protected void finalCarryReduceLast(long[] limbs) {
|
||||||
long carry = limbs[numLimbs - 1] >> bitsPerLimb;
|
long carry = limbs[numLimbs - 1] >> bitsPerLimb;
|
||||||
limbs[numLimbs - 1] -= carry << bitsPerLimb;
|
limbs[numLimbs - 1] -= carry << bitsPerLimb;
|
||||||
modReduceIn(limbs, numLimbs, carry);
|
reduceIn(limbs, carry, numLimbs);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final void modReduce(long[] limbs, int start, int end) {
|
protected final void modReduce(long[] limbs, int start, int end) {
|
||||||
|
|
||||||
for (int i = start; i < end; i++) {
|
for (int i = start; i < end; i++) {
|
||||||
modReduceIn(limbs, i, limbs[i]);
|
reduceIn(limbs, limbs[i], i);
|
||||||
limbs[i] = 0;
|
limbs[i] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -203,7 +204,7 @@ public class IntegerPolynomial1305 extends IntegerPolynomial {
|
||||||
long carry4 = carryValue(new4);
|
long carry4 = carryValue(new4);
|
||||||
limbs[4] = new4 - (carry4 << BITS_PER_LIMB);
|
limbs[4] = new4 - (carry4 << BITS_PER_LIMB);
|
||||||
|
|
||||||
modReduceIn(limbs, 5, carry4);
|
reduceIn(limbs, carry4, 5);
|
||||||
carry(limbs);
|
carry(limbs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -51,6 +51,13 @@ public class IntegerPolynomial25519 extends IntegerPolynomial {
|
||||||
super(BITS_PER_LIMB, NUM_LIMBS, 1, MODULUS);
|
super(BITS_PER_LIMB, NUM_LIMBS, 1, MODULUS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void reduceIn(long[] limbs, long v, int i) {
|
||||||
|
long t0 = 19 * v;
|
||||||
|
limbs[i - 10] += (t0 << 5) & LIMB_MASK;
|
||||||
|
limbs[i - 9] += t0 >> 21;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void finalCarryReduceLast(long[] limbs) {
|
protected void finalCarryReduceLast(long[] limbs) {
|
||||||
|
|
||||||
|
@ -81,17 +88,6 @@ public class IntegerPolynomial25519 extends IntegerPolynomial {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void mult(long[] a, long[] b, long[] r) {
|
protected void mult(long[] a, long[] b, long[] r) {
|
||||||
|
|
||||||
// Use grade-school multiplication into primitives to avoid the
|
|
||||||
// temporary array allocation. This is equivalent to the following
|
|
||||||
// code:
|
|
||||||
// long[] c = new long[2 * NUM_LIMBS - 1];
|
|
||||||
// for(int i = 0; i < NUM_LIMBS; i++) {
|
|
||||||
// for(int j - 0; j < NUM_LIMBS; j++) {
|
|
||||||
// c[i + j] += a[i] * b[j]
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
long c0 = (a[0] * b[0]);
|
long c0 = (a[0] * b[0]);
|
||||||
long c1 = (a[0] * b[1]) + (a[1] * b[0]);
|
long c1 = (a[0] * b[1]) + (a[1] * b[0]);
|
||||||
long c2 = (a[0] * b[2]) + (a[1] * b[1]) + (a[2] * b[0]);
|
long c2 = (a[0] * b[2]) + (a[1] * b[1]) + (a[2] * b[0]);
|
||||||
|
@ -172,7 +168,6 @@ public class IntegerPolynomial25519 extends IntegerPolynomial {
|
||||||
// carry(0,9)
|
// carry(0,9)
|
||||||
carry(r, 0, 9);
|
carry(r, 0, 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void square(long[] a, long[] r) {
|
protected void square(long[] a, long[] r) {
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -45,16 +45,17 @@ public class IntegerPolynomial448 extends IntegerPolynomial {
|
||||||
super(BITS_PER_LIMB, NUM_LIMBS, 1, MODULUS);
|
super(BITS_PER_LIMB, NUM_LIMBS, 1, MODULUS);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void modReduceIn(long[] limbs, int index, long x) {
|
@Override
|
||||||
limbs[index - NUM_LIMBS] += x;
|
protected void reduceIn(long[] limbs, long v, int i) {
|
||||||
limbs[index - NUM_LIMBS / 2] += x;
|
limbs[i - 8] += v;
|
||||||
|
limbs[i - 16] += v;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void finalCarryReduceLast(long[] limbs) {
|
protected void finalCarryReduceLast(long[] limbs) {
|
||||||
long carry = limbs[numLimbs - 1] >> bitsPerLimb;
|
long carry = limbs[numLimbs - 1] >> bitsPerLimb;
|
||||||
limbs[numLimbs - 1] -= carry << bitsPerLimb;
|
limbs[numLimbs - 1] -= carry << bitsPerLimb;
|
||||||
modReduceIn(limbs, numLimbs, carry);
|
reduceIn(limbs, carry, numLimbs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,228 @@
|
||||||
|
/*
|
||||||
|
* 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. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* 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 sun.security.util.math.intpoly;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The field of integers modulo a binomial prime. This is a general-purpose
|
||||||
|
* field implementation, that is much slower than more specialized classes
|
||||||
|
* like IntegerPolynomial25519. It is suitable when only a small number of
|
||||||
|
* arithmetic operations are required in some field. For example, this class
|
||||||
|
* can be used for operations on scalars/exponents in signature operations.
|
||||||
|
*
|
||||||
|
* This class may only be used for primes of the form 2^a + b.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class IntegerPolynomialModBinP extends IntegerPolynomial {
|
||||||
|
|
||||||
|
private final long[] reduceLimbs;
|
||||||
|
private final int bitOffset;
|
||||||
|
private final int limbMask;
|
||||||
|
private final int rightBitOffset;
|
||||||
|
private final int power;
|
||||||
|
|
||||||
|
public IntegerPolynomialModBinP(int bitsPerLimb,
|
||||||
|
int numLimbs,
|
||||||
|
int power,
|
||||||
|
BigInteger subtrahend) {
|
||||||
|
super(bitsPerLimb, numLimbs, 1,
|
||||||
|
BigInteger.valueOf(2).pow(power).subtract(subtrahend));
|
||||||
|
|
||||||
|
boolean negate = false;
|
||||||
|
if (subtrahend.compareTo(BigInteger.ZERO) < 0) {
|
||||||
|
negate = true;
|
||||||
|
subtrahend = subtrahend.negate();
|
||||||
|
}
|
||||||
|
int reduceLimbsLength = subtrahend.bitLength() / bitsPerLimb + 1;
|
||||||
|
reduceLimbs = new long[reduceLimbsLength];
|
||||||
|
ImmutableElement reduceElem = getElement(subtrahend);
|
||||||
|
if (negate) {
|
||||||
|
reduceElem = reduceElem.additiveInverse();
|
||||||
|
}
|
||||||
|
System.arraycopy(reduceElem.limbs, 0, reduceLimbs, 0,
|
||||||
|
reduceLimbs.length);
|
||||||
|
|
||||||
|
// begin test code
|
||||||
|
System.out.println("reduce limbs:");
|
||||||
|
for (int i = 0; i < reduceLimbs.length; i++) {
|
||||||
|
System.out.println(i + ":" + reduceLimbs[i]);
|
||||||
|
}
|
||||||
|
// end test code
|
||||||
|
|
||||||
|
this.power = power;
|
||||||
|
this.bitOffset = numLimbs * bitsPerLimb - power;
|
||||||
|
this.limbMask = -1 >>> (64 - bitsPerLimb);
|
||||||
|
this.rightBitOffset = bitsPerLimb - bitOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void finalCarryReduceLast(long[] limbs) {
|
||||||
|
|
||||||
|
int extraBits = bitsPerLimb * numLimbs - power;
|
||||||
|
int highBits = bitsPerLimb - extraBits;
|
||||||
|
long c = limbs[numLimbs - 1] >> highBits;
|
||||||
|
limbs[numLimbs - 1] -= c << highBits;
|
||||||
|
for (int j = 0; j < reduceLimbs.length; j++) {
|
||||||
|
int reduceBits = power + extraBits - j * bitsPerLimb;
|
||||||
|
modReduceInBits(limbs, numLimbs, reduceBits, c * reduceLimbs[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow more general (and slower) input conversion that takes a large
|
||||||
|
* value and reduces it.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ImmutableElement getElement(byte[] v, int offset, int length,
|
||||||
|
byte highByte) {
|
||||||
|
|
||||||
|
long[] result = new long[numLimbs];
|
||||||
|
int numHighBits = 32 - Integer.numberOfLeadingZeros(highByte);
|
||||||
|
int numBits = 8 * length + numHighBits;
|
||||||
|
int requiredLimbs = (numBits + bitsPerLimb - 1) / bitsPerLimb;
|
||||||
|
if (requiredLimbs > numLimbs) {
|
||||||
|
long[] temp = new long[requiredLimbs];
|
||||||
|
encode(v, offset, length, highByte, temp);
|
||||||
|
// encode does a full carry/reduce
|
||||||
|
System.arraycopy(temp, 0, result, 0, result.length);
|
||||||
|
} else {
|
||||||
|
encode(v, offset, length, highByte, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ImmutableElement(result, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multiply a and b, and store the result in c. Requires that
|
||||||
|
* a.length == b.length == numLimbs and c.length >= 2 * numLimbs - 1.
|
||||||
|
* It is allowed for a and b to be the same array.
|
||||||
|
*/
|
||||||
|
private void multOnly(long[] a, long[] b, long[] c) {
|
||||||
|
for (int i = 0; i < numLimbs; i++) {
|
||||||
|
for (int j = 0; j < numLimbs; j++) {
|
||||||
|
c[i + j] += a[i] * b[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void mult(long[] a, long[] b, long[] r) {
|
||||||
|
|
||||||
|
long[] c = new long[2 * numLimbs];
|
||||||
|
multOnly(a, b, c);
|
||||||
|
carryReduce(c, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void modReduceInBits(long[] limbs, int index, int bits, long x) {
|
||||||
|
|
||||||
|
if (bits % bitsPerLimb == 0) {
|
||||||
|
int pos = bits / bitsPerLimb;
|
||||||
|
limbs[index - pos] += x;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int secondPos = bits / (bitsPerLimb);
|
||||||
|
int bitOffset = (secondPos + 1) * bitsPerLimb - bits;
|
||||||
|
int rightBitOffset = bitsPerLimb - bitOffset;
|
||||||
|
limbs[index - (secondPos + 1)] += (x << bitOffset) & limbMask;
|
||||||
|
limbs[index - secondPos] += x >> rightBitOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void reduceIn(long[] c, long v, int i) {
|
||||||
|
|
||||||
|
for (int j = 0; j < reduceLimbs.length; j++) {
|
||||||
|
modReduceInBits(c, i, power - bitsPerLimb * j, reduceLimbs[j] * v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void carryReduce(long[] c, long[] r) {
|
||||||
|
|
||||||
|
// full carry to prevent overflow during reduce
|
||||||
|
carry(c);
|
||||||
|
// Reduce in from all high positions
|
||||||
|
for (int i = c.length - 1; i >= numLimbs; i--) {
|
||||||
|
reduceIn(c, c[i], i);
|
||||||
|
c[i] = 0;
|
||||||
|
}
|
||||||
|
// carry on lower positions that possibly carries out one position
|
||||||
|
carry(c, 0, numLimbs);
|
||||||
|
// reduce in a single position
|
||||||
|
reduceIn(c, c[numLimbs], numLimbs);
|
||||||
|
c[numLimbs] = 0;
|
||||||
|
// final carry
|
||||||
|
carry(c, 0, numLimbs - 1);
|
||||||
|
System.arraycopy(c, 0, r, 0, r.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void reduce(long[] a) {
|
||||||
|
// TODO: optimize this
|
||||||
|
long[] c = new long[a.length + 2];
|
||||||
|
System.arraycopy(a, 0, c, 0, a.length);
|
||||||
|
carryReduce(c, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void square(long[] a, long[] r) {
|
||||||
|
|
||||||
|
long[] c = new long[2 * numLimbs];
|
||||||
|
for (int i = 0; i < numLimbs; i++) {
|
||||||
|
c[2 * i] += a[i] * a[i];
|
||||||
|
for (int j = i + 1; j < numLimbs; j++) {
|
||||||
|
c[i + j] += 2 * a[i] * a[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
carryReduce(c, r);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The field of integers modulo the order of the Curve25519 subgroup
|
||||||
|
*/
|
||||||
|
public static class Curve25519OrderField extends IntegerPolynomialModBinP {
|
||||||
|
|
||||||
|
public Curve25519OrderField() {
|
||||||
|
super(26, 10, 252,
|
||||||
|
new BigInteger("-27742317777372353535851937790883648493"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The field of integers modulo the order of the Curve448 subgroup
|
||||||
|
*/
|
||||||
|
public static class Curve448OrderField extends IntegerPolynomialModBinP {
|
||||||
|
|
||||||
|
public Curve448OrderField() {
|
||||||
|
super(28, 16, 446,
|
||||||
|
new BigInteger("138180668098951153520073867485154268803366" +
|
||||||
|
"92474882178609894547503885"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,11 +28,13 @@ package sun.security.x509;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.security.interfaces.RSAKey;
|
import java.security.interfaces.RSAKey;
|
||||||
import java.security.spec.AlgorithmParameterSpec;
|
import java.security.spec.AlgorithmParameterSpec;
|
||||||
|
import java.security.spec.EdDSAParameterSpec;
|
||||||
import java.security.spec.InvalidParameterSpecException;
|
import java.security.spec.InvalidParameterSpecException;
|
||||||
import java.security.spec.MGF1ParameterSpec;
|
import java.security.spec.MGF1ParameterSpec;
|
||||||
import java.security.spec.PSSParameterSpec;
|
import java.security.spec.PSSParameterSpec;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.security.*;
|
import java.security.*;
|
||||||
|
import java.security.interfaces.*;
|
||||||
|
|
||||||
import sun.security.rsa.PSSParameters;
|
import sun.security.rsa.PSSParameters;
|
||||||
import sun.security.util.*;
|
import sun.security.util.*;
|
||||||
|
@ -199,7 +201,8 @@ public class AlgorithmId implements Serializable, DerEncoder {
|
||||||
} else {
|
} else {
|
||||||
bytes.putNull();
|
bytes.putNull();
|
||||||
}*/
|
}*/
|
||||||
if (algid.equals(RSASSA_PSS_oid)) {
|
if (algid.equals(RSASSA_PSS_oid) || algid.equals(ed448_oid)
|
||||||
|
|| algid.equals(ed25519_oid)) {
|
||||||
// RFC 4055 3.3: when an RSASSA-PSS key does not require
|
// RFC 4055 3.3: when an RSASSA-PSS key does not require
|
||||||
// parameter validation, field is absent.
|
// parameter validation, field is absent.
|
||||||
} else {
|
} else {
|
||||||
|
@ -588,6 +591,12 @@ public class AlgorithmId implements Serializable, DerEncoder {
|
||||||
if (name.equalsIgnoreCase("SHA512withECDSA")) {
|
if (name.equalsIgnoreCase("SHA512withECDSA")) {
|
||||||
return AlgorithmId.sha512WithECDSA_oid;
|
return AlgorithmId.sha512WithECDSA_oid;
|
||||||
}
|
}
|
||||||
|
if (name.equalsIgnoreCase("ED25519")) {
|
||||||
|
return AlgorithmId.ed25519_oid;
|
||||||
|
}
|
||||||
|
if (name.equalsIgnoreCase("ED448")) {
|
||||||
|
return AlgorithmId.ed448_oid;
|
||||||
|
}
|
||||||
|
|
||||||
return oidTable().get(name.toUpperCase(Locale.ENGLISH));
|
return oidTable().get(name.toUpperCase(Locale.ENGLISH));
|
||||||
}
|
}
|
||||||
|
@ -902,6 +911,11 @@ public class AlgorithmId implements Serializable, DerEncoder {
|
||||||
public static final ObjectIdentifier pbeWithSHA1AndRC2_40_oid =
|
public static final ObjectIdentifier pbeWithSHA1AndRC2_40_oid =
|
||||||
ObjectIdentifier.of("1.2.840.113549.1.12.1.6");
|
ObjectIdentifier.of("1.2.840.113549.1.12.1.6");
|
||||||
|
|
||||||
|
public static final ObjectIdentifier ed25519_oid =
|
||||||
|
ObjectIdentifier.of("1.3.101.112");
|
||||||
|
public static final ObjectIdentifier ed448_oid =
|
||||||
|
ObjectIdentifier.of("1.3.101.113");
|
||||||
|
|
||||||
static {
|
static {
|
||||||
nameTable = new HashMap<>();
|
nameTable = new HashMap<>();
|
||||||
nameTable.put(MD5_oid, "MD5");
|
nameTable.put(MD5_oid, "MD5");
|
||||||
|
@ -921,6 +935,8 @@ public class AlgorithmId implements Serializable, DerEncoder {
|
||||||
nameTable.put(DSA_OIW_oid, "DSA");
|
nameTable.put(DSA_OIW_oid, "DSA");
|
||||||
nameTable.put(EC_oid, "EC");
|
nameTable.put(EC_oid, "EC");
|
||||||
nameTable.put(ECDH_oid, "ECDH");
|
nameTable.put(ECDH_oid, "ECDH");
|
||||||
|
nameTable.put(ed25519_oid, "ED25519");
|
||||||
|
nameTable.put(ed448_oid, "ED448");
|
||||||
|
|
||||||
nameTable.put(AES_oid, "AES");
|
nameTable.put(AES_oid, "AES");
|
||||||
|
|
||||||
|
@ -1044,6 +1060,8 @@ public class AlgorithmId implements Serializable, DerEncoder {
|
||||||
+ "withRSA";
|
+ "withRSA";
|
||||||
case "RSASSA-PSS":
|
case "RSASSA-PSS":
|
||||||
return "RSASSA-PSS";
|
return "RSASSA-PSS";
|
||||||
|
case "EDDSA":
|
||||||
|
return edAlgFromKey(k);
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -1094,6 +1112,8 @@ public class AlgorithmId implements Serializable, DerEncoder {
|
||||||
return PSSParamsHolder.PSS_384_ID;
|
return PSSParamsHolder.PSS_384_ID;
|
||||||
} else if (spec == PSSParamsHolder.PSS_512_SPEC) {
|
} else if (spec == PSSParamsHolder.PSS_512_SPEC) {
|
||||||
return PSSParamsHolder.PSS_512_ID;
|
return PSSParamsHolder.PSS_512_ID;
|
||||||
|
} else if (spec instanceof EdDSAParameterSpec) {
|
||||||
|
return AlgorithmId.get(algName);
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
AlgorithmParameters result =
|
AlgorithmParameters result =
|
||||||
|
@ -1130,6 +1150,14 @@ public class AlgorithmId implements Serializable, DerEncoder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String edAlgFromKey(PrivateKey k) {
|
||||||
|
if (k instanceof EdECPrivateKey) {
|
||||||
|
EdECPrivateKey edKey = (EdECPrivateKey) k;
|
||||||
|
return edKey.getParams().getName();
|
||||||
|
}
|
||||||
|
return "EdDSA";
|
||||||
|
}
|
||||||
|
|
||||||
// Values from SP800-57 part 1 rev 4 tables 2 and 3
|
// Values from SP800-57 part 1 rev 4 tables 2 and 3
|
||||||
private static String ecStrength (int bitLength) {
|
private static String ecStrength (int bitLength) {
|
||||||
if (bitLength >= 512) { // 256 bits of strength
|
if (bitLength >= 512) { // 256 bits of strength
|
||||||
|
|
|
@ -0,0 +1,156 @@
|
||||||
|
/*
|
||||||
|
* 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. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* 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 sun.security.ec;
|
||||||
|
|
||||||
|
import sun.security.util.ObjectIdentifier;
|
||||||
|
import sun.security.x509.AlgorithmId;
|
||||||
|
|
||||||
|
import java.security.spec.AlgorithmParameterSpec;
|
||||||
|
import java.security.spec.NamedParameterSpec;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public class ParametersMap<T> {
|
||||||
|
|
||||||
|
private Map<Integer, T> sizeMap = new HashMap<Integer, T>();
|
||||||
|
private Map<ObjectIdentifier, T> oidMap =
|
||||||
|
new HashMap<ObjectIdentifier, T>();
|
||||||
|
private Map<String, T> nameMap = new HashMap<String, T>();
|
||||||
|
|
||||||
|
|
||||||
|
public void fix() {
|
||||||
|
|
||||||
|
sizeMap = Collections.unmodifiableMap(sizeMap);
|
||||||
|
oidMap = Collections.unmodifiableMap(oidMap);
|
||||||
|
nameMap = Collections.unmodifiableMap(nameMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void put(String name, ObjectIdentifier oid, int size, T params) {
|
||||||
|
nameMap.put(name.toLowerCase(), params);
|
||||||
|
oidMap.put(oid, params);
|
||||||
|
sizeMap.put(size, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<T> getByOid(ObjectIdentifier id) {
|
||||||
|
return Optional.ofNullable(oidMap.get(id));
|
||||||
|
}
|
||||||
|
public Optional<T> getBySize(int size) {
|
||||||
|
return Optional.ofNullable(sizeMap.get(size));
|
||||||
|
}
|
||||||
|
public Optional<T> getByName(String name) {
|
||||||
|
return Optional.ofNullable(nameMap.get(name.toLowerCase()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utility method that is used by the methods below to handle exception
|
||||||
|
// suppliers
|
||||||
|
private static
|
||||||
|
<A, B> Supplier<B> apply(final Function<A, B> func, final A a) {
|
||||||
|
return new Supplier<B>() {
|
||||||
|
@Override
|
||||||
|
public B get() {
|
||||||
|
return func.apply(a);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get parameters by key size, or throw an exception if no parameters are
|
||||||
|
* defined for the specified key size. This method is used in several
|
||||||
|
* contexts that should throw different exceptions when the parameters
|
||||||
|
* are not found. The first argument is a function that produces the
|
||||||
|
* desired exception.
|
||||||
|
*
|
||||||
|
* @param exception a function that produces an exception from a string
|
||||||
|
* @param size the desired key size
|
||||||
|
* @param <E> the type of exception that is thrown
|
||||||
|
* @return the parameters for the specified key size
|
||||||
|
* @throws T when suitable parameters do not exist
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
<E extends Throwable>
|
||||||
|
T getBySize(Function<String, E> exception,
|
||||||
|
int size) throws E {
|
||||||
|
|
||||||
|
Optional<T> paramsOpt = getBySize(size);
|
||||||
|
return paramsOpt.orElseThrow(
|
||||||
|
apply(exception, "Unsupported size: " + size));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get parameters by algorithm ID, or throw an exception if no
|
||||||
|
* parameters are defined for the specified ID. This method is used in
|
||||||
|
* several contexts that should throw different exceptions when the
|
||||||
|
* parameters are not found. The first argument is a function that produces
|
||||||
|
* the desired exception.
|
||||||
|
*
|
||||||
|
* @param exception a function that produces an exception from a string
|
||||||
|
* @param algId the algorithm ID
|
||||||
|
* @param <E> the type of exception that is thrown
|
||||||
|
* @return the parameters for the specified algorithm ID
|
||||||
|
* @throws E when suitable parameters do not exist
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
<E extends Throwable>
|
||||||
|
T get(Function<String, E> exception,
|
||||||
|
AlgorithmId algId) throws E {
|
||||||
|
|
||||||
|
Optional<T> paramsOpt = getByOid(algId.getOID());
|
||||||
|
return paramsOpt.orElseThrow(
|
||||||
|
apply(exception, "Unsupported OID: " + algId.getOID()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get parameters by algorithm parameter spec, or throw an exception if no
|
||||||
|
* parameters are defined for the spec. This method is used in
|
||||||
|
* several contexts that should throw different exceptions when the
|
||||||
|
* parameters are not found. The first argument is a function that produces
|
||||||
|
* the desired exception.
|
||||||
|
*
|
||||||
|
* @param exception a function that produces an exception from a string
|
||||||
|
* @param params the algorithm parameters spec
|
||||||
|
* @param <E> the type of exception that is thrown
|
||||||
|
* @return the parameters for the spec
|
||||||
|
* @throws E when suitable parameters do not exist
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
<E extends Throwable>
|
||||||
|
T get(Function<String, E> exception,
|
||||||
|
AlgorithmParameterSpec params) throws E {
|
||||||
|
|
||||||
|
if (params instanceof NamedParameterSpec) {
|
||||||
|
NamedParameterSpec namedParams = (NamedParameterSpec) params;
|
||||||
|
Optional<T> paramsOpt = getByName(namedParams.getName());
|
||||||
|
return paramsOpt.orElseThrow(
|
||||||
|
apply(exception, "Unsupported name: " + namedParams.getName()));
|
||||||
|
} else {
|
||||||
|
throw exception.apply("Only NamedParameterSpec is supported.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -37,6 +37,11 @@ import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import sun.security.ec.ed.EdDSAAlgorithmParameters;
|
||||||
|
import sun.security.ec.ed.EdDSAKeyFactory;
|
||||||
|
import sun.security.ec.ed.EdDSAKeyPairGenerator;
|
||||||
|
import sun.security.ec.ed.EdDSASignature;
|
||||||
import sun.security.util.CurveDB;
|
import sun.security.util.CurveDB;
|
||||||
import sun.security.util.NamedCurve;
|
import sun.security.util.NamedCurve;
|
||||||
|
|
||||||
|
@ -116,6 +121,15 @@ public final class SunEC extends Provider {
|
||||||
String algo = getAlgorithm();
|
String algo = getAlgorithm();
|
||||||
try {
|
try {
|
||||||
if (type.equals("Signature")) {
|
if (type.equals("Signature")) {
|
||||||
|
|
||||||
|
if (algo.equalsIgnoreCase("EdDSA")) {
|
||||||
|
return new EdDSASignature();
|
||||||
|
} else if (algo.equalsIgnoreCase("Ed25519")) {
|
||||||
|
return new EdDSASignature.Ed25519();
|
||||||
|
} else if (algo.equalsIgnoreCase("Ed448")) {
|
||||||
|
return new EdDSASignature.Ed448();
|
||||||
|
}
|
||||||
|
|
||||||
boolean inP1363 = algo.endsWith("inP1363Format");
|
boolean inP1363 = algo.endsWith("inP1363Format");
|
||||||
if (inP1363) {
|
if (inP1363) {
|
||||||
algo = algo.substring(0, algo.length() - 13);
|
algo = algo.substring(0, algo.length() - 13);
|
||||||
|
@ -148,6 +162,12 @@ public final class SunEC extends Provider {
|
||||||
return new XDHKeyFactory.X25519();
|
return new XDHKeyFactory.X25519();
|
||||||
} else if (algo.equals("X448")) {
|
} else if (algo.equals("X448")) {
|
||||||
return new XDHKeyFactory.X448();
|
return new XDHKeyFactory.X448();
|
||||||
|
} else if (algo.equalsIgnoreCase("EdDSA")) {
|
||||||
|
return new EdDSAKeyFactory();
|
||||||
|
} else if (algo.equalsIgnoreCase("Ed25519")) {
|
||||||
|
return new EdDSAKeyFactory.Ed25519();
|
||||||
|
} else if (algo.equalsIgnoreCase("Ed448")) {
|
||||||
|
return new EdDSAKeyFactory.Ed448();
|
||||||
}
|
}
|
||||||
} else if (type.equals("AlgorithmParameters")) {
|
} else if (type.equals("AlgorithmParameters")) {
|
||||||
if (algo.equals("EC")) {
|
if (algo.equals("EC")) {
|
||||||
|
@ -162,6 +182,12 @@ public final class SunEC extends Provider {
|
||||||
return new XDHKeyPairGenerator.X25519();
|
return new XDHKeyPairGenerator.X25519();
|
||||||
} else if (algo.equals("X448")) {
|
} else if (algo.equals("X448")) {
|
||||||
return new XDHKeyPairGenerator.X448();
|
return new XDHKeyPairGenerator.X448();
|
||||||
|
} else if (algo.equalsIgnoreCase("EdDSA")) {
|
||||||
|
return new EdDSAKeyPairGenerator();
|
||||||
|
} else if (algo.equalsIgnoreCase("Ed25519")) {
|
||||||
|
return new EdDSAKeyPairGenerator.Ed25519();
|
||||||
|
} else if (algo.equalsIgnoreCase("Ed448")) {
|
||||||
|
return new EdDSAKeyPairGenerator.Ed448();
|
||||||
}
|
}
|
||||||
} else if (type.equals("KeyAgreement")) {
|
} else if (type.equals("KeyAgreement")) {
|
||||||
if (algo.equals("ECDH")) {
|
if (algo.equals("ECDH")) {
|
||||||
|
@ -184,8 +210,7 @@ public final class SunEC extends Provider {
|
||||||
}
|
}
|
||||||
|
|
||||||
public SunEC() {
|
public SunEC() {
|
||||||
super("SunEC", PROVIDER_VER,
|
super("SunEC", PROVIDER_VER, "Sun Elliptic Curve provider");
|
||||||
"Sun Elliptic Curve provider (EC, ECDSA, ECDH)");
|
|
||||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||||
public Void run() {
|
public Void run() {
|
||||||
putEntries();
|
putEntries();
|
||||||
|
@ -255,6 +280,7 @@ public final class SunEC extends Provider {
|
||||||
apAttrs));
|
apAttrs));
|
||||||
|
|
||||||
putXDHEntries();
|
putXDHEntries();
|
||||||
|
putEdDSAEntries();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Signature engines
|
* Signature engines
|
||||||
|
@ -350,4 +376,39 @@ public final class SunEC extends Provider {
|
||||||
new String[]{"1.3.101.111", "OID.1.3.101.111"}, ATTRS));
|
new String[]{"1.3.101.111", "OID.1.3.101.111"}, ATTRS));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void putEdDSAEntries() {
|
||||||
|
|
||||||
|
HashMap<String, String> ATTRS = new HashMap<>(1);
|
||||||
|
ATTRS.put("ImplementedIn", "Software");
|
||||||
|
|
||||||
|
/* EdDSA does not require native implementation */
|
||||||
|
putService(new ProviderService(this, "KeyFactory",
|
||||||
|
"EdDSA", "sun.security.ec.ed.EdDSAKeyFactory", null, ATTRS));
|
||||||
|
putService(new ProviderService(this, "KeyFactory",
|
||||||
|
"Ed25519", "sun.security.ec.ed.EdDSAKeyFactory.Ed25519",
|
||||||
|
new String[]{"1.3.101.112", "OID.1.3.101.112"}, ATTRS));
|
||||||
|
putService(new ProviderService(this, "KeyFactory",
|
||||||
|
"Ed448", "sun.security.ec.ed.EdDSAKeyFactory.Ed448",
|
||||||
|
new String[]{"1.3.101.113", "OID.1.3.101.113"}, ATTRS));
|
||||||
|
|
||||||
|
putService(new ProviderService(this, "KeyPairGenerator",
|
||||||
|
"EdDSA", "sun.security.ec.ed.EdDSAKeyPairGenerator", null, ATTRS));
|
||||||
|
putService(new ProviderService(this, "KeyPairGenerator",
|
||||||
|
"Ed25519", "sun.security.ec.ed.EdDSAKeyPairGenerator.Ed25519",
|
||||||
|
new String[]{"1.3.101.112", "OID.1.3.101.112"}, ATTRS));
|
||||||
|
putService(new ProviderService(this, "KeyPairGenerator",
|
||||||
|
"Ed448", "sun.security.ec.ed.EdDSAKeyPairGenerator.Ed448",
|
||||||
|
new String[]{"1.3.101.113", "OID.1.3.101.113"}, ATTRS));
|
||||||
|
|
||||||
|
putService(new ProviderService(this, "Signature",
|
||||||
|
"EdDSA", "sun.security.ec.ed.EdDSASignature", null, ATTRS));
|
||||||
|
putService(new ProviderService(this, "Signature",
|
||||||
|
"Ed25519", "sun.security.ec.ed.EdDSASignature.Ed25519",
|
||||||
|
new String[]{"1.3.101.112", "OID.1.3.101.112"}, ATTRS));
|
||||||
|
putService(new ProviderService(this, "Signature",
|
||||||
|
"Ed448", "sun.security.ec.ed.EdDSASignature.Ed448",
|
||||||
|
new String[]{"1.3.101.113", "OID.1.3.101.113"}, ATTRS));
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,18 +29,17 @@ import java.io.IOException;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.security.spec.AlgorithmParameterSpec;
|
import java.security.spec.AlgorithmParameterSpec;
|
||||||
import java.security.spec.NamedParameterSpec;
|
import java.security.spec.NamedParameterSpec;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
import sun.security.util.ObjectIdentifier;
|
import sun.security.util.ObjectIdentifier;
|
||||||
import sun.security.x509.AlgorithmId;
|
import sun.security.x509.AlgorithmId;
|
||||||
|
|
||||||
public class XECParameters {
|
public class XECParameters {
|
||||||
|
|
||||||
|
static ParametersMap<XECParameters> namedParams = new ParametersMap<>();
|
||||||
|
|
||||||
// Naming/identification parameters
|
// Naming/identification parameters
|
||||||
private final ObjectIdentifier oid;
|
private final ObjectIdentifier oid;
|
||||||
private final String name;
|
private final String name;
|
||||||
|
@ -106,10 +105,6 @@ public class XECParameters {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Map<Integer, XECParameters> SIZE_MAP;
|
|
||||||
private static final Map<ObjectIdentifier, XECParameters> OID_MAP;
|
|
||||||
private static final Map<String, XECParameters> NAME_MAP;
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
final BigInteger TWO = BigInteger.valueOf(2);
|
final BigInteger TWO = BigInteger.valueOf(2);
|
||||||
|
|
||||||
|
@ -140,9 +135,7 @@ public class XECParameters {
|
||||||
// Unable to set X448 parameters---it will be disabled
|
// Unable to set X448 parameters---it will be disabled
|
||||||
}
|
}
|
||||||
|
|
||||||
SIZE_MAP = Collections.unmodifiableMap(bySize);
|
namedParams.fix();
|
||||||
OID_MAP = Collections.unmodifiableMap(byOid);
|
|
||||||
NAME_MAP = Collections.unmodifiableMap(byName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addParameters(int bits, BigInteger p, int a24,
|
private static void addParameters(int bits, BigInteger p, int a24,
|
||||||
|
@ -154,110 +147,36 @@ public class XECParameters {
|
||||||
ObjectIdentifier oid = new ObjectIdentifier(objectId);
|
ObjectIdentifier oid = new ObjectIdentifier(objectId);
|
||||||
XECParameters params =
|
XECParameters params =
|
||||||
new XECParameters(bits, p, a24, basePoint, logCofactor, oid, name);
|
new XECParameters(bits, p, a24, basePoint, logCofactor, oid, name);
|
||||||
bySize.put(bits, params);
|
namedParams.put(name.toLowerCase(), oid, bits, params);
|
||||||
byOid.put(oid, params);
|
|
||||||
byName.put(name.toLowerCase(), params);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Optional<XECParameters> getByOid(ObjectIdentifier id) {
|
|
||||||
return Optional.ofNullable(OID_MAP.get(id));
|
|
||||||
}
|
|
||||||
public static Optional<XECParameters> getBySize(int size) {
|
|
||||||
return Optional.ofNullable(SIZE_MAP.get(size));
|
|
||||||
}
|
|
||||||
public static Optional<XECParameters> getByName(String name) {
|
|
||||||
return Optional.ofNullable(NAME_MAP.get(name.toLowerCase()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean oidEquals(XECParameters other) {
|
boolean oidEquals(XECParameters other) {
|
||||||
return oid.equals(other.getOid());
|
return oid.equals(other.getOid());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Utility method that is used by the methods below to handle exception
|
|
||||||
// suppliers
|
|
||||||
private static
|
|
||||||
<A, B> Supplier<B> apply(final Function<A, B> func, final A a) {
|
|
||||||
return new Supplier<B>() {
|
|
||||||
@Override
|
|
||||||
public B get() {
|
|
||||||
return func.apply(a);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get parameters by key size, or throw an exception if no parameters are
|
|
||||||
* defined for the specified key size. This method is used in several
|
|
||||||
* contexts that should throw different exceptions when the parameters
|
|
||||||
* are not found. The first argument is a function that produces the
|
|
||||||
* desired exception.
|
|
||||||
*
|
|
||||||
* @param exception a function that produces an exception from a string
|
|
||||||
* @param size the desired key size
|
|
||||||
* @param <T> the type of exception that is thrown
|
|
||||||
* @return the parameters for the specified key size
|
|
||||||
* @throws T when suitable parameters do not exist
|
|
||||||
*/
|
|
||||||
public static
|
public static
|
||||||
<T extends Throwable>
|
<T extends Throwable>
|
||||||
XECParameters getBySize(Function<String, T> exception,
|
XECParameters getBySize(Function<String, T> exception,
|
||||||
int size) throws T {
|
int size) throws T {
|
||||||
|
|
||||||
Optional<XECParameters> xecParams = getBySize(size);
|
return namedParams.getBySize(exception, size);
|
||||||
return xecParams.orElseThrow(
|
|
||||||
apply(exception, "Unsupported size: " + size));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get parameters by algorithm ID, or throw an exception if no
|
|
||||||
* parameters are defined for the specified ID. This method is used in
|
|
||||||
* several contexts that should throw different exceptions when the
|
|
||||||
* parameters are not found. The first argument is a function that produces
|
|
||||||
* the desired exception.
|
|
||||||
*
|
|
||||||
* @param exception a function that produces an exception from a string
|
|
||||||
* @param algId the algorithm ID
|
|
||||||
* @param <T> the type of exception that is thrown
|
|
||||||
* @return the parameters for the specified algorithm ID
|
|
||||||
* @throws T when suitable parameters do not exist
|
|
||||||
*/
|
|
||||||
public static
|
public static
|
||||||
<T extends Throwable>
|
<T extends Throwable>
|
||||||
XECParameters get(Function<String, T> exception,
|
XECParameters get(Function<String, T> exception,
|
||||||
AlgorithmId algId) throws T {
|
AlgorithmId algId) throws T {
|
||||||
|
|
||||||
Optional<XECParameters> xecParams = getByOid(algId.getOID());
|
return namedParams.get(exception, algId);
|
||||||
return xecParams.orElseThrow(
|
|
||||||
apply(exception, "Unsupported OID: " + algId.getOID()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get parameters by algorithm parameter spec, or throw an exception if no
|
|
||||||
* parameters are defined for the spec. This method is used in
|
|
||||||
* several contexts that should throw different exceptions when the
|
|
||||||
* parameters are not found. The first argument is a function that produces
|
|
||||||
* the desired exception.
|
|
||||||
*
|
|
||||||
* @param exception a function that produces an exception from a string
|
|
||||||
* @param params the algorithm parameters spec
|
|
||||||
* @param <T> the type of exception that is thrown
|
|
||||||
* @return the parameters for the spec
|
|
||||||
* @throws T when suitable parameters do not exist
|
|
||||||
*/
|
|
||||||
public static
|
public static
|
||||||
<T extends Throwable>
|
<T extends Throwable>
|
||||||
XECParameters get(Function<String, T> exception,
|
XECParameters get(Function<String, T> exception,
|
||||||
AlgorithmParameterSpec params) throws T {
|
AlgorithmParameterSpec params) throws T {
|
||||||
|
|
||||||
if (params instanceof NamedParameterSpec) {
|
return namedParams.get(exception, params);
|
||||||
NamedParameterSpec namedParams = (NamedParameterSpec) params;
|
|
||||||
Optional<XECParameters> xecParams =
|
|
||||||
getByName(namedParams.getName());
|
|
||||||
return xecParams.orElseThrow(
|
|
||||||
apply(exception, "Unsupported name: " + namedParams.getName()));
|
|
||||||
} else {
|
|
||||||
throw exception.apply("Only NamedParameterSpec is supported.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,214 @@
|
||||||
|
/*
|
||||||
|
* 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. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* 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 sun.security.ec.ed;
|
||||||
|
|
||||||
|
import sun.security.ec.point.*;
|
||||||
|
import sun.security.util.math.*;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Elliptic curve point arithmetic, decoding, and other operations for the
|
||||||
|
* family of curves including edwards25519 and its related group. Though the
|
||||||
|
* operations in this class are optimized for edwards25519, they are correct
|
||||||
|
* for any twisted Edwards curve ax^2 + y^2 = 1 + dx^2y^2 (mod p) with the
|
||||||
|
* following properties:
|
||||||
|
* 1) a = -1 (mod p)
|
||||||
|
* 2) a is square (mod p)
|
||||||
|
* 3) d is not square (mod p)
|
||||||
|
*/
|
||||||
|
public class Ed25519Operations extends EdECOperations {
|
||||||
|
|
||||||
|
private final SmallValue two;
|
||||||
|
private final ImmutableIntegerModuloP d;
|
||||||
|
private final ExtendedHomogeneousPoint.Immutable basePoint;
|
||||||
|
|
||||||
|
private static final BigInteger TWO = BigInteger.valueOf(2);
|
||||||
|
private static final BigInteger SEVEN = BigInteger.valueOf(7);
|
||||||
|
private final BigInteger sizeMinus5;
|
||||||
|
|
||||||
|
public Ed25519Operations(ImmutableIntegerModuloP d, BigInteger baseX,
|
||||||
|
BigInteger baseY) {
|
||||||
|
|
||||||
|
this.two = d.getField().getSmallValue(2);
|
||||||
|
this.d = d;
|
||||||
|
this.basePoint = of(new AffinePoint(
|
||||||
|
d.getField().getElement(baseX), d.getField().getElement(baseY)
|
||||||
|
));
|
||||||
|
this.sizeMinus5 =
|
||||||
|
d.getField().getSize().subtract(BigInteger.valueOf(5));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Point basePointMultiply(byte[] scalar) {
|
||||||
|
return setProduct(basePoint.mutable(), scalar);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ExtendedHomogeneousPoint.Immutable getNeutral() {
|
||||||
|
IntegerFieldModuloP field = d.getField();
|
||||||
|
return new ExtendedHomogeneousPoint.Immutable(field.get0(),
|
||||||
|
field.get1(), field.get0(), field.get1());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected MutablePoint setSum(MutablePoint p1, MutablePoint p2,
|
||||||
|
MutableIntegerModuloP t1,
|
||||||
|
MutableIntegerModuloP t2,
|
||||||
|
MutableIntegerModuloP t3) {
|
||||||
|
|
||||||
|
ExtendedHomogeneousPoint.Mutable ehp1 =
|
||||||
|
(ExtendedHomogeneousPoint.Mutable) p1;
|
||||||
|
ExtendedHomogeneousPoint.Mutable ehp2 =
|
||||||
|
(ExtendedHomogeneousPoint.Mutable) p2;
|
||||||
|
return setSum(ehp1, ehp2, t1, t2, t3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected MutablePoint setDouble(MutablePoint p, MutableIntegerModuloP t1,
|
||||||
|
MutableIntegerModuloP t2) {
|
||||||
|
|
||||||
|
ExtendedHomogeneousPoint.Mutable ehp =
|
||||||
|
(ExtendedHomogeneousPoint.Mutable) p;
|
||||||
|
return setDouble(ehp, t1, t2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ExtendedHomogeneousPoint.Immutable of(AffinePoint p) {
|
||||||
|
return new ExtendedHomogeneousPoint.Immutable(p.getX(), p.getY(),
|
||||||
|
p.getX().multiply(p.getY()), p.getX().getField().get1());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends Throwable>
|
||||||
|
AffinePoint decodeAffinePoint(Function<String, T> exception,
|
||||||
|
int xLSB, IntegerModuloP y) throws T {
|
||||||
|
|
||||||
|
IntegerFieldModuloP field = d.getField();
|
||||||
|
BigInteger p = field.getSize();
|
||||||
|
ImmutableIntegerModuloP y2 = y.square();
|
||||||
|
ImmutableIntegerModuloP u = y2.subtract(field.get1());
|
||||||
|
MutableIntegerModuloP v = d.mutable().setProduct(y2)
|
||||||
|
.setSum(field.get1());
|
||||||
|
|
||||||
|
MutableIntegerModuloP x =
|
||||||
|
u.mutable().setProduct(v.pow(BigInteger.valueOf(3)));
|
||||||
|
ImmutableIntegerModuloP uv7pow =
|
||||||
|
u.multiply(v.pow(SEVEN)).pow(sizeMinus5.shiftRight(3));
|
||||||
|
x.setProduct(uv7pow);
|
||||||
|
|
||||||
|
v.setProduct(x).setProduct(x);
|
||||||
|
// v now holds vx^2
|
||||||
|
BigInteger bigVX2 = v.asBigInteger();
|
||||||
|
if (bigVX2.equals(u.asBigInteger())) {
|
||||||
|
// do nothing---x is correct
|
||||||
|
} else if (bigVX2.equals(u.additiveInverse().asBigInteger())) {
|
||||||
|
BigInteger exp = p.subtract(BigInteger.ONE).shiftRight(2);
|
||||||
|
IntegerModuloP twoPow = field.getElement(TWO.modPow(exp, p));
|
||||||
|
x.setProduct(twoPow);
|
||||||
|
} else {
|
||||||
|
throw exception.apply("Invalid point");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x.asBigInteger().equals(BigInteger.ZERO) && xLSB == 1) {
|
||||||
|
throw exception.apply("Invalid point");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xLSB != x.asBigInteger().mod(BigInteger.valueOf(2)).intValue()) {
|
||||||
|
x.setAdditiveInverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new AffinePoint(x.fixed(), y.fixed());
|
||||||
|
}
|
||||||
|
|
||||||
|
ExtendedHomogeneousPoint.Mutable setSum(
|
||||||
|
ExtendedHomogeneousPoint.Mutable p1,
|
||||||
|
ExtendedHomogeneousPoint.Mutable p2,
|
||||||
|
MutableIntegerModuloP t1,
|
||||||
|
MutableIntegerModuloP t2,
|
||||||
|
MutableIntegerModuloP t3) {
|
||||||
|
|
||||||
|
t1.setValue(p2.getY()).setDifference(p2.getX());
|
||||||
|
// t1 holds y2 - x2
|
||||||
|
t2.setValue(p1.getY()).setDifference(p1.getX()).setProduct(t1);
|
||||||
|
// t2 holds A = (y1 - x1) * (y2 - x2)
|
||||||
|
t1.setValue(p2.getY()).setSum(p2.getX());
|
||||||
|
// t1 holds y2 + x2
|
||||||
|
t3.setValue(p1.getY()).setSum(p1.getX()).setProduct(t1);
|
||||||
|
// t3 holds B = (y1 + x1) * (y2 + x2)
|
||||||
|
p1.getX().setValue(t3).setDifference(t2);
|
||||||
|
// x holds E = B - A
|
||||||
|
t3.setSum(t2);
|
||||||
|
// t3 holds H = B + A, t2 is unused
|
||||||
|
t2.setValue(d).setSum(d).setProduct(p1.getT()).setProduct(p2.getT());
|
||||||
|
// t2 holds C
|
||||||
|
t1.setValue(p1.getZ()).setProduct(p2.getZ()).setProduct(two);
|
||||||
|
// t1 holds D
|
||||||
|
p1.getY().setValue(t1).setSum(t2);
|
||||||
|
// y holds G
|
||||||
|
p1.getZ().setValue(t1).setDifference(t2);
|
||||||
|
// z holds F
|
||||||
|
|
||||||
|
p1.getT().setValue(p1.getX()).setProduct(t3);
|
||||||
|
p1.getX().setProduct(p1.getZ());
|
||||||
|
p1.getZ().setProduct(p1.getY());
|
||||||
|
p1.getY().setProduct(t3);
|
||||||
|
|
||||||
|
return p1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ExtendedHomogeneousPoint.Mutable setDouble(
|
||||||
|
ExtendedHomogeneousPoint.Mutable p,
|
||||||
|
MutableIntegerModuloP t1, MutableIntegerModuloP t2) {
|
||||||
|
|
||||||
|
t1.setValue(p.getX()).setSum(p.getY()).setSquare();
|
||||||
|
// t1 holds (x + y)^2
|
||||||
|
p.getX().setSquare();
|
||||||
|
// x = A = x^2
|
||||||
|
p.getY().setSquare();
|
||||||
|
// y = B = y^2
|
||||||
|
t2.setValue(p.getX()).setSum(p.getY()).setReduced();
|
||||||
|
// t2 holds H
|
||||||
|
p.getZ().setSquare().setProduct(two);
|
||||||
|
// z holds C
|
||||||
|
|
||||||
|
p.getT().setValue(t2).setDifference(t1);
|
||||||
|
// t holds E
|
||||||
|
t1.setValue(p.getX()).setDifference(p.getY()).setReduced();
|
||||||
|
// t1 holds G
|
||||||
|
|
||||||
|
p.getZ().setSum(t1);
|
||||||
|
// z holds F
|
||||||
|
|
||||||
|
p.getX().setValue(p.getT()).setProduct(p.getZ());
|
||||||
|
p.getY().setValue(t1).setProduct(t2);
|
||||||
|
p.getT().setProduct(t2);
|
||||||
|
p.getZ().setProduct(t1);
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,201 @@
|
||||||
|
/*
|
||||||
|
* 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. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* 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 sun.security.ec.ed;
|
||||||
|
|
||||||
|
import sun.security.ec.point.*;
|
||||||
|
import sun.security.util.math.*;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
// Arithmetic works for a=1 and non-square d
|
||||||
|
/*
|
||||||
|
* Elliptic curve point arithmetic, decoding, and other operations for the
|
||||||
|
* family of curves including edwards448 and its related group. Though the
|
||||||
|
* operations in this class are optimized for edwards448, they are correct
|
||||||
|
* for any untwisted Edwards curve x^2 + y^2 = 1 + dx^2y^2 (mod p) where
|
||||||
|
* d is not square (mod p).
|
||||||
|
*/
|
||||||
|
public class Ed448Operations extends EdECOperations {
|
||||||
|
|
||||||
|
private final SmallValue two;
|
||||||
|
private final ImmutableIntegerModuloP d;
|
||||||
|
private final ProjectivePoint.Immutable basePoint;
|
||||||
|
|
||||||
|
private static final BigInteger TWO = BigInteger.valueOf(2);
|
||||||
|
private static final BigInteger THREE = BigInteger.valueOf(3);
|
||||||
|
private static final BigInteger FIVE = BigInteger.valueOf(5);
|
||||||
|
private final BigInteger sizeMinus3;
|
||||||
|
|
||||||
|
public Ed448Operations(ImmutableIntegerModuloP d, BigInteger baseX,
|
||||||
|
BigInteger baseY) {
|
||||||
|
|
||||||
|
this.two = d.getField().getSmallValue(2);
|
||||||
|
this.d = d;
|
||||||
|
this.basePoint = of(new AffinePoint(
|
||||||
|
d.getField().getElement(baseX),
|
||||||
|
d.getField().getElement(baseY)
|
||||||
|
));
|
||||||
|
|
||||||
|
this.sizeMinus3 = d.getField().getSize().subtract(THREE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Point basePointMultiply(byte[] scalar) {
|
||||||
|
return setProduct(basePoint.mutable(), scalar);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ProjectivePoint.Immutable getNeutral() {
|
||||||
|
IntegerFieldModuloP field = d.getField();
|
||||||
|
return new ProjectivePoint.Immutable(field.get0(), field.get1(),
|
||||||
|
field.get1());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected MutablePoint setSum(MutablePoint p1, MutablePoint p2,
|
||||||
|
MutableIntegerModuloP t1,
|
||||||
|
MutableIntegerModuloP t2,
|
||||||
|
MutableIntegerModuloP t3) {
|
||||||
|
|
||||||
|
ProjectivePoint.Mutable ehp1 = (ProjectivePoint.Mutable) p1;
|
||||||
|
ProjectivePoint.Mutable ehp2 = (ProjectivePoint.Mutable) p2;
|
||||||
|
return setSum(ehp1, ehp2, t1, t2, t3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected MutablePoint setDouble(MutablePoint p, MutableIntegerModuloP t1,
|
||||||
|
MutableIntegerModuloP t2) {
|
||||||
|
|
||||||
|
ProjectivePoint.Mutable ehp = (ProjectivePoint.Mutable) p;
|
||||||
|
return setDouble(ehp, t1, t2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ProjectivePoint.Immutable of(AffinePoint p) {
|
||||||
|
return new ProjectivePoint.Immutable(p.getX(), p.getY(),
|
||||||
|
p.getX().getField().get1());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends Throwable>
|
||||||
|
AffinePoint decodeAffinePoint(Function<String, T> exception, int xLSB,
|
||||||
|
IntegerModuloP y) throws T {
|
||||||
|
|
||||||
|
ImmutableIntegerModuloP y2 = y.square();
|
||||||
|
ImmutableIntegerModuloP u = y2.subtract(d.getField().get1());
|
||||||
|
MutableIntegerModuloP v = d.mutable().setProduct(y2)
|
||||||
|
.setDifference(d.getField().get1());
|
||||||
|
|
||||||
|
IntegerModuloP u5v3pow = u.pow(FIVE).multiply(v.pow(THREE))
|
||||||
|
.pow(sizeMinus3.shiftRight(2));
|
||||||
|
|
||||||
|
MutableIntegerModuloP x = v.mutable().setProduct(u.pow(THREE))
|
||||||
|
.setProduct(u5v3pow);
|
||||||
|
|
||||||
|
v.setProduct(x).setProduct(x);
|
||||||
|
// v now holds vx^2
|
||||||
|
if (v.asBigInteger().equals(u.asBigInteger())) {
|
||||||
|
// x is correct
|
||||||
|
} else {
|
||||||
|
throw exception.apply("Invalid point");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x.asBigInteger().equals(BigInteger.ZERO) && xLSB == 1) {
|
||||||
|
throw exception.apply("Invalid point");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xLSB != x.asBigInteger().mod(TWO).intValue()) {
|
||||||
|
x.setAdditiveInverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new AffinePoint(x.fixed(), y.fixed());
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectivePoint.Mutable setSum(
|
||||||
|
ProjectivePoint.Mutable p1,
|
||||||
|
ProjectivePoint.Mutable p2,
|
||||||
|
MutableIntegerModuloP t1,
|
||||||
|
MutableIntegerModuloP t2,
|
||||||
|
MutableIntegerModuloP t3) {
|
||||||
|
|
||||||
|
t1.setValue(p1.getX()).setProduct(p2.getX());
|
||||||
|
// t1 holds C
|
||||||
|
t2.setValue(p2.getX()).setSum(p2.getY());
|
||||||
|
p1.getX().setSum(p1.getY()).setProduct(t2);
|
||||||
|
// x holds H
|
||||||
|
p1.getZ().setProduct(p2.getZ());
|
||||||
|
// z holds A
|
||||||
|
p1.getY().setProduct(p2.getY());
|
||||||
|
// y holds D
|
||||||
|
|
||||||
|
t3.setValue(d).setProduct(t1).setProduct(p1.getY());
|
||||||
|
// t3 holds E
|
||||||
|
// do part of the final calculation of x and y to free up t1
|
||||||
|
p1.getX().setDifference(t1).setReduced().setDifference(p1.getY());
|
||||||
|
p1.getY().setDifference(t1);
|
||||||
|
t1.setValue(p1.getZ()).setSquare();
|
||||||
|
// t2 holds B
|
||||||
|
|
||||||
|
t2.setValue(t1).setDifference(t3);
|
||||||
|
// t2 holds F
|
||||||
|
t1.setSum(t3);
|
||||||
|
// t1 holds G
|
||||||
|
|
||||||
|
p1.getX().setProduct(t2).setProduct(p1.getZ());
|
||||||
|
p1.getY().setProduct(t1).setProduct(p1.getZ());
|
||||||
|
p1.getZ().setValue(t2.multiply(t1));
|
||||||
|
|
||||||
|
return p1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ProjectivePoint.Mutable setDouble(ProjectivePoint.Mutable p,
|
||||||
|
MutableIntegerModuloP t1,
|
||||||
|
MutableIntegerModuloP t2) {
|
||||||
|
|
||||||
|
t2.setValue(p.getX()).setSquare();
|
||||||
|
// t2 holds C
|
||||||
|
p.getX().setSum(p.getY()).setSquare();
|
||||||
|
// x holds B
|
||||||
|
p.getY().setSquare();
|
||||||
|
// y holds D
|
||||||
|
p.getZ().setSquare();
|
||||||
|
// z holds H
|
||||||
|
|
||||||
|
t1.setValue(t2).setSum(p.getY()).setReduced();
|
||||||
|
// t1 holds E
|
||||||
|
t2.setDifference(p.getY());
|
||||||
|
p.getY().setValue(t1).setProduct(t2);
|
||||||
|
|
||||||
|
p.getZ().setProduct(two);
|
||||||
|
p.getZ().setAdditiveInverse().setSum(t1);
|
||||||
|
// z holds J
|
||||||
|
p.getX().setDifference(t1).setProduct(p.getZ());
|
||||||
|
p.getZ().setProduct(t1);
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
* 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. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* 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 sun.security.ec.ed;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.AlgorithmParametersSpi;
|
||||||
|
import java.security.spec.AlgorithmParameterSpec;
|
||||||
|
import java.security.spec.ECParameterSpec;
|
||||||
|
import java.security.spec.EdDSAParameterSpec;
|
||||||
|
import java.security.spec.InvalidParameterSpecException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This AlgorithmParametersSpi only supports NamedParameterSpec.
|
||||||
|
* EdDSAParameterSpec is not support because there is not ASN.1 format
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class EdDSAAlgorithmParameters extends AlgorithmParametersSpi {
|
||||||
|
|
||||||
|
EdDSAParameterSpec edspec;
|
||||||
|
|
||||||
|
// If no curve is provide, wait engineInit() to provide one.
|
||||||
|
public EdDSAAlgorithmParameters() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NamedParameterSpec can only be used if curve was not specified
|
||||||
|
* as part of getInstance(EdDSA). If the curve was used, engineInit will
|
||||||
|
* throws an exception for being already initialized.
|
||||||
|
* EdDSAParameterSpec is not support because there is not ASN.1 format
|
||||||
|
*
|
||||||
|
* @param paramSpec NamedParameterSpec curve.
|
||||||
|
*
|
||||||
|
* @throws InvalidParameterSpecException
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void engineInit(AlgorithmParameterSpec paramSpec)
|
||||||
|
throws InvalidParameterSpecException {
|
||||||
|
if (paramSpec instanceof EdDSAParameterSpec) {
|
||||||
|
edspec = (EdDSAParameterSpec)paramSpec;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new InvalidParameterSpecException(
|
||||||
|
"Unknown AlgorithmParameterSpec");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void engineInit(byte[] params) throws IOException {
|
||||||
|
throw new IOException(
|
||||||
|
"EdDSA does not support parameters as a byte array.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void engineInit(byte[] params, String format) throws IOException {
|
||||||
|
engineInit(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected <T extends AlgorithmParameterSpec> T engineGetParameterSpec(
|
||||||
|
Class<T> paramSpec) throws InvalidParameterSpecException {
|
||||||
|
|
||||||
|
if (paramSpec.isAssignableFrom(ECParameterSpec.class)) {
|
||||||
|
return paramSpec.cast(edspec);
|
||||||
|
}
|
||||||
|
throw new InvalidParameterSpecException(
|
||||||
|
"Only EDDSAParameterSpec supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte[] engineGetEncoded() throws IOException {
|
||||||
|
throw new IOException(
|
||||||
|
"EdDSA does not support parameters as a byte array.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte[] engineGetEncoded(String format) throws IOException {
|
||||||
|
throw new IOException(
|
||||||
|
"EdDSA does not support parameters as a byte array.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String engineToString() {
|
||||||
|
return edspec.toString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,236 @@
|
||||||
|
/*
|
||||||
|
* 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. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* 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 sun.security.ec.ed;
|
||||||
|
|
||||||
|
import java.security.KeyFactorySpi;
|
||||||
|
import java.security.Key;
|
||||||
|
import java.security.PublicKey;
|
||||||
|
import java.security.PrivateKey;
|
||||||
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.ProviderException;
|
||||||
|
import java.security.interfaces.*;
|
||||||
|
import java.security.spec.*;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class EdDSAKeyFactory extends KeyFactorySpi {
|
||||||
|
|
||||||
|
private EdDSAParameters lockedParams = null;
|
||||||
|
|
||||||
|
public EdDSAKeyFactory() {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
protected EdDSAKeyFactory(NamedParameterSpec paramSpec) {
|
||||||
|
lockedParams = EdDSAParameters.get(ProviderException::new, paramSpec);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Key engineTranslateKey(Key key) throws InvalidKeyException {
|
||||||
|
|
||||||
|
if (key == null) {
|
||||||
|
throw new InvalidKeyException("Key must not be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key instanceof EdECKey) {
|
||||||
|
EdECKey edKey = (EdECKey) key;
|
||||||
|
EdDSAParameters params = EdDSAParameters.get(
|
||||||
|
InvalidKeyException::new, edKey.getParams());
|
||||||
|
checkLockedParams(InvalidKeyException::new, params);
|
||||||
|
|
||||||
|
if (edKey instanceof EdECPublicKey) {
|
||||||
|
EdECPublicKey publicKey = (EdECPublicKey) edKey;
|
||||||
|
return new EdDSAPublicKeyImpl(params, publicKey.getPoint());
|
||||||
|
} else if (edKey instanceof EdECPrivateKey) {
|
||||||
|
EdECPrivateKey privateKey = (EdECPrivateKey) edKey;
|
||||||
|
byte[] privateKeyBytes = privateKey.getBytes().orElseThrow(
|
||||||
|
() -> new InvalidKeyException("No private key data"));
|
||||||
|
return new EdDSAPrivateKeyImpl(params, privateKeyBytes);
|
||||||
|
} else {
|
||||||
|
throw new InvalidKeyException("Unsupported EdECKey subclass");
|
||||||
|
}
|
||||||
|
} else if (key instanceof PublicKey &&
|
||||||
|
key.getFormat().equals("X.509")) {
|
||||||
|
EdDSAPublicKeyImpl result =
|
||||||
|
new EdDSAPublicKeyImpl(key.getEncoded());
|
||||||
|
checkLockedParams(InvalidKeyException::new, result.getParams());
|
||||||
|
return result;
|
||||||
|
} else if (key instanceof PrivateKey &&
|
||||||
|
key.getFormat().equals("PKCS#8")) {
|
||||||
|
EdDSAPrivateKeyImpl result =
|
||||||
|
new EdDSAPrivateKeyImpl(key.getEncoded());
|
||||||
|
checkLockedParams(InvalidKeyException::new, result.getParams());
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
throw new InvalidKeyException("Unsupported key type or format");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private
|
||||||
|
<T extends Throwable>
|
||||||
|
void checkLockedParams(Function<String, T> exception,
|
||||||
|
NamedParameterSpec spec) throws T {
|
||||||
|
|
||||||
|
EdDSAParameters params = EdDSAParameters.get(exception, spec);
|
||||||
|
checkLockedParams(exception, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
private
|
||||||
|
<T extends Throwable>
|
||||||
|
void checkLockedParams(Function<String, T> exception,
|
||||||
|
EdDSAParameters params) throws T {
|
||||||
|
|
||||||
|
if (lockedParams != null && lockedParams != params) {
|
||||||
|
throw exception.apply("Parameters must be " +
|
||||||
|
lockedParams.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PublicKey engineGeneratePublic(KeySpec keySpec)
|
||||||
|
throws InvalidKeySpecException {
|
||||||
|
|
||||||
|
try {
|
||||||
|
return generatePublicImpl(keySpec);
|
||||||
|
} catch (InvalidKeyException ex) {
|
||||||
|
throw new InvalidKeySpecException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
|
||||||
|
throws InvalidKeySpecException {
|
||||||
|
|
||||||
|
try {
|
||||||
|
return generatePrivateImpl(keySpec);
|
||||||
|
} catch (InvalidKeyException ex) {
|
||||||
|
throw new InvalidKeySpecException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private PublicKey generatePublicImpl(KeySpec keySpec)
|
||||||
|
throws InvalidKeyException, InvalidKeySpecException {
|
||||||
|
|
||||||
|
if (keySpec instanceof X509EncodedKeySpec) {
|
||||||
|
X509EncodedKeySpec x509Spec = (X509EncodedKeySpec) keySpec;
|
||||||
|
EdDSAPublicKeyImpl result =
|
||||||
|
new EdDSAPublicKeyImpl(x509Spec.getEncoded());
|
||||||
|
checkLockedParams(InvalidKeySpecException::new,
|
||||||
|
result.getParams());
|
||||||
|
return result;
|
||||||
|
} else if (keySpec instanceof EdECPublicKeySpec) {
|
||||||
|
EdECPublicKeySpec publicKeySpec = (EdECPublicKeySpec) keySpec;
|
||||||
|
EdDSAParameters params = EdDSAParameters.get(
|
||||||
|
InvalidKeySpecException::new, publicKeySpec.getParams());
|
||||||
|
checkLockedParams(InvalidKeySpecException::new, params);
|
||||||
|
return new EdDSAPublicKeyImpl(params, publicKeySpec.getPoint());
|
||||||
|
} else {
|
||||||
|
throw new InvalidKeySpecException(
|
||||||
|
"Only X509EncodedKeySpec and EdECPublicKeySpec are supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private PrivateKey generatePrivateImpl(KeySpec keySpec)
|
||||||
|
throws InvalidKeyException, InvalidKeySpecException {
|
||||||
|
|
||||||
|
if (keySpec instanceof PKCS8EncodedKeySpec) {
|
||||||
|
PKCS8EncodedKeySpec pkcsSpec = (PKCS8EncodedKeySpec) keySpec;
|
||||||
|
EdDSAPrivateKeyImpl result =
|
||||||
|
new EdDSAPrivateKeyImpl(pkcsSpec.getEncoded());
|
||||||
|
checkLockedParams(InvalidKeySpecException::new,
|
||||||
|
result.getParams());
|
||||||
|
return result;
|
||||||
|
} else if (keySpec instanceof EdECPrivateKeySpec) {
|
||||||
|
EdECPrivateKeySpec privateKeySpec = (EdECPrivateKeySpec) keySpec;
|
||||||
|
EdDSAParameters params = EdDSAParameters.get(
|
||||||
|
InvalidKeySpecException::new, privateKeySpec.getParams());
|
||||||
|
checkLockedParams(InvalidKeySpecException::new, params);
|
||||||
|
return new EdDSAPrivateKeyImpl(params, privateKeySpec.getBytes());
|
||||||
|
} else {
|
||||||
|
throw new InvalidKeySpecException(
|
||||||
|
"Only PKCS8EncodedKeySpec and EdECPrivateKeySpec supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec)
|
||||||
|
throws InvalidKeySpecException {
|
||||||
|
|
||||||
|
if (key instanceof EdECPublicKey) {
|
||||||
|
checkLockedParams(InvalidKeySpecException::new,
|
||||||
|
((EdECPublicKey) key).getParams());
|
||||||
|
|
||||||
|
if (X509EncodedKeySpec.class.isAssignableFrom(keySpec)) {
|
||||||
|
if (!key.getFormat().equals("X.509")) {
|
||||||
|
throw new InvalidKeySpecException("Format is not X.509");
|
||||||
|
}
|
||||||
|
return keySpec.cast(new X509EncodedKeySpec(key.getEncoded()));
|
||||||
|
} else if (EdECPublicKeySpec.class.isAssignableFrom(keySpec)) {
|
||||||
|
EdECPublicKey edKey = (EdECPublicKey) key;
|
||||||
|
return keySpec.cast(
|
||||||
|
new EdECPublicKeySpec(edKey.getParams(), edKey.getPoint()));
|
||||||
|
} else {
|
||||||
|
throw new InvalidKeySpecException(
|
||||||
|
"KeySpec must be X509EncodedKeySpec or EdECPublicKeySpec");
|
||||||
|
}
|
||||||
|
} else if (key instanceof EdECPrivateKey) {
|
||||||
|
checkLockedParams(InvalidKeySpecException::new,
|
||||||
|
((EdECPrivateKey) key).getParams());
|
||||||
|
|
||||||
|
if (PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec)) {
|
||||||
|
if (!key.getFormat().equals("PKCS#8")) {
|
||||||
|
throw new InvalidKeySpecException("Format is not PKCS#8");
|
||||||
|
}
|
||||||
|
return keySpec.cast(new PKCS8EncodedKeySpec(key.getEncoded()));
|
||||||
|
} else if (EdECPrivateKeySpec.class.isAssignableFrom(keySpec)) {
|
||||||
|
EdECPrivateKey edKey = (EdECPrivateKey) key;
|
||||||
|
byte[] scalar = edKey.getBytes().orElseThrow(
|
||||||
|
() -> new InvalidKeySpecException("No private key value")
|
||||||
|
);
|
||||||
|
return keySpec.cast(
|
||||||
|
new EdECPrivateKeySpec(edKey.getParams(), scalar));
|
||||||
|
} else {
|
||||||
|
throw new InvalidKeySpecException
|
||||||
|
("KeySpec must be PKCS8EncodedKeySpec or EdECPrivateKeySpec");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new InvalidKeySpecException("Unsupported key type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Ed25519 extends EdDSAKeyFactory {
|
||||||
|
|
||||||
|
public Ed25519() {
|
||||||
|
super(NamedParameterSpec.ED25519);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Ed448 extends EdDSAKeyFactory {
|
||||||
|
|
||||||
|
public Ed448() {
|
||||||
|
super(NamedParameterSpec.ED448);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,139 @@
|
||||||
|
/*
|
||||||
|
* 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. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* 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 sun.security.ec.ed;
|
||||||
|
|
||||||
|
//import java.security.*;
|
||||||
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.InvalidParameterException;
|
||||||
|
import java.security.KeyPair;
|
||||||
|
import java.security.KeyPairGeneratorSpi;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.ProviderException;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.security.spec.AlgorithmParameterSpec;
|
||||||
|
import java.security.spec.EdECPoint;
|
||||||
|
import java.security.spec.NamedParameterSpec;
|
||||||
|
|
||||||
|
import sun.security.jca.JCAUtil;
|
||||||
|
import sun.security.util.SecurityProviderConstants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key pair generator for the EdDSA signature algorithm.
|
||||||
|
*/
|
||||||
|
public class EdDSAKeyPairGenerator extends KeyPairGeneratorSpi {
|
||||||
|
|
||||||
|
private SecureRandom random = null;
|
||||||
|
private EdDSAOperations ops = null;
|
||||||
|
private EdDSAParameters lockedParams = null;
|
||||||
|
|
||||||
|
public EdDSAKeyPairGenerator() {
|
||||||
|
initialize(SecurityProviderConstants.DEF_ED_KEY_SIZE, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private EdDSAKeyPairGenerator(NamedParameterSpec paramSpec) {
|
||||||
|
tryInitialize(paramSpec);
|
||||||
|
lockedParams = ops.getParameters();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tryInitialize(NamedParameterSpec paramSpec) {
|
||||||
|
try {
|
||||||
|
initialize(paramSpec, null);
|
||||||
|
} catch (InvalidAlgorithmParameterException ex) {
|
||||||
|
String name = paramSpec.getName();
|
||||||
|
throw new ProviderException(name + " not supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize(int keySize, SecureRandom random) {
|
||||||
|
|
||||||
|
EdDSAParameters params = EdDSAParameters.getBySize(
|
||||||
|
InvalidParameterException::new, keySize);
|
||||||
|
|
||||||
|
initializeImpl(params, random);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize(AlgorithmParameterSpec params, SecureRandom random)
|
||||||
|
throws InvalidAlgorithmParameterException {
|
||||||
|
|
||||||
|
EdDSAParameters edParams = EdDSAParameters.get(
|
||||||
|
InvalidAlgorithmParameterException::new, params);
|
||||||
|
|
||||||
|
try {
|
||||||
|
initializeImpl(edParams, random);
|
||||||
|
} catch (InvalidParameterException e) {
|
||||||
|
throw new InvalidAlgorithmParameterException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeImpl(EdDSAParameters params, SecureRandom random) {
|
||||||
|
|
||||||
|
if (lockedParams != null && lockedParams != params) {
|
||||||
|
throw new InvalidParameterException("Parameters must be " +
|
||||||
|
lockedParams.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.ops = new EdDSAOperations(params);
|
||||||
|
} catch (NoSuchAlgorithmException ex) {
|
||||||
|
throw new ProviderException(ex);
|
||||||
|
}
|
||||||
|
this.random = random == null ? JCAUtil.getSecureRandom() : random;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KeyPair generateKeyPair() {
|
||||||
|
|
||||||
|
byte[] privateKey = ops.generatePrivate(random);
|
||||||
|
EdECPoint publicKey = ops.computePublic(privateKey);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new KeyPair(
|
||||||
|
new EdDSAPublicKeyImpl(ops.getParameters(), publicKey),
|
||||||
|
new EdDSAPrivateKeyImpl(ops.getParameters(), privateKey)
|
||||||
|
);
|
||||||
|
} catch (InvalidKeyException ex) {
|
||||||
|
throw new ProviderException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Ed25519 extends EdDSAKeyPairGenerator {
|
||||||
|
|
||||||
|
public Ed25519() {
|
||||||
|
super(NamedParameterSpec.ED25519);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Ed448 extends EdDSAKeyPairGenerator {
|
||||||
|
|
||||||
|
public Ed448() {
|
||||||
|
super(NamedParameterSpec.ED448);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,279 @@
|
||||||
|
/*
|
||||||
|
* 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. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* 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 sun.security.ec.ed;
|
||||||
|
|
||||||
|
import sun.security.ec.point.AffinePoint;
|
||||||
|
import sun.security.ec.point.Point;
|
||||||
|
import sun.security.util.ArrayUtil;
|
||||||
|
import sun.security.util.math.IntegerFieldModuloP;
|
||||||
|
import sun.security.util.math.IntegerModuloP;
|
||||||
|
import sun.security.util.math.MutableIntegerModuloP;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.security.SignatureException;
|
||||||
|
import java.security.spec.EdDSAParameterSpec;
|
||||||
|
import java.security.spec.EdECPoint;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A class containing the operations of the EdDSA signature scheme. The
|
||||||
|
* parameters include an object that performs the elliptic curve point
|
||||||
|
* arithmetic, and EdDSAOperations uses this object to construct the signing
|
||||||
|
* and verification operations.
|
||||||
|
*/
|
||||||
|
public class EdDSAOperations {
|
||||||
|
|
||||||
|
private final EdDSAParameters params;
|
||||||
|
|
||||||
|
public EdDSAOperations(EdDSAParameters params)
|
||||||
|
throws NoSuchAlgorithmException {
|
||||||
|
|
||||||
|
this.params = params;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EdDSAParameters getParameters() {
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] generatePrivate(SecureRandom random) {
|
||||||
|
byte[] result = new byte[params.getKeyLength()];
|
||||||
|
random.nextBytes(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EdECPoint computePublic(byte[] privateKey) {
|
||||||
|
byte[] privateKeyHash = params.digest(privateKey);
|
||||||
|
int byteLength = privateKeyHash.length / 2;
|
||||||
|
byte[] s = Arrays.copyOf(privateKeyHash, byteLength);
|
||||||
|
prune(s);
|
||||||
|
IntegerModuloP fieldS = params.getOrderField().getElement(s);
|
||||||
|
fieldS.asByteArray(s);
|
||||||
|
Point A = params.getEdOperations().basePointMultiply(s);
|
||||||
|
return asEdECPoint(A.asAffine());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static EdECPoint asEdECPoint(AffinePoint p) {
|
||||||
|
return new EdECPoint(p.getX().asBigInteger().testBit(0),
|
||||||
|
p.getY().asBigInteger());
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] sign(EdDSAParameterSpec sigParams, byte[] privateKey,
|
||||||
|
byte[] message) {
|
||||||
|
|
||||||
|
byte[] privateKeyHash = params.digest(privateKey);
|
||||||
|
|
||||||
|
int byteLength = privateKeyHash.length / 2;
|
||||||
|
byte[] s = Arrays.copyOf(privateKeyHash, byteLength);
|
||||||
|
prune(s);
|
||||||
|
IntegerModuloP sElem = params.getOrderField().getElement(s);
|
||||||
|
sElem.asByteArray(s);
|
||||||
|
Point A = params.getEdOperations().basePointMultiply(s);
|
||||||
|
byte[] prefix = Arrays.copyOfRange(privateKeyHash,
|
||||||
|
privateKeyHash.length / 2, privateKeyHash.length);
|
||||||
|
byte[] dom = params.dom(sigParams);
|
||||||
|
byte[] r = params.digest(dom, prefix, message);
|
||||||
|
|
||||||
|
// reduce r modulo the order
|
||||||
|
IntegerModuloP fieldR = params.getOrderField().getElement(r);
|
||||||
|
r = new byte[params.getKeyLength()];
|
||||||
|
fieldR.asByteArray(r);
|
||||||
|
|
||||||
|
Point R = params.getEdOperations().basePointMultiply(r);
|
||||||
|
|
||||||
|
byte[] encodedR = encode(byteLength, R);
|
||||||
|
byte[] encodedA = encode(byteLength, A);
|
||||||
|
byte[] k = params.digest(dom, encodedR, encodedA, message);
|
||||||
|
|
||||||
|
// S computation is in group-order field
|
||||||
|
IntegerFieldModuloP subField = params.getOrderField();
|
||||||
|
IntegerModuloP kElem = subField.getElement(k);
|
||||||
|
IntegerModuloP rElem = subField.getElement(r);
|
||||||
|
MutableIntegerModuloP S = kElem.mutable().setProduct(sElem);
|
||||||
|
S.setSum(rElem);
|
||||||
|
// need to be reduced before output conversion
|
||||||
|
S.setReduced();
|
||||||
|
byte[] sArr = S.asByteArray(byteLength);
|
||||||
|
byte[] rArr = encode(byteLength, R);
|
||||||
|
|
||||||
|
byte[] result = new byte[byteLength * 2];
|
||||||
|
System.arraycopy(rArr, 0, result, 0, byteLength);
|
||||||
|
System.arraycopy(sArr, 0, result, byteLength, byteLength);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean verify(EdDSAParameterSpec sigParams, AffinePoint affineA,
|
||||||
|
byte[] publicKey, byte[] message, byte[] signature)
|
||||||
|
throws SignatureException {
|
||||||
|
|
||||||
|
if (signature == null) {
|
||||||
|
throw new SignatureException("signature was null");
|
||||||
|
}
|
||||||
|
byte[] encR = Arrays.copyOf(signature, signature.length / 2);
|
||||||
|
byte[] encS = Arrays.copyOfRange(signature, signature.length / 2,
|
||||||
|
signature.length);
|
||||||
|
|
||||||
|
// reject s if it is too large
|
||||||
|
ArrayUtil.reverse(encS);
|
||||||
|
BigInteger bigS = new BigInteger(1, encS);
|
||||||
|
if (bigS.compareTo(params.getOrderField().getSize()) >= 0) {
|
||||||
|
throw new SignatureException("s is too large");
|
||||||
|
}
|
||||||
|
ArrayUtil.reverse(encS);
|
||||||
|
|
||||||
|
byte[] dom = params.dom(sigParams);
|
||||||
|
AffinePoint affineR = decodeAffinePoint(SignatureException::new, encR);
|
||||||
|
byte[] k = params.digest(dom, encR, publicKey, message);
|
||||||
|
// reduce k to improve performance of multiply
|
||||||
|
IntegerFieldModuloP subField = params.getOrderField();
|
||||||
|
IntegerModuloP kElem = subField.getElement(k);
|
||||||
|
k = kElem.asByteArray(k.length / 2);
|
||||||
|
|
||||||
|
Point pointR = params.getEdOperations().of(affineR);
|
||||||
|
Point pointA = params.getEdOperations().of(affineA);
|
||||||
|
|
||||||
|
EdECOperations edOps = params.getEdOperations();
|
||||||
|
Point lhs = edOps.basePointMultiply(encS);
|
||||||
|
Point rhs = edOps.setSum(edOps.setProduct(pointA.mutable(), k),
|
||||||
|
pointR.mutable());
|
||||||
|
|
||||||
|
return lhs.affineEquals(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean verify(EdDSAParameterSpec sigParams, byte[] publicKey,
|
||||||
|
byte[] message, byte[] signature)
|
||||||
|
throws InvalidKeyException, SignatureException {
|
||||||
|
|
||||||
|
AffinePoint affineA = decodeAffinePoint(InvalidKeyException::new,
|
||||||
|
publicKey);
|
||||||
|
return verify(sigParams, affineA, publicKey, message, signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
public
|
||||||
|
<T extends Throwable>
|
||||||
|
AffinePoint decodeAffinePoint(Function<String, T> exception, byte[] arr)
|
||||||
|
throws T {
|
||||||
|
|
||||||
|
if (arr.length != params.getKeyLength()) {
|
||||||
|
throw exception.apply("incorrect length");
|
||||||
|
}
|
||||||
|
|
||||||
|
arr = arr.clone();
|
||||||
|
int xLSB = (0xFF & arr[arr.length - 1]) >>> 7;
|
||||||
|
arr[arr.length - 1] &= 0x7F;
|
||||||
|
int yLength = (params.getBits() + 7) >> 3;
|
||||||
|
IntegerModuloP y =
|
||||||
|
params.getField().getElement(arr, 0, yLength, (byte) 0);
|
||||||
|
// reject non-canonical y values
|
||||||
|
ArrayUtil.reverse(arr);
|
||||||
|
BigInteger bigY = new BigInteger(1, arr);
|
||||||
|
if (bigY.compareTo(params.getField().getSize()) >= 0) {
|
||||||
|
throw exception.apply("y value is too large");
|
||||||
|
}
|
||||||
|
return params.getEdOperations().decodeAffinePoint(exception, xLSB, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public
|
||||||
|
<T extends Throwable>
|
||||||
|
AffinePoint decodeAffinePoint(Function<String, T> exception,
|
||||||
|
EdECPoint point)
|
||||||
|
throws T {
|
||||||
|
|
||||||
|
// reject non-canonical y values
|
||||||
|
if (point.getY().compareTo(params.getField().getSize()) >= 0) {
|
||||||
|
throw exception.apply("y value is too large");
|
||||||
|
}
|
||||||
|
|
||||||
|
int xLSB = point.isXOdd() ? 1 : 0;
|
||||||
|
IntegerModuloP y = params.getField().getElement(point.getY());
|
||||||
|
return params.getEdOperations().decodeAffinePoint(exception, xLSB, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mask off the high order bits of an encoded integer in an array. The
|
||||||
|
* array is modified in place.
|
||||||
|
*
|
||||||
|
* @param arr an array containing an encoded integer
|
||||||
|
* @param bits the number of bits to keep
|
||||||
|
* @return the number, in range [0,8], of bits kept in the highest byte
|
||||||
|
*/
|
||||||
|
private static int maskHighOrder(byte[] arr, int bits) {
|
||||||
|
|
||||||
|
int lastByteIndex = arr.length - 1;
|
||||||
|
int bitsDiff = arr.length * 8 - bits;
|
||||||
|
int highBits = 8 - bitsDiff;
|
||||||
|
byte msbMaskOff = (byte) ((1 << highBits) - 1);
|
||||||
|
arr[lastByteIndex] &= msbMaskOff;
|
||||||
|
|
||||||
|
return highBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prune an encoded scalar value by modifying it in place. The extra
|
||||||
|
* high-order bits are masked off, the highest valid bit it set, and the
|
||||||
|
* number is rounded down to a multiple of the co-factor.
|
||||||
|
*
|
||||||
|
* @param k an encoded scalar value
|
||||||
|
* @param bits the number of bits in the scalar
|
||||||
|
* @param logCofactor the base-2 logarithm of the co-factor
|
||||||
|
*/
|
||||||
|
private static void prune(byte[] k, int bits, int logCofactor) {
|
||||||
|
|
||||||
|
int lastByteIndex = k.length - 1;
|
||||||
|
|
||||||
|
// mask off unused high-order bits
|
||||||
|
int highBits = maskHighOrder(k, bits);
|
||||||
|
|
||||||
|
// set the highest bit
|
||||||
|
if (highBits == 0) {
|
||||||
|
k[lastByteIndex - 1] |= 0x80;
|
||||||
|
} else {
|
||||||
|
byte msbMaskOn = (byte) (1 << (highBits - 1));
|
||||||
|
k[lastByteIndex] |= msbMaskOn;
|
||||||
|
}
|
||||||
|
|
||||||
|
// round down to a multiple of the co-factor
|
||||||
|
byte lsbMaskOff = (byte) (0xFF << logCofactor);
|
||||||
|
k[0] &= lsbMaskOff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void prune(byte[] arr) {
|
||||||
|
prune(arr, params.getBits(), params.getLogCofactor());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] encode(int length, Point p) {
|
||||||
|
return encode(length, p.asAffine());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] encode(int length, AffinePoint p) {
|
||||||
|
byte[] result = p.getY().asByteArray(length);
|
||||||
|
int xLSB = p.getX().asByteArray(1)[0] & 0x01;
|
||||||
|
result[result.length - 1] |= (xLSB << 7);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,332 @@
|
||||||
|
/*
|
||||||
|
* 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. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* 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 sun.security.ec.ed;
|
||||||
|
|
||||||
|
import sun.security.ec.ParametersMap;
|
||||||
|
import sun.security.provider.SHAKE256;
|
||||||
|
import sun.security.util.ObjectIdentifier;
|
||||||
|
import sun.security.util.math.*;
|
||||||
|
import sun.security.util.math.intpoly.*;
|
||||||
|
import sun.security.x509.AlgorithmId;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.*;
|
||||||
|
import java.security.spec.*;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The set of parameters that defines an instance of the EdDSA signature
|
||||||
|
* scheme.
|
||||||
|
*/
|
||||||
|
public class EdDSAParameters {
|
||||||
|
|
||||||
|
public interface DigesterFactory {
|
||||||
|
// Default digest creator
|
||||||
|
Digester createDigester();
|
||||||
|
|
||||||
|
// Override this method if multiple key lengths are needed
|
||||||
|
default Digester createDigester(int len) {
|
||||||
|
return createDigester();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a digest over all the provided byte arrays
|
||||||
|
default byte[] digest(byte[]... data) {
|
||||||
|
Digester d = createDigester();
|
||||||
|
for (byte[] curData : data) {
|
||||||
|
d.update(curData, 0, curData.length);
|
||||||
|
}
|
||||||
|
return d.digest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hash for Ed25519
|
||||||
|
private static class SHA512DigesterFactory implements DigesterFactory {
|
||||||
|
@Override
|
||||||
|
public Digester createDigester() {
|
||||||
|
try {
|
||||||
|
MessageDigest md = MessageDigest.getInstance("SHA-512");
|
||||||
|
return new MessageDigester(md);
|
||||||
|
} catch (NoSuchAlgorithmException ex) {
|
||||||
|
throw new ProviderException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hash for Ed448
|
||||||
|
private static class SHAKE256DigesterFactory implements DigesterFactory {
|
||||||
|
@Override
|
||||||
|
// Most usage for Ed448 is 114bytes long
|
||||||
|
public Digester createDigester() {
|
||||||
|
return new SHAKE256Digester(114);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ed448 uses 64bytes long hasg for the signature message
|
||||||
|
@Override
|
||||||
|
public Digester createDigester(int len) {
|
||||||
|
return new SHAKE256Digester(len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Digester {
|
||||||
|
void update(byte data);
|
||||||
|
void update(byte[] data, int off, int len);
|
||||||
|
byte[] digest();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class MessageDigester implements Digester {
|
||||||
|
private final MessageDigest md;
|
||||||
|
|
||||||
|
private MessageDigester(MessageDigest md) {
|
||||||
|
this.md = md;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(byte data) {
|
||||||
|
md.update(data);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void update(byte[] data, int off, int len) {
|
||||||
|
md.update(data, off, len);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public byte[] digest() {
|
||||||
|
return md.digest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class SHAKE256Digester implements Digester {
|
||||||
|
SHAKE256 md;
|
||||||
|
|
||||||
|
SHAKE256Digester(int len) {
|
||||||
|
md = new SHAKE256(len);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void update(byte data) {
|
||||||
|
md.update(data);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void update(byte[] data, int off, int len) {
|
||||||
|
md.update(data, off, len);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public byte[] digest() {
|
||||||
|
return md.digest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static ParametersMap<EdDSAParameters> namedParams = new ParametersMap<>();
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
private final ObjectIdentifier oid;
|
||||||
|
private final IntegerFieldModuloP field;
|
||||||
|
private final IntegerFieldModuloP orderField;
|
||||||
|
private final ImmutableIntegerModuloP d;
|
||||||
|
private final EdECOperations edOperations;
|
||||||
|
private final DigesterFactory digester;
|
||||||
|
private final int keyLength;
|
||||||
|
private final int bits;
|
||||||
|
private final int logCofactor;
|
||||||
|
private final Function<EdDSAParameterSpec, byte[]> dom;
|
||||||
|
|
||||||
|
public EdDSAParameters(String name, ObjectIdentifier oid,
|
||||||
|
IntegerFieldModuloP field,
|
||||||
|
IntegerFieldModuloP orderField,
|
||||||
|
ImmutableIntegerModuloP d,
|
||||||
|
EdECOperations edOps,
|
||||||
|
DigesterFactory digester,
|
||||||
|
Function<EdDSAParameterSpec, byte[]> dom,
|
||||||
|
int keyLength, int bits, int logCofactor) {
|
||||||
|
this.oid = oid;
|
||||||
|
this.name = name;
|
||||||
|
this.field = field;
|
||||||
|
this.orderField = orderField;
|
||||||
|
this.d = d;
|
||||||
|
this.edOperations = edOps;
|
||||||
|
this.digester = digester;
|
||||||
|
this.keyLength = keyLength;
|
||||||
|
this.bits = bits;
|
||||||
|
this.logCofactor = logCofactor;
|
||||||
|
this.dom = dom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
public ObjectIdentifier getOid() {
|
||||||
|
return oid;
|
||||||
|
}
|
||||||
|
public IntegerFieldModuloP getField() {
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
public IntegerFieldModuloP getOrderField() {
|
||||||
|
return orderField;
|
||||||
|
}
|
||||||
|
public ImmutableIntegerModuloP getD() {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
public EdECOperations getEdOperations() {
|
||||||
|
return edOperations;
|
||||||
|
}
|
||||||
|
public int getKeyLength() {
|
||||||
|
return keyLength;
|
||||||
|
}
|
||||||
|
public int getBits() {
|
||||||
|
return bits;
|
||||||
|
}
|
||||||
|
public int getLogCofactor() {
|
||||||
|
return logCofactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Digester createDigester() {
|
||||||
|
return digester.createDigester();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Digester createDigester(int len) {
|
||||||
|
return digester.createDigester(len);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] digest(byte[]... data) {
|
||||||
|
return digester.digest(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] dom(EdDSAParameterSpec sigParams) {
|
||||||
|
return dom.apply(sigParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final static String prefixStr25519 =
|
||||||
|
"SigEd25519 no Ed25519 collisions";
|
||||||
|
private final static String prefixStr448 = "SigEd448";
|
||||||
|
|
||||||
|
// Used for Ed25519
|
||||||
|
static byte[] dom2(EdDSAParameterSpec sigParams) {
|
||||||
|
if (!sigParams.isPrehash() && !sigParams.getContext().isPresent()) {
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
return domImpl(prefixStr25519, sigParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used for Ed488
|
||||||
|
static byte[] dom4(EdDSAParameterSpec sigParams) {
|
||||||
|
return domImpl(prefixStr448, sigParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
static byte[] domImpl(String prefixStr, EdDSAParameterSpec sigParams) {
|
||||||
|
byte[] prefix = prefixStr.getBytes(StandardCharsets.US_ASCII);
|
||||||
|
byte[] context = sigParams.getContext().orElse(new byte[0]);
|
||||||
|
int length = prefix.length + 2 + context.length;
|
||||||
|
byte[] result = new byte[length];
|
||||||
|
System.arraycopy(prefix, 0, result, 0, prefix.length);
|
||||||
|
byte x = (byte) (sigParams.isPrehash() ? 1 : 0);
|
||||||
|
result[prefix.length] = x;
|
||||||
|
result[prefix.length + 1] = (byte) context.length;
|
||||||
|
System.arraycopy(context, 0, result, prefix.length + 2,
|
||||||
|
context.length);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
// set up Ed25519
|
||||||
|
try {
|
||||||
|
IntegerFieldModuloP ed25519Field = new IntegerPolynomial25519();
|
||||||
|
IntegerFieldModuloP ed25519OrderField = new Curve25519OrderField();
|
||||||
|
BigInteger biD = new BigInteger("3709570593466943934313808350875" +
|
||||||
|
"4565189542113879843219016388785533085940283555");
|
||||||
|
ImmutableIntegerModuloP d = ed25519Field.getElement(biD);
|
||||||
|
BigInteger baseX = new BigInteger("15112221349535400772501151409" +
|
||||||
|
"588531511454012693041857206046113283949847762202");
|
||||||
|
BigInteger baseY = new BigInteger("46316835694926478169428394003" +
|
||||||
|
"475163141307993866256225615783033603165251855960");
|
||||||
|
EdECOperations edOps = new Ed25519Operations(d, baseX, baseY);
|
||||||
|
String name = NamedParameterSpec.ED25519.getName();
|
||||||
|
ObjectIdentifier oid = new ObjectIdentifier("1.3.101.112");
|
||||||
|
int bits = 255;
|
||||||
|
DigesterFactory digester = new SHA512DigesterFactory();
|
||||||
|
EdDSAParameters params = new EdDSAParameters(name, oid,
|
||||||
|
ed25519Field, ed25519OrderField, d, edOps,
|
||||||
|
digester, EdDSAParameters::dom2, 32, bits, 3);
|
||||||
|
|
||||||
|
namedParams.put(name, oid, bits, params);
|
||||||
|
|
||||||
|
} catch (IOException ex) {
|
||||||
|
// Unable to set Ed25519 parameters---it will be disabled
|
||||||
|
}
|
||||||
|
|
||||||
|
// set up Ed448
|
||||||
|
try {
|
||||||
|
IntegerFieldModuloP ed448Field = new IntegerPolynomial448();
|
||||||
|
IntegerFieldModuloP ed448OrderField = new Curve448OrderField();
|
||||||
|
BigInteger biD = ed448Field.getSize().subtract(
|
||||||
|
new BigInteger("39081"));
|
||||||
|
ImmutableIntegerModuloP d = ed448Field.getElement(biD);
|
||||||
|
BigInteger baseX = new BigInteger("224580040295924300187604334" +
|
||||||
|
"099896036246789641632564134246125461686950415467406032909" +
|
||||||
|
"029192869357953282578032075146446173674602635247710");
|
||||||
|
BigInteger baseY = new BigInteger("298819210078481492676017930" +
|
||||||
|
"443930673437544040154080242095928241372331506189835876003" +
|
||||||
|
"536878655418784733982303233503462500531545062832660");
|
||||||
|
EdECOperations edOps = new Ed448Operations(d, baseX, baseY);
|
||||||
|
String name = NamedParameterSpec.ED448.getName();
|
||||||
|
ObjectIdentifier oid = new ObjectIdentifier("1.3.101.113");
|
||||||
|
int bits = 448;
|
||||||
|
DigesterFactory digester = new SHAKE256DigesterFactory();
|
||||||
|
EdDSAParameters params = new EdDSAParameters(name, oid,
|
||||||
|
ed448Field, ed448OrderField, d, edOps,
|
||||||
|
digester, EdDSAParameters::dom4, 57, bits, 2);
|
||||||
|
|
||||||
|
namedParams.put(name, oid, bits, params);
|
||||||
|
|
||||||
|
} catch (IOException ex) {
|
||||||
|
// Unable to set Ed448 parameters---it will be disabled
|
||||||
|
}
|
||||||
|
|
||||||
|
namedParams.fix();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static
|
||||||
|
<T extends Throwable>
|
||||||
|
EdDSAParameters getBySize(Function<String, T> exception,
|
||||||
|
int size) throws T {
|
||||||
|
|
||||||
|
return namedParams.getBySize(exception, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static
|
||||||
|
<T extends Throwable>
|
||||||
|
EdDSAParameters get(Function<String, T> exception,
|
||||||
|
AlgorithmId algId) throws T {
|
||||||
|
|
||||||
|
return namedParams.get(exception, algId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static
|
||||||
|
<T extends Throwable>
|
||||||
|
EdDSAParameters get(Function<String, T> exception,
|
||||||
|
AlgorithmParameterSpec params) throws T {
|
||||||
|
|
||||||
|
return namedParams.get(exception, params);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,116 @@
|
||||||
|
/*
|
||||||
|
* 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. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* 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 sun.security.ec.ed;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.ProviderException;
|
||||||
|
import java.security.interfaces.EdECPrivateKey;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.security.spec.NamedParameterSpec;
|
||||||
|
|
||||||
|
import sun.security.pkcs.PKCS8Key;
|
||||||
|
import sun.security.x509.AlgorithmId;
|
||||||
|
import sun.security.util.*;
|
||||||
|
|
||||||
|
public final class EdDSAPrivateKeyImpl
|
||||||
|
extends PKCS8Key implements EdECPrivateKey {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private final NamedParameterSpec paramSpec;
|
||||||
|
private byte[] h;
|
||||||
|
|
||||||
|
EdDSAPrivateKeyImpl(EdDSAParameters params, byte[] h)
|
||||||
|
throws InvalidKeyException {
|
||||||
|
|
||||||
|
this.paramSpec = new NamedParameterSpec(params.getName());
|
||||||
|
this.algid = new AlgorithmId(params.getOid());
|
||||||
|
this.h = h.clone();
|
||||||
|
|
||||||
|
encodeKey();
|
||||||
|
|
||||||
|
checkLength(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
EdDSAPrivateKeyImpl(byte[] encoded) throws InvalidKeyException {
|
||||||
|
|
||||||
|
decode(encoded);
|
||||||
|
EdDSAParameters params = EdDSAParameters.get(
|
||||||
|
InvalidKeyException::new, algid);
|
||||||
|
paramSpec = new NamedParameterSpec(params.getName());
|
||||||
|
|
||||||
|
decodeKey();
|
||||||
|
|
||||||
|
checkLength(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void decodeKey() throws InvalidKeyException {
|
||||||
|
try {
|
||||||
|
DerInputStream derStream = new DerInputStream(key);
|
||||||
|
h = derStream.getOctetString();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new InvalidKeyException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void encodeKey() {
|
||||||
|
DerOutputStream derKey = new DerOutputStream();
|
||||||
|
try {
|
||||||
|
derKey.putOctetString(h);
|
||||||
|
this.key = derKey.toByteArray();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new ProviderException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkLength(EdDSAParameters params) throws InvalidKeyException {
|
||||||
|
|
||||||
|
if (params.getKeyLength() != this.h.length) {
|
||||||
|
throw new InvalidKeyException("key length is " + this.h.length +
|
||||||
|
", key length must be " + params.getKeyLength());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getKey() {
|
||||||
|
return h.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAlgorithm() {
|
||||||
|
return "EdDSA";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NamedParameterSpec getParams() {
|
||||||
|
return paramSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<byte[]> getBytes() {
|
||||||
|
return Optional.of(getKey());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,130 @@
|
||||||
|
/*
|
||||||
|
* 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. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* 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 sun.security.ec.ed;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.KeyRep;
|
||||||
|
import java.security.interfaces.EdECPublicKey;
|
||||||
|
import java.security.spec.EdECPoint;
|
||||||
|
import java.security.spec.NamedParameterSpec;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import sun.security.util.BitArray;
|
||||||
|
import sun.security.x509.AlgorithmId;
|
||||||
|
import sun.security.x509.X509Key;
|
||||||
|
|
||||||
|
public final class EdDSAPublicKeyImpl extends X509Key implements EdECPublicKey {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private final EdECPoint point;
|
||||||
|
private final NamedParameterSpec paramSpec;
|
||||||
|
|
||||||
|
public EdDSAPublicKeyImpl(EdDSAParameters params, EdECPoint point)
|
||||||
|
throws InvalidKeyException {
|
||||||
|
this.paramSpec = new NamedParameterSpec(params.getName());
|
||||||
|
this.algid = new AlgorithmId(params.getOid());
|
||||||
|
this.point = point;
|
||||||
|
|
||||||
|
byte[] encodedPoint = point.getY().toByteArray();
|
||||||
|
reverse(encodedPoint);
|
||||||
|
// array may be too large or too small, depending on the value
|
||||||
|
encodedPoint = Arrays.copyOf(encodedPoint, params.getKeyLength());
|
||||||
|
// set the high-order bit of the encoded point
|
||||||
|
byte msb = (byte) (point.isXOdd() ? 0x80 : 0);
|
||||||
|
encodedPoint[encodedPoint.length - 1] |= msb;
|
||||||
|
setKey(new BitArray(encodedPoint.length * 8, encodedPoint));
|
||||||
|
|
||||||
|
checkLength(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EdDSAPublicKeyImpl(byte[] encoded) throws InvalidKeyException {
|
||||||
|
decode(encoded);
|
||||||
|
|
||||||
|
EdDSAParameters params =
|
||||||
|
EdDSAParameters.get(InvalidKeyException::new, algid);
|
||||||
|
this.paramSpec = new NamedParameterSpec(params.getName());
|
||||||
|
// construct the EdECPoint representation
|
||||||
|
byte[] encodedPoint = getKey().toByteArray();
|
||||||
|
byte msb = encodedPoint[encodedPoint.length - 1];
|
||||||
|
encodedPoint[encodedPoint.length - 1] &= (byte) 0x7F;
|
||||||
|
boolean xOdd = (msb & 0x80) != 0;
|
||||||
|
reverse(encodedPoint);
|
||||||
|
BigInteger y = new BigInteger(1, encodedPoint);
|
||||||
|
this.point = new EdECPoint(xOdd, y);
|
||||||
|
|
||||||
|
checkLength(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkLength(EdDSAParameters params) throws InvalidKeyException {
|
||||||
|
if (params.getKeyLength() * 8 != getKey().length()) {
|
||||||
|
throw new InvalidKeyException(
|
||||||
|
"key length must be " + params.getKeyLength());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getEncodedPoint() {
|
||||||
|
return getKey().toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EdECPoint getPoint() {
|
||||||
|
return point;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NamedParameterSpec getParams() {
|
||||||
|
return paramSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAlgorithm() {
|
||||||
|
return "EdDSA";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Object writeReplace() throws java.io.ObjectStreamException {
|
||||||
|
return new KeyRep(KeyRep.Type.PUBLIC, getAlgorithm(), getFormat(),
|
||||||
|
getEncoded());
|
||||||
|
}
|
||||||
|
|
||||||
|
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--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,314 @@
|
||||||
|
/*
|
||||||
|
* 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. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* 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 sun.security.ec.ed;
|
||||||
|
|
||||||
|
import sun.security.ec.point.AffinePoint;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.security.AlgorithmParameters;
|
||||||
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.InvalidParameterException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.PrivateKey;
|
||||||
|
import java.security.ProviderException;
|
||||||
|
import java.security.PublicKey;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.security.SignatureException;
|
||||||
|
import java.security.SignatureSpi;
|
||||||
|
import java.security.interfaces.EdECPrivateKey;
|
||||||
|
import java.security.interfaces.EdECPublicKey;
|
||||||
|
import java.security.spec.AlgorithmParameterSpec;
|
||||||
|
import java.security.spec.EdDSAParameterSpec;
|
||||||
|
import java.security.spec.NamedParameterSpec;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class EdDSASignature extends SignatureSpi {
|
||||||
|
|
||||||
|
private interface MessageAccumulator {
|
||||||
|
void add(byte b);
|
||||||
|
void add(byte[] data, int off, int len);
|
||||||
|
byte[] getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class DigestAccumulator implements MessageAccumulator {
|
||||||
|
private final EdDSAParameters.Digester digester;
|
||||||
|
|
||||||
|
DigestAccumulator(EdDSAParameters.Digester digester) {
|
||||||
|
this.digester = digester;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void add(byte b) {
|
||||||
|
digester.update(b);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void add(byte[] data, int off, int len) {
|
||||||
|
digester.update(data, off, len);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public byte[] getMessage() {
|
||||||
|
return digester.digest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class MemoryAccumulator implements MessageAccumulator {
|
||||||
|
ByteArrayOutputStream message = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void add(byte b) {
|
||||||
|
message.write(b);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void add(byte[] data, int off, int len) {
|
||||||
|
message.write(data, off, len);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public byte[] getMessage() {
|
||||||
|
return message.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] privateKey;
|
||||||
|
private AffinePoint publicKeyPoint;
|
||||||
|
private byte[] publicKeyBytes;
|
||||||
|
private EdDSAOperations ops;
|
||||||
|
private EdDSAParameters lockedParams = null;
|
||||||
|
private MessageAccumulator message = null;
|
||||||
|
private EdDSAParameterSpec sigParams = new EdDSAParameterSpec(false);
|
||||||
|
|
||||||
|
public EdDSASignature() {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
EdDSASignature(NamedParameterSpec paramSpec) {
|
||||||
|
lockedParams = EdDSAParameters.get(ProviderException::new, paramSpec);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void engineInitVerify(PublicKey publicKey)
|
||||||
|
throws InvalidKeyException {
|
||||||
|
|
||||||
|
if (!(publicKey instanceof EdECPublicKey)) {
|
||||||
|
throw new InvalidKeyException("Unsupported key type");
|
||||||
|
}
|
||||||
|
EdECPublicKey edKey = (EdECPublicKey) publicKey;
|
||||||
|
EdDSAParameters params = EdDSAParameters.get(
|
||||||
|
InvalidKeyException::new, edKey.getParams());
|
||||||
|
|
||||||
|
initImpl(params);
|
||||||
|
this.privateKey = null;
|
||||||
|
this.publicKeyPoint = ops.decodeAffinePoint(InvalidKeyException::new,
|
||||||
|
edKey.getPoint());
|
||||||
|
EdDSAPublicKeyImpl pubKeyImpl = new EdDSAPublicKeyImpl(params,
|
||||||
|
edKey.getPoint());
|
||||||
|
this.publicKeyBytes = pubKeyImpl.getEncodedPoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void engineInitSign(PrivateKey privateKey)
|
||||||
|
throws InvalidKeyException {
|
||||||
|
engineInitSign(privateKey, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void engineInitSign(PrivateKey privateKey, SecureRandom random)
|
||||||
|
throws InvalidKeyException {
|
||||||
|
|
||||||
|
if (!(privateKey instanceof EdECPrivateKey)) {
|
||||||
|
throw new InvalidKeyException("Unsupported key type");
|
||||||
|
}
|
||||||
|
EdECPrivateKey edKey = (EdECPrivateKey) privateKey;
|
||||||
|
|
||||||
|
initImpl(edKey.getParams());
|
||||||
|
this.privateKey = edKey.getBytes().orElseThrow(
|
||||||
|
() -> new InvalidKeyException("No private key value"));
|
||||||
|
this.publicKeyPoint = null;
|
||||||
|
this.publicKeyBytes = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private
|
||||||
|
<T extends Throwable>
|
||||||
|
void checkLockedParams(Function<String, T> exception,
|
||||||
|
EdDSAParameters params) throws T {
|
||||||
|
if (lockedParams != null && lockedParams != params) {
|
||||||
|
throw exception.apply("Parameters must be " +
|
||||||
|
lockedParams.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureMessageInit() throws SignatureException {
|
||||||
|
if (message == null) {
|
||||||
|
initMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initMessage() throws SignatureException {
|
||||||
|
if (this.ops == null) {
|
||||||
|
throw new SignatureException("not initialized");
|
||||||
|
}
|
||||||
|
EdDSAParameters params = ops.getParameters();
|
||||||
|
|
||||||
|
if (sigParams.isPrehash()) {
|
||||||
|
this.message = new DigestAccumulator(params.createDigester(64));
|
||||||
|
} else {
|
||||||
|
this.message = new MemoryAccumulator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void engineUpdate(byte b) throws SignatureException {
|
||||||
|
ensureMessageInit();
|
||||||
|
this.message.add(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void engineUpdate(byte[] b, int off, int len)
|
||||||
|
throws SignatureException {
|
||||||
|
|
||||||
|
ensureMessageInit();
|
||||||
|
this.message.add(b, off, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte[] engineSign() throws SignatureException {
|
||||||
|
if (privateKey == null) {
|
||||||
|
throw new SignatureException("Missing private key");
|
||||||
|
}
|
||||||
|
ensureMessageInit();
|
||||||
|
byte[] result = ops.sign(this.sigParams, this.privateKey,
|
||||||
|
message.getMessage());
|
||||||
|
message = null;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
|
||||||
|
if (publicKeyBytes == null) {
|
||||||
|
throw new SignatureException("Missing publicKey");
|
||||||
|
}
|
||||||
|
if (message == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
boolean result = ops.verify(this.sigParams, this.publicKeyPoint,
|
||||||
|
this.publicKeyBytes, message.getMessage(), sigBytes);
|
||||||
|
message = null;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initImpl(EdDSAParameters params) throws InvalidKeyException {
|
||||||
|
checkLockedParams(InvalidKeyException::new, params);
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.ops = new EdDSAOperations(params);
|
||||||
|
} catch (NoSuchAlgorithmException ex) {
|
||||||
|
throw new ProviderException(ex);
|
||||||
|
}
|
||||||
|
// message is (re)set to null
|
||||||
|
// it will be initialized on first update
|
||||||
|
this.message = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initImpl(NamedParameterSpec paramSpec)
|
||||||
|
throws InvalidKeyException {
|
||||||
|
|
||||||
|
EdDSAParameters params = EdDSAParameters.get(
|
||||||
|
InvalidKeyException::new, paramSpec);
|
||||||
|
initImpl(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
@Override
|
||||||
|
protected Object engineGetParameter(String param)
|
||||||
|
throws InvalidParameterException {
|
||||||
|
throw new UnsupportedOperationException("getParameter() not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
@Override
|
||||||
|
protected void engineSetParameter(String param, Object value)
|
||||||
|
throws InvalidParameterException {
|
||||||
|
|
||||||
|
throw new UnsupportedOperationException("setParameter() not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void engineSetParameter(AlgorithmParameterSpec params)
|
||||||
|
throws InvalidAlgorithmParameterException {
|
||||||
|
|
||||||
|
// by convention, ignore null parameters
|
||||||
|
if (params == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params instanceof EdDSAParameterSpec) {
|
||||||
|
if (message != null) {
|
||||||
|
// sign/verify in progress
|
||||||
|
throw new InvalidParameterException("Cannot change signature " +
|
||||||
|
"parameters during operation");
|
||||||
|
}
|
||||||
|
EdDSAParameterSpec edDsaParams = (EdDSAParameterSpec) params;
|
||||||
|
checkContextLength(edDsaParams);
|
||||||
|
|
||||||
|
this.sigParams = edDsaParams;
|
||||||
|
} else {
|
||||||
|
throw new InvalidAlgorithmParameterException(
|
||||||
|
"Only EdDSAParameterSpec supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void checkContextLength(EdDSAParameterSpec edDsaParams)
|
||||||
|
throws InvalidAlgorithmParameterException {
|
||||||
|
|
||||||
|
if (edDsaParams.getContext().isPresent()) {
|
||||||
|
byte[] context = edDsaParams.getContext().get();
|
||||||
|
if (context.length > 255) {
|
||||||
|
throw new InvalidAlgorithmParameterException(
|
||||||
|
"Context is longer than 255 bytes");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// There is no RFC-defined ASN.1 for prehash and context (RFC 8410)
|
||||||
|
@Override
|
||||||
|
protected AlgorithmParameters engineGetParameters() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Ed25519 extends EdDSASignature {
|
||||||
|
|
||||||
|
public Ed25519() {
|
||||||
|
super(NamedParameterSpec.ED25519);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Ed448 extends EdDSASignature {
|
||||||
|
|
||||||
|
public Ed448() {
|
||||||
|
super(NamedParameterSpec.ED448);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
/*
|
||||||
|
* 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. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* 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 sun.security.ec.ed;
|
||||||
|
|
||||||
|
import sun.security.ec.point.*;
|
||||||
|
import sun.security.util.math.IntegerModuloP;
|
||||||
|
import sun.security.util.math.MutableIntegerModuloP;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Base class for Edwards curve ECC implementations.
|
||||||
|
*/
|
||||||
|
public abstract class EdECOperations {
|
||||||
|
|
||||||
|
// Curve-specific base point multiplication.
|
||||||
|
public abstract Point basePointMultiply(byte[] s);
|
||||||
|
|
||||||
|
// Decode curve-specifics to the affinePoint
|
||||||
|
public abstract <T extends Throwable>
|
||||||
|
AffinePoint decodeAffinePoint(Function<String, T> exception,
|
||||||
|
int xLSB, IntegerModuloP y) throws T;
|
||||||
|
|
||||||
|
// Curve specific point from an X,Y point
|
||||||
|
public abstract ImmutablePoint of(AffinePoint p);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generic method for taking two classes implementing MutablePoint to be
|
||||||
|
* called by the curve-specific setSum()
|
||||||
|
*/
|
||||||
|
public MutablePoint setSum(MutablePoint p1, MutablePoint p2) {
|
||||||
|
MutableIntegerModuloP t1 = p2.getField().get1().mutable();
|
||||||
|
MutableIntegerModuloP t2 = p2.getField().get1().mutable();
|
||||||
|
MutableIntegerModuloP t3 = p2.getField().get1().mutable();
|
||||||
|
return setSum(p1, p2, t1, t2, t3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generic method for taking a class implementing MutablePoint with a
|
||||||
|
* scalar to returning the point product using curve-specific methods.
|
||||||
|
*/
|
||||||
|
public MutablePoint setProduct(MutablePoint p1, byte[] s) {
|
||||||
|
MutablePoint p = p1.mutable();
|
||||||
|
p1.setValue(getNeutral());
|
||||||
|
MutablePoint addResult = getNeutral().mutable();
|
||||||
|
MutableIntegerModuloP t1 = p.getField().get0().mutable();
|
||||||
|
MutableIntegerModuloP t2 = p.getField().get0().mutable();
|
||||||
|
MutableIntegerModuloP t3 = p.getField().get0().mutable();
|
||||||
|
|
||||||
|
for (int i = 0; i < s.length * 8; i++) {
|
||||||
|
addResult.setValue(p1);
|
||||||
|
setSum(addResult, p, t1, t2, t3);
|
||||||
|
int swap = bitAt(s, i);
|
||||||
|
p1.conditionalSet(addResult, swap);
|
||||||
|
setDouble(p, t1, t2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return p1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Abstract method for constructing the neutral point on the curve
|
||||||
|
protected abstract ImmutablePoint getNeutral();
|
||||||
|
|
||||||
|
|
||||||
|
// Abstract method for Curve-specific point addition
|
||||||
|
protected abstract MutablePoint setSum(MutablePoint p1, MutablePoint p2,
|
||||||
|
MutableIntegerModuloP t1,
|
||||||
|
MutableIntegerModuloP t2,
|
||||||
|
MutableIntegerModuloP t3);
|
||||||
|
// Abstract method for Curve-specific point doubling
|
||||||
|
protected abstract MutablePoint setDouble(MutablePoint p,
|
||||||
|
MutableIntegerModuloP t1,
|
||||||
|
MutableIntegerModuloP t2);
|
||||||
|
|
||||||
|
private static int bitAt(byte[] arr, int index) {
|
||||||
|
int byteIndex = index / 8;
|
||||||
|
int bitIndex = index % 8;
|
||||||
|
return (arr[byteIndex] & (1 << bitIndex)) >> bitIndex;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,194 @@
|
||||||
|
/*
|
||||||
|
* 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. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* 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 sun.security.ec.point;
|
||||||
|
|
||||||
|
import sun.security.util.math.*;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Elliptic curve point in extended homogeneous coordinates (X, Y, T, Z) where
|
||||||
|
* an affine point (x, y) is represented using any (X, Y, T, Z) s.t.
|
||||||
|
* x = X/Z, y = Y/Z, and x*y = T/Z.
|
||||||
|
*/
|
||||||
|
public abstract class ExtendedHomogeneousPoint
|
||||||
|
<T extends IntegerModuloP> implements Point {
|
||||||
|
|
||||||
|
protected final T x;
|
||||||
|
protected final T y;
|
||||||
|
protected final T t;
|
||||||
|
protected final T z;
|
||||||
|
|
||||||
|
protected ExtendedHomogeneousPoint(T x, T y, T t, T z) {
|
||||||
|
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.t = t;
|
||||||
|
this.z = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IntegerFieldModuloP getField() {
|
||||||
|
return this.x.getField();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Immutable fixed() {
|
||||||
|
return new Immutable(x.fixed(), y.fixed(), t.fixed(), z.fixed());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mutable mutable() {
|
||||||
|
return new Mutable(x.mutable(), y.mutable(), t.mutable(), z.mutable());
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getX() {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getY() {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getT() {
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getZ() {
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AffinePoint asAffine() {
|
||||||
|
IntegerModuloP zInv = z.multiplicativeInverse();
|
||||||
|
return new AffinePoint(x.multiply(zInv), y.multiply(zInv));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static
|
||||||
|
<T1 extends IntegerModuloP, T2 extends IntegerModuloP>
|
||||||
|
boolean affineEquals(ExtendedHomogeneousPoint<T1> p1,
|
||||||
|
ExtendedHomogeneousPoint<T2> p2) {
|
||||||
|
MutableIntegerModuloP x1 = p1.getX().mutable().setProduct(p2.getZ());
|
||||||
|
MutableIntegerModuloP x2 = p2.getX().mutable().setProduct(p1.getZ());
|
||||||
|
if (!x1.asBigInteger().equals(x2.asBigInteger())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MutableIntegerModuloP y1 = p1.getY().mutable().setProduct(p2.getZ());
|
||||||
|
MutableIntegerModuloP y2 = p2.getY().mutable().setProduct(p1.getZ());
|
||||||
|
if (!y1.asBigInteger().equals(y2.asBigInteger())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean affineEquals(Point p) {
|
||||||
|
if (p instanceof ExtendedHomogeneousPoint) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
ExtendedHomogeneousPoint<IntegerModuloP> ehp =
|
||||||
|
(ExtendedHomogeneousPoint<IntegerModuloP>) p;
|
||||||
|
return affineEquals(this, ehp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return asAffine().equals(p.asAffine());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Immutable
|
||||||
|
extends ExtendedHomogeneousPoint<ImmutableIntegerModuloP>
|
||||||
|
implements ImmutablePoint {
|
||||||
|
|
||||||
|
public Immutable(ImmutableIntegerModuloP x,
|
||||||
|
ImmutableIntegerModuloP y,
|
||||||
|
ImmutableIntegerModuloP t,
|
||||||
|
ImmutableIntegerModuloP z) {
|
||||||
|
super(x, y, t, z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Mutable
|
||||||
|
extends ExtendedHomogeneousPoint<MutableIntegerModuloP>
|
||||||
|
implements MutablePoint {
|
||||||
|
|
||||||
|
public Mutable(MutableIntegerModuloP x,
|
||||||
|
MutableIntegerModuloP y,
|
||||||
|
MutableIntegerModuloP t,
|
||||||
|
MutableIntegerModuloP z) {
|
||||||
|
super(x, y, t, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mutable conditionalSet(Point p, int set) {
|
||||||
|
if (!(p instanceof ExtendedHomogeneousPoint)) {
|
||||||
|
throw new RuntimeException("Incompatible point");
|
||||||
|
}
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
ExtendedHomogeneousPoint<IntegerModuloP> ehp =
|
||||||
|
(ExtendedHomogeneousPoint<IntegerModuloP>) p;
|
||||||
|
return conditionalSet(ehp, set);
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T extends IntegerModuloP>
|
||||||
|
Mutable conditionalSet(ExtendedHomogeneousPoint<T> ehp, int set) {
|
||||||
|
|
||||||
|
x.conditionalSet(ehp.x, set);
|
||||||
|
y.conditionalSet(ehp.y, set);
|
||||||
|
t.conditionalSet(ehp.t, set);
|
||||||
|
z.conditionalSet(ehp.z, set);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mutable setValue(AffinePoint p) {
|
||||||
|
x.setValue(p.getX());
|
||||||
|
y.setValue(p.getY());
|
||||||
|
t.setValue(p.getX()).setProduct(p.getY());
|
||||||
|
z.setValue(p.getX().getField().get1());
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mutable setValue(Point p) {
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
ExtendedHomogeneousPoint<IntegerModuloP> ehp =
|
||||||
|
(ExtendedHomogeneousPoint<IntegerModuloP>) p;
|
||||||
|
|
||||||
|
return setValue(ehp);
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T extends IntegerModuloP>
|
||||||
|
Mutable setValue(ExtendedHomogeneousPoint<T> ehp) {
|
||||||
|
|
||||||
|
x.setValue(ehp.x);
|
||||||
|
y.setValue(ehp.y);
|
||||||
|
t.setValue(ehp.t);
|
||||||
|
z.setValue(ehp.z);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -38,6 +38,7 @@ public interface Point {
|
||||||
|
|
||||||
IntegerFieldModuloP getField();
|
IntegerFieldModuloP getField();
|
||||||
AffinePoint asAffine();
|
AffinePoint asAffine();
|
||||||
|
boolean affineEquals(Point p);
|
||||||
|
|
||||||
ImmutablePoint fixed();
|
ImmutablePoint fixed();
|
||||||
MutablePoint mutable();
|
MutablePoint mutable();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -77,6 +77,36 @@ public abstract class ProjectivePoint
|
||||||
return new AffinePoint(x.multiply(zInv), y.multiply(zInv));
|
return new AffinePoint(x.multiply(zInv), y.multiply(zInv));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static
|
||||||
|
<T1 extends IntegerModuloP, T2 extends IntegerModuloP>
|
||||||
|
boolean affineEquals(ProjectivePoint<T1> p1,
|
||||||
|
ProjectivePoint<T2> p2) {
|
||||||
|
MutableIntegerModuloP x1 = p1.getX().mutable().setProduct(p2.getZ());
|
||||||
|
MutableIntegerModuloP x2 = p2.getX().mutable().setProduct(p1.getZ());
|
||||||
|
if (!x1.asBigInteger().equals(x2.asBigInteger())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MutableIntegerModuloP y1 = p1.getY().mutable().setProduct(p2.getZ());
|
||||||
|
MutableIntegerModuloP y2 = p2.getY().mutable().setProduct(p1.getZ());
|
||||||
|
if (!y1.asBigInteger().equals(y2.asBigInteger())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean affineEquals(Point p) {
|
||||||
|
if (p instanceof ProjectivePoint) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
ProjectivePoint<IntegerModuloP> pp =
|
||||||
|
(ProjectivePoint<IntegerModuloP>) p;
|
||||||
|
return affineEquals(this, pp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return asAffine().equals(p.asAffine());
|
||||||
|
}
|
||||||
|
|
||||||
public static class Immutable
|
public static class Immutable
|
||||||
extends ProjectivePoint<ImmutableIntegerModuloP>
|
extends ProjectivePoint<ImmutableIntegerModuloP>
|
||||||
implements ImmutablePoint {
|
implements ImmutablePoint {
|
||||||
|
|
144
test/jdk/sun/security/ec/ed/EdECKeyFormat.java
Normal file
144
test/jdk/sun/security/ec/ed/EdECKeyFormat.java
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8166597
|
||||||
|
* @summary Check for correct formatting of EdDSA keys
|
||||||
|
* @library /test/lib
|
||||||
|
* @build jdk.test.lib.Convert
|
||||||
|
* @modules java.base/sun.security.util
|
||||||
|
* @run main EdECKeyFormat
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.security.*;
|
||||||
|
import java.security.spec.*;
|
||||||
|
import java.security.interfaces.*;
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.file.*;
|
||||||
|
import java.math.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import jdk.test.lib.Convert;
|
||||||
|
|
||||||
|
import sun.security.util.*;
|
||||||
|
|
||||||
|
public class EdECKeyFormat {
|
||||||
|
|
||||||
|
private interface Test {
|
||||||
|
public void runTest(Provider p) throws Exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void forEachProvider(Test t, String algName)
|
||||||
|
throws Exception {
|
||||||
|
|
||||||
|
int tested = 0;
|
||||||
|
for (Provider p : Security.getProviders()) {
|
||||||
|
Provider.Service s = p.getService("KeyPairGenerator", algName);
|
||||||
|
if (s != null) {
|
||||||
|
t.runTest(p);
|
||||||
|
tested++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tested == 0) {
|
||||||
|
throw new RuntimeException("no service found for " + algName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<String, String> privKeys = Map.of(
|
||||||
|
"Ed25519",
|
||||||
|
"302e020100300506032b657004220420d4ee72dbf913584ad5b6d8f1f769f8ad3afe" +
|
||||||
|
"7c28cbf1d4fbe097a88f44755842",
|
||||||
|
"Ed448",
|
||||||
|
"3047020100300506032b6571043b043980998f387e05852d217c1d715b177c24aa7b" +
|
||||||
|
"f3f4c3a72223f4983597b9ab2ed4793c30d871c24388b380d80bb36d963f5c276219" +
|
||||||
|
"b0677fed00"
|
||||||
|
);
|
||||||
|
|
||||||
|
private static List<String> pubKeys = List.of(
|
||||||
|
"302a300506032b657003210019bf44096984cdfe8541bac167dc3b96c85086aa30b6" +
|
||||||
|
"b6cb0c5c38ad703166e1"
|
||||||
|
);
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
privKeyTest("Ed25519");
|
||||||
|
privKeyTest("Ed448");
|
||||||
|
pubKeyTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void pubKeyTest() throws Exception {
|
||||||
|
forEachProvider(EdECKeyFormat::pubKeyTest, "EdDSA");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void pubKeyTest(Provider p) throws Exception {
|
||||||
|
for (String s : pubKeys) {
|
||||||
|
pubKeyTest(p, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void pubKeyTest(Provider p, String key) throws Exception {
|
||||||
|
// ensure that a properly-formatted key can be read
|
||||||
|
byte[] encodedKey = Convert.hexStringToByteArray(key);
|
||||||
|
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedKey);
|
||||||
|
KeyFactory kf = KeyFactory.getInstance("EdDSA", p);
|
||||||
|
kf.generatePublic(keySpec);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void privKeyTest(String algName) throws Exception {
|
||||||
|
|
||||||
|
forEachProvider(p -> privKeyTest(algName, p), algName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void privKeyTest(String algName, Provider p)
|
||||||
|
throws Exception {
|
||||||
|
|
||||||
|
System.out.println("Testing " + algName + " in " + p.getName());
|
||||||
|
|
||||||
|
// ensure format produced is correct
|
||||||
|
KeyPairGenerator kpg = KeyPairGenerator.getInstance(algName, p);
|
||||||
|
KeyPair kp = kpg.generateKeyPair();
|
||||||
|
PrivateKey priv = kp.getPrivate();
|
||||||
|
checkPrivKeyFormat(priv.getEncoded());
|
||||||
|
KeyFactory kf = KeyFactory.getInstance(algName, p);
|
||||||
|
PKCS8EncodedKeySpec keySpec =
|
||||||
|
kf.getKeySpec(priv, PKCS8EncodedKeySpec.class);
|
||||||
|
checkPrivKeyFormat(keySpec.getEncoded());
|
||||||
|
|
||||||
|
// ensure that a properly-formatted key can be read
|
||||||
|
byte[] encodedKey = Convert.hexStringToByteArray(privKeys.get(algName));
|
||||||
|
keySpec = new PKCS8EncodedKeySpec(encodedKey);
|
||||||
|
kf.generatePrivate(keySpec);
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
581
test/jdk/sun/security/ec/ed/TestEdDSA.java
Normal file
581
test/jdk/sun/security/ec/ed/TestEdDSA.java
Normal file
|
@ -0,0 +1,581 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8166597
|
||||||
|
* @summary EdDSA Signature Known Answer Tests (KAT) from RFC 8032
|
||||||
|
* @library /test/lib
|
||||||
|
* @build jdk.test.lib.Convert
|
||||||
|
* @run main TestEdDSA
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.security.*;
|
||||||
|
import java.security.spec.*;
|
||||||
|
import java.util.*;
|
||||||
|
import jdk.test.lib.Convert;
|
||||||
|
|
||||||
|
public class TestEdDSA {
|
||||||
|
|
||||||
|
private static SecureRandom random = new SecureRandom();
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
runBasicTests();
|
||||||
|
runKAT();
|
||||||
|
runCurveMixTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void runKAT() throws Exception {
|
||||||
|
|
||||||
|
// "pure" Ed25519
|
||||||
|
runSignTest("Ed25519", null,
|
||||||
|
"9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60",
|
||||||
|
"d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a",
|
||||||
|
"",
|
||||||
|
"e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e06522490155" +
|
||||||
|
"5fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b");
|
||||||
|
|
||||||
|
runSignTest("Ed25519", null,
|
||||||
|
"4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb",
|
||||||
|
"3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c",
|
||||||
|
"72",
|
||||||
|
"92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da" +
|
||||||
|
"085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00");
|
||||||
|
|
||||||
|
runSignTest("Ed25519", null,
|
||||||
|
"c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7",
|
||||||
|
"fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025",
|
||||||
|
"af82",
|
||||||
|
"6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac" +
|
||||||
|
"18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a");
|
||||||
|
|
||||||
|
runSignTest("Ed25519", null,
|
||||||
|
"f5e5767cf153319517630f226876b86c8160cc583bc013744c6bf255f5cc0ee5",
|
||||||
|
"278117fc144c72340f67d0f2316e8386ceffbf2b2428c9c51fef7c597f1d426e",
|
||||||
|
"08b8b2b733424243760fe426a4b54908632110a66c2f6591eabd3345e3e4eb98" +
|
||||||
|
"fa6e264bf09efe12ee50f8f54e9f77b1e355f6c50544e23fb1433ddf73be84d8" +
|
||||||
|
"79de7c0046dc4996d9e773f4bc9efe5738829adb26c81b37c93a1b270b20329d" +
|
||||||
|
"658675fc6ea534e0810a4432826bf58c941efb65d57a338bbd2e26640f89ffbc" +
|
||||||
|
"1a858efcb8550ee3a5e1998bd177e93a7363c344fe6b199ee5d02e82d522c4fe" +
|
||||||
|
"ba15452f80288a821a579116ec6dad2b3b310da903401aa62100ab5d1a36553e" +
|
||||||
|
"06203b33890cc9b832f79ef80560ccb9a39ce767967ed628c6ad573cb116dbef" +
|
||||||
|
"efd75499da96bd68a8a97b928a8bbc103b6621fcde2beca1231d206be6cd9ec7" +
|
||||||
|
"aff6f6c94fcd7204ed3455c68c83f4a41da4af2b74ef5c53f1d8ac70bdcb7ed1" +
|
||||||
|
"85ce81bd84359d44254d95629e9855a94a7c1958d1f8ada5d0532ed8a5aa3fb2" +
|
||||||
|
"d17ba70eb6248e594e1a2297acbbb39d502f1a8c6eb6f1ce22b3de1a1f40cc24" +
|
||||||
|
"554119a831a9aad6079cad88425de6bde1a9187ebb6092cf67bf2b13fd65f270" +
|
||||||
|
"88d78b7e883c8759d2c4f5c65adb7553878ad575f9fad878e80a0c9ba63bcbcc" +
|
||||||
|
"2732e69485bbc9c90bfbd62481d9089beccf80cfe2df16a2cf65bd92dd597b07" +
|
||||||
|
"07e0917af48bbb75fed413d238f5555a7a569d80c3414a8d0859dc65a46128ba" +
|
||||||
|
"b27af87a71314f318c782b23ebfe808b82b0ce26401d2e22f04d83d1255dc51a" +
|
||||||
|
"ddd3b75a2b1ae0784504df543af8969be3ea7082ff7fc9888c144da2af58429e" +
|
||||||
|
"c96031dbcad3dad9af0dcbaaaf268cb8fcffead94f3c7ca495e056a9b47acdb7" +
|
||||||
|
"51fb73e666c6c655ade8297297d07ad1ba5e43f1bca32301651339e22904cc8c" +
|
||||||
|
"42f58c30c04aafdb038dda0847dd988dcda6f3bfd15c4b4c4525004aa06eeff8" +
|
||||||
|
"ca61783aacec57fb3d1f92b0fe2fd1a85f6724517b65e614ad6808d6f6ee34df" +
|
||||||
|
"f7310fdc82aebfd904b01e1dc54b2927094b2db68d6f903b68401adebf5a7e08" +
|
||||||
|
"d78ff4ef5d63653a65040cf9bfd4aca7984a74d37145986780fc0b16ac451649" +
|
||||||
|
"de6188a7dbdf191f64b5fc5e2ab47b57f7f7276cd419c17a3ca8e1b939ae49e4" +
|
||||||
|
"88acba6b965610b5480109c8b17b80e1b7b750dfc7598d5d5011fd2dcc5600a3" +
|
||||||
|
"2ef5b52a1ecc820e308aa342721aac0943bf6686b64b2579376504ccc493d97e" +
|
||||||
|
"6aed3fb0f9cd71a43dd497f01f17c0e2cb3797aa2a2f256656168e6c496afc5f" +
|
||||||
|
"b93246f6b1116398a346f1a641f3b041e989f7914f90cc2c7fff357876e506b5" +
|
||||||
|
"0d334ba77c225bc307ba537152f3f1610e4eafe595f6d9d90d11faa933a15ef1" +
|
||||||
|
"369546868a7f3a45a96768d40fd9d03412c091c6315cf4fde7cb68606937380d" +
|
||||||
|
"b2eaaa707b4c4185c32eddcdd306705e4dc1ffc872eeee475a64dfac86aba41c" +
|
||||||
|
"0618983f8741c5ef68d3a101e8a3b8cac60c905c15fc910840b94c00a0b9d0",
|
||||||
|
"0aab4c900501b3e24d7cdf4663326a3a87df5e4843b2cbdb67cbf6e460fec350" +
|
||||||
|
"aa5371b1508f9f4528ecea23c436d94b5e8fcd4f681e30a6ac00a9704a188a03");
|
||||||
|
|
||||||
|
runSignTest("Ed25519", null,
|
||||||
|
"833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42",
|
||||||
|
"ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf",
|
||||||
|
"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a" +
|
||||||
|
"2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f",
|
||||||
|
"dc2a4459e7369633a52b1bf277839a00201009a3efbf3ecb69bea2186c26b589" +
|
||||||
|
"09351fc9ac90b3ecfdfbc7c66431e0303dca179c138ac17ad9bef1177331a704");
|
||||||
|
|
||||||
|
// Ed25519ctx
|
||||||
|
byte[] context = Convert.hexStringToByteArray("666f6f");
|
||||||
|
runSignTest("Ed25519", new EdDSAParameterSpec(false, context),
|
||||||
|
"0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6",
|
||||||
|
"dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292",
|
||||||
|
"f726936d19c800494e3fdaff20b276a8",
|
||||||
|
"55a4cc2f70a54e04288c5f4cd1e45a7bb520b36292911876cada7323198dd87a" +
|
||||||
|
"8b36950b95130022907a7fb7c4e9b2d5f6cca685a587b4b21f4b888e4e7edb0d");
|
||||||
|
|
||||||
|
context = Convert.hexStringToByteArray("626172");
|
||||||
|
runSignTest("Ed25519", new EdDSAParameterSpec(false, context),
|
||||||
|
"0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6",
|
||||||
|
"dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292",
|
||||||
|
"f726936d19c800494e3fdaff20b276a8",
|
||||||
|
"fc60d5872fc46b3aa69f8b5b4351d5808f92bcc044606db097abab6dbcb1aee3" +
|
||||||
|
"216c48e8b3b66431b5b186d1d28f8ee15a5ca2df6668346291c2043d4eb3e90d");
|
||||||
|
|
||||||
|
context = Convert.hexStringToByteArray("666f6f");
|
||||||
|
runSignTest("Ed25519", new EdDSAParameterSpec(false, context),
|
||||||
|
"0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6",
|
||||||
|
"dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292",
|
||||||
|
"508e9e6882b979fea900f62adceaca35",
|
||||||
|
"8b70c1cc8310e1de20ac53ce28ae6e7207f33c3295e03bb5c0732a1d20dc6490" +
|
||||||
|
"8922a8b052cf99b7c4fe107a5abb5b2c4085ae75890d02df26269d8945f84b0b");
|
||||||
|
|
||||||
|
context = Convert.hexStringToByteArray("666f6f");
|
||||||
|
runSignTest("Ed25519", new EdDSAParameterSpec(false, context),
|
||||||
|
"ab9c2853ce297ddab85c993b3ae14bcad39b2c682beabc27d6d4eb20711d6560",
|
||||||
|
"0f1d1274943b91415889152e893d80e93275a1fc0b65fd71b4b0dda10ad7d772",
|
||||||
|
"f726936d19c800494e3fdaff20b276a8",
|
||||||
|
"21655b5f1aa965996b3f97b3c849eafba922a0a62992f73b3d1b73106a84ad85" +
|
||||||
|
"e9b86a7b6005ea868337ff2d20a7f5fbd4cd10b0be49a68da2b2e0dc0ad8960f");
|
||||||
|
|
||||||
|
// Ed25519ph
|
||||||
|
runSignTest("Ed25519", new EdDSAParameterSpec(true),
|
||||||
|
"833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42",
|
||||||
|
"ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf",
|
||||||
|
"616263",
|
||||||
|
"98a70222f0b8121aa9d30f813d683f809e462b469c7ff87639499bb94e6dae41" +
|
||||||
|
"31f85042463c2a355a2003d062adf5aaa10b8c61e636062aaad11c2a26083406");
|
||||||
|
|
||||||
|
// Ed448
|
||||||
|
runSignTest("Ed448", null,
|
||||||
|
"6c82a562cb808d10d632be89c8513ebf6c929f34ddfa8c9f63c9960ef6e348a3" +
|
||||||
|
"528c8a3fcc2f044e39a3fc5b94492f8f032e7549a20098f95b",
|
||||||
|
"5fd7449b59b461fd2ce787ec616ad46a1da1342485a70e1f8a0ea75d80e96778" +
|
||||||
|
"edf124769b46c7061bd6783df1e50f6cd1fa1abeafe8256180",
|
||||||
|
"",
|
||||||
|
"533a37f6bbe457251f023c0d88f976ae2dfb504a843e34d2074fd823d41a591f" +
|
||||||
|
"2b233f034f628281f2fd7a22ddd47d7828c59bd0a21bfd3980ff0d2028d4b18a" +
|
||||||
|
"9df63e006c5d1c2d345b925d8dc00b4104852db99ac5c7cdda8530a113a0f4db" +
|
||||||
|
"b61149f05a7363268c71d95808ff2e652600");
|
||||||
|
|
||||||
|
runSignTest("Ed448", null,
|
||||||
|
"c4eab05d357007c632f3dbb48489924d552b08fe0c353a0d4a1f00acda2c463a" +
|
||||||
|
"fbea67c5e8d2877c5e3bc397a659949ef8021e954e0a12274e",
|
||||||
|
"43ba28f430cdff456ae531545f7ecd0ac834a55d9358c0372bfa0c6c6798c086" +
|
||||||
|
"6aea01eb00742802b8438ea4cb82169c235160627b4c3a9480",
|
||||||
|
"03",
|
||||||
|
"26b8f91727bd62897af15e41eb43c377efb9c610d48f2335cb0bd0087810f435" +
|
||||||
|
"2541b143c4b981b7e18f62de8ccdf633fc1bf037ab7cd779805e0dbcc0aae1cb" +
|
||||||
|
"cee1afb2e027df36bc04dcecbf154336c19f0af7e0a6472905e799f1953d2a0f" +
|
||||||
|
"f3348ab21aa4adafd1d234441cf807c03a00");
|
||||||
|
|
||||||
|
context = Convert.hexStringToByteArray("666f6f");
|
||||||
|
runSignTest("Ed448", new EdDSAParameterSpec(false, context),
|
||||||
|
"c4eab05d357007c632f3dbb48489924d552b08fe0c353a0d4a1f00acda2c463a" +
|
||||||
|
"fbea67c5e8d2877c5e3bc397a659949ef8021e954e0a12274e",
|
||||||
|
"43ba28f430cdff456ae531545f7ecd0ac834a55d9358c0372bfa0c6c6798c086" +
|
||||||
|
"6aea01eb00742802b8438ea4cb82169c235160627b4c3a9480",
|
||||||
|
"03",
|
||||||
|
"d4f8f6131770dd46f40867d6fd5d5055de43541f8c5e35abbcd001b32a89f7d2" +
|
||||||
|
"151f7647f11d8ca2ae279fb842d607217fce6e042f6815ea000c85741de5" +
|
||||||
|
"c8da1144a6a1aba7f96de42505d7a7298524fda538fccbbb754f578c1cad" +
|
||||||
|
"10d54d0d5428407e85dcbc98a49155c13764e66c3c00");
|
||||||
|
|
||||||
|
runSignTest("Ed448", null,
|
||||||
|
"cd23d24f714274e744343237b93290f511f6425f98e64459ff203e898508" +
|
||||||
|
"3ffdf60500553abc0e05cd02184bdb89c4ccd67e187951267eb328",
|
||||||
|
"dcea9e78f35a1bf3499a831b10b86c90aac01cd84b67a0109b55a36e9328" +
|
||||||
|
"b1e365fce161d71ce7131a543ea4cb5f7e9f1d8b00696447001400",
|
||||||
|
"0c3e544074ec63b0265e0c",
|
||||||
|
"1f0a8888ce25e8d458a21130879b840a9089d999aaba039eaf3e3afa090a09d3" +
|
||||||
|
"89dba82c4ff2ae8ac5cdfb7c55e94d5d961a29fe0109941e00b8dbdeea6d3b05" +
|
||||||
|
"1068df7254c0cdc129cbe62db2dc957dbb47b51fd3f213fb8698f064774250a5" +
|
||||||
|
"028961c9bf8ffd973fe5d5c206492b140e00");
|
||||||
|
|
||||||
|
runSignTest("Ed448", null,
|
||||||
|
"258cdd4ada32ed9c9ff54e63756ae582fb8fab2ac721f2c8e676a72768513d93" +
|
||||||
|
"9f63dddb55609133f29adf86ec9929dccb52c1c5fd2ff7e21b",
|
||||||
|
"3ba16da0c6f2cc1f30187740756f5e798d6bc5fc015d7c63cc9510ee3fd44adc" +
|
||||||
|
"24d8e968b6e46e6f94d19b945361726bd75e149ef09817f580",
|
||||||
|
"64a65f3cdedcdd66811e2915",
|
||||||
|
"7eeeab7c4e50fb799b418ee5e3197ff6bf15d43a14c34389b59dd1a7b1b85b4ae904" +
|
||||||
|
"38aca634bea45e3a2695f1270f07fdcdf7c62b8efeaf00b45c2c96ba457eb1a8" +
|
||||||
|
"bf075a3db28e5c24f6b923ed4ad747c3c9e03c7079efb87cb110d3a99861e720" +
|
||||||
|
"03cbae6d6b8b827e4e6c143064ff3c00");
|
||||||
|
|
||||||
|
runSignTest("Ed448", null,
|
||||||
|
"7ef4e84544236752fbb56b8f31a23a10e42814f5f55ca037cdcc11c64c9a3b29" +
|
||||||
|
"49c1bb60700314611732a6c2fea98eebc0266a11a93970100e",
|
||||||
|
"b3da079b0aa493a5772029f0467baebee5a8112d9d3a22532361da294f7bb381" +
|
||||||
|
"5c5dc59e176b4d9f381ca0938e13c6c07b174be65dfa578e80",
|
||||||
|
"64a65f3cdedcdd66811e2915e7",
|
||||||
|
"6a12066f55331b6c22acd5d5bfc5d71228fbda80ae8dec26bdd306743c5027cb" +
|
||||||
|
"4890810c162c027468675ecf645a83176c0d7323a2ccde2d80efe5a1268e" +
|
||||||
|
"8aca1d6fbc194d3f77c44986eb4ab4177919ad8bec33eb47bbb5fc6e2819" +
|
||||||
|
"6fd1caf56b4e7e0ba5519234d047155ac727a1053100");
|
||||||
|
|
||||||
|
runSignTest("Ed448", null,
|
||||||
|
"d65df341ad13e008567688baedda8e9dcdc17dc024974ea5b4227b6530e339bf" +
|
||||||
|
"f21f99e68ca6968f3cca6dfe0fb9f4fab4fa135d5542ea3f01",
|
||||||
|
"df9705f58edbab802c7f8363cfe5560ab1c6132c20a9f1dd163483a26f8ac53a" +
|
||||||
|
"39d6808bf4a1dfbd261b099bb03b3fb50906cb28bd8a081f00",
|
||||||
|
"bd0f6a3747cd561bdddf4640a332461a4a30a12a434cd0bf40d766d9c6d458e5" +
|
||||||
|
"512204a30c17d1f50b5079631f64eb3112182da3005835461113718d1a5ef944",
|
||||||
|
"554bc2480860b49eab8532d2a533b7d578ef473eeb58c98bb2d0e1ce488a98b1" +
|
||||||
|
"8dfde9b9b90775e67f47d4a1c3482058efc9f40d2ca033a0801b63d45b3b722e" +
|
||||||
|
"f552bad3b4ccb667da350192b61c508cf7b6b5adadc2c8d9a446ef003fb05cba" +
|
||||||
|
"5f30e88e36ec2703b349ca229c2670833900");
|
||||||
|
|
||||||
|
runSignTest("Ed448", new EdDSAParameterSpec(false),
|
||||||
|
"2ec5fe3c17045abdb136a5e6a913e32ab75ae68b53d2fc149b77e504132d3756" +
|
||||||
|
"9b7e766ba74a19bd6162343a21c8590aa9cebca9014c636df5",
|
||||||
|
"79756f014dcfe2079f5dd9e718be4171e2ef2486a08f25186f6bff43a9936b9b" +
|
||||||
|
"fe12402b08ae65798a3d81e22e9ec80e7690862ef3d4ed3a00",
|
||||||
|
"15777532b0bdd0d1389f636c5f6b9ba734c90af572877e2d272dd078aa1e567c" +
|
||||||
|
"fa80e12928bb542330e8409f3174504107ecd5efac61ae7504dabe2a602ede89" +
|
||||||
|
"e5cca6257a7c77e27a702b3ae39fc769fc54f2395ae6a1178cab4738e543072f" +
|
||||||
|
"c1c177fe71e92e25bf03e4ecb72f47b64d0465aaea4c7fad372536c8ba516a60" +
|
||||||
|
"39c3c2a39f0e4d832be432dfa9a706a6e5c7e19f397964ca4258002f7c0541b5" +
|
||||||
|
"90316dbc5622b6b2a6fe7a4abffd96105eca76ea7b98816af0748c10df048ce0" +
|
||||||
|
"12d901015a51f189f3888145c03650aa23ce894c3bd889e030d565071c59f409" +
|
||||||
|
"a9981b51878fd6fc110624dcbcde0bf7a69ccce38fabdf86f3bef6044819de11",
|
||||||
|
"c650ddbb0601c19ca11439e1640dd931f43c518ea5bea70d3dcde5f4191fe53f" +
|
||||||
|
"00cf966546b72bcc7d58be2b9badef28743954e3a44a23f880e8d4f1cfce2d7a" +
|
||||||
|
"61452d26da05896f0a50da66a239a8a188b6d825b3305ad77b73fbac0836ecc6" +
|
||||||
|
"0987fd08527c1a8e80d5823e65cafe2a3d00");
|
||||||
|
|
||||||
|
runSignTest("Ed448", null,
|
||||||
|
"872d093780f5d3730df7c212664b37b8a0f24f56810daa8382cd4f" +
|
||||||
|
"a3f77634ec44dc54f1c2ed9bea86fafb7632d8be199ea165f5ad55dd9ce8",
|
||||||
|
"a81b2e8a70a5ac94ffdbcc9badfc3feb0801f258578bb114ad44ece" +
|
||||||
|
"1ec0e799da08effb81c5d685c0c56f64eecaef8cdf11cc38737838cf400",
|
||||||
|
"6ddf802e1aae4986935f7f981ba3f0351d6273c0a0c22c9c0e8339168e675412" +
|
||||||
|
"a3debfaf435ed651558007db4384b650fcc07e3b586a27a4f7a00ac8a6fec2cd" +
|
||||||
|
"86ae4bf1570c41e6a40c931db27b2faa15a8cedd52cff7362c4e6e23daec0fbc" +
|
||||||
|
"3a79b6806e316efcc7b68119bf46bc76a26067a53f296dafdbdc11c77f7777e9" +
|
||||||
|
"72660cf4b6a9b369a6665f02e0cc9b6edfad136b4fabe723d2813db3136cfde9" +
|
||||||
|
"b6d044322fee2947952e031b73ab5c603349b307bdc27bc6cb8b8bbd7bd32321" +
|
||||||
|
"9b8033a581b59eadebb09b3c4f3d2277d4f0343624acc817804728b25ab79717" +
|
||||||
|
"2b4c5c21a22f9c7839d64300232eb66e53f31c723fa37fe387c7d3e50bdf9813" +
|
||||||
|
"a30e5bb12cf4cd930c40cfb4e1fc622592a49588794494d56d24ea4b40c89fc0" +
|
||||||
|
"596cc9ebb961c8cb10adde976a5d602b1c3f85b9b9a001ed3c6a4d3b1437f520" +
|
||||||
|
"96cd1956d042a597d561a596ecd3d1735a8d570ea0ec27225a2c4aaff26306d1" +
|
||||||
|
"526c1af3ca6d9cf5a2c98f47e1c46db9a33234cfd4d81f2c98538a09ebe76998" +
|
||||||
|
"d0d8fd25997c7d255c6d66ece6fa56f11144950f027795e653008f4bd7ca2dee" +
|
||||||
|
"85d8e90f3dc315130ce2a00375a318c7c3d97be2c8ce5b6db41a6254ff264fa6" +
|
||||||
|
"155baee3b0773c0f497c573f19bb4f4240281f0b1f4f7be857a4e59d416c06b4" +
|
||||||
|
"c50fa09e1810ddc6b1467baeac5a3668d11b6ecaa901440016f389f80acc4db9" +
|
||||||
|
"77025e7f5924388c7e340a732e554440e76570f8dd71b7d640b3450d1fd5f041" +
|
||||||
|
"0a18f9a3494f707c717b79b4bf75c98400b096b21653b5d217cf3565c9597456" +
|
||||||
|
"f70703497a078763829bc01bb1cbc8fa04eadc9a6e3f6699587a9e75c94e5bab" +
|
||||||
|
"0036e0b2e711392cff0047d0d6b05bd2a588bc109718954259f1d86678a579a3" +
|
||||||
|
"120f19cfb2963f177aeb70f2d4844826262e51b80271272068ef5b3856fa8535" +
|
||||||
|
"aa2a88b2d41f2a0e2fda7624c2850272ac4a2f561f8f2f7a318bfd5caf969614" +
|
||||||
|
"9e4ac824ad3460538fdc25421beec2cc6818162d06bbed0c40a387192349db67" +
|
||||||
|
"a118bada6cd5ab0140ee273204f628aad1c135f770279a651e24d8c14d75a605" +
|
||||||
|
"9d76b96a6fd857def5e0b354b27ab937a5815d16b5fae407ff18222c6d1ed263" +
|
||||||
|
"be68c95f32d908bd895cd76207ae726487567f9a67dad79abec316f683b17f2d" +
|
||||||
|
"02bf07e0ac8b5bc6162cf94697b3c27cd1fea49b27f23ba2901871962506520c" +
|
||||||
|
"392da8b6ad0d99f7013fbc06c2c17a569500c8a7696481c1cd33e9b14e40b82e" +
|
||||||
|
"79a5f5db82571ba97bae3ad3e0479515bb0e2b0f3bfcd1fd33034efc6245eddd" +
|
||||||
|
"7ee2086ddae2600d8ca73e214e8c2b0bdb2b047c6a464a562ed77b73d2d841c4" +
|
||||||
|
"b34973551257713b753632efba348169abc90a68f42611a40126d7cb21b58695" +
|
||||||
|
"568186f7e569d2ff0f9e745d0487dd2eb997cafc5abf9dd102e62ff66cba87",
|
||||||
|
"e301345a41a39a4d72fff8df69c98075a0cc082b802fc9b2b6bc503f926b65bd" +
|
||||||
|
"df7f4c8f1cb49f6396afc8a70abe6d8aef0db478d4c6b2970076c6a0484fe76d" +
|
||||||
|
"76b3a97625d79f1ce240e7c576750d295528286f719b413de9ada3e8eb78ed57" +
|
||||||
|
"3603ce30d8bb761785dc30dbc320869e1a00");
|
||||||
|
|
||||||
|
runSignTest("Ed448", new EdDSAParameterSpec(true),
|
||||||
|
"833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901" +
|
||||||
|
"b96dca3d42ef7822e0d5104127dc05d6dbefde69e3ab2cec7c867c6e2c49",
|
||||||
|
"259b71c19f83ef77a7abd26524cbdb3161b590a48f7d17de3ee0ba9" +
|
||||||
|
"c52beb743c09428a131d6b1b57303d90d8132c276d5ed3d5d01c0f53880",
|
||||||
|
"616263",
|
||||||
|
"822f6901f7480f3d5f562c592994d9693602875614483256505600bbc281ae38" +
|
||||||
|
"1f54d6bce2ea911574932f52a4e6cadd78769375ec3ffd1b801a0d9b3f4030cd" +
|
||||||
|
"433964b6457ea39476511214f97469b57dd32dbc560a9a94d00bff07620464a3" +
|
||||||
|
"ad203df7dc7ce360c3cd3696d9d9fab90f00");
|
||||||
|
|
||||||
|
runSignTest("Ed448", new EdDSAParameterSpec(true, context),
|
||||||
|
"833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42" +
|
||||||
|
"ef7822e0d5104127dc05d6dbefde69e3ab2cec7c867c6e2c49",
|
||||||
|
"259b71c19f83ef77a7abd26524cbdb3161b590a48f7d17de3ee0ba9c52beb743" +
|
||||||
|
"c09428a131d6b1b57303d90d8132c276d5ed3d5d01c0f53880",
|
||||||
|
"616263",
|
||||||
|
"c32299d46ec8ff02b54540982814dce9a05812f81962b649d528095916a2aa48" +
|
||||||
|
"1065b1580423ef927ecf0af5888f90da0f6a9a85ad5dc3f280d91224ba9911a3" +
|
||||||
|
"653d00e484e2ce232521481c8658df304bb7745a73514cdb9bf3e15784ab7128" +
|
||||||
|
"4f8d0704a608c54a6b62d97beb511d132100");
|
||||||
|
|
||||||
|
System.out.println("All test vectors passed");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void runSignTest(String algorithm,
|
||||||
|
AlgorithmParameterSpec params, String privateKey, String publicKey,
|
||||||
|
String message, String signature) throws Exception {
|
||||||
|
|
||||||
|
byte[] privKeyBytes = Convert.hexStringToByteArray(privateKey);
|
||||||
|
EdECPoint pubKeyPoint = Convert.hexStringToEdPoint(publicKey);
|
||||||
|
byte[] msgBytes = Convert.hexStringToByteArray(message);
|
||||||
|
byte[] computedSig;
|
||||||
|
|
||||||
|
NamedParameterSpec namedSpec = new NamedParameterSpec(algorithm);
|
||||||
|
EdECPrivateKeySpec privKeySpec =
|
||||||
|
new EdECPrivateKeySpec(namedSpec, privKeyBytes);
|
||||||
|
KeyFactory kf = KeyFactory.getInstance(algorithm);
|
||||||
|
PrivateKey privKey = kf.generatePrivate(privKeySpec);
|
||||||
|
Signature sig = Signature.getInstance(algorithm);
|
||||||
|
if (params != null) {
|
||||||
|
sig.setParameter(params);
|
||||||
|
}
|
||||||
|
sig.initSign(privKey);
|
||||||
|
sig.update(msgBytes);
|
||||||
|
computedSig = sig.sign();
|
||||||
|
if (!Arrays.equals(computedSig,
|
||||||
|
Convert.hexStringToByteArray(signature))) {
|
||||||
|
throw new RuntimeException("Incorrect signature");
|
||||||
|
}
|
||||||
|
|
||||||
|
// test verification
|
||||||
|
sig = Signature.getInstance(algorithm);
|
||||||
|
if (params != null) {
|
||||||
|
sig.setParameter(params);
|
||||||
|
}
|
||||||
|
EdECPublicKeySpec pubKeySpec =
|
||||||
|
new EdECPublicKeySpec(namedSpec, pubKeyPoint);
|
||||||
|
PublicKey pubKey = kf.generatePublic(pubKeySpec);
|
||||||
|
sig.initVerify(pubKey);
|
||||||
|
sig.update(msgBytes);
|
||||||
|
if (!sig.verify(computedSig)) {
|
||||||
|
throw new RuntimeException("Signature did not verify");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static void runBasicTests() throws Exception {
|
||||||
|
runBasicTest("EdDSA", null);
|
||||||
|
|
||||||
|
runBasicTest("EdDSA", 255);
|
||||||
|
runBasicTest("EdDSA", "Ed25519");
|
||||||
|
runBasicTest("Ed25519", null);
|
||||||
|
runBasicTest("1.3.101.112", null);
|
||||||
|
runBasicTest("OID.1.3.101.112", null);
|
||||||
|
|
||||||
|
runBasicTest("EdDSA", 448);
|
||||||
|
runBasicTest("EdDSA", "Ed448");
|
||||||
|
runBasicTest("Ed448", null);
|
||||||
|
runBasicTest("1.3.101.113", null);
|
||||||
|
runBasicTest("OID.1.3.101.113", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void runBasicTest(String name, Object param)
|
||||||
|
throws Exception {
|
||||||
|
|
||||||
|
KeyPairGenerator kpg = KeyPairGenerator.getInstance(name);
|
||||||
|
if (param instanceof Integer) {
|
||||||
|
kpg.initialize((Integer) param, random);
|
||||||
|
} else if (param instanceof String) {
|
||||||
|
kpg.initialize(new NamedParameterSpec((String) param), random);
|
||||||
|
}
|
||||||
|
KeyPair kp = kpg.generateKeyPair();
|
||||||
|
|
||||||
|
Signature sig = Signature.getInstance(name);
|
||||||
|
sig.initSign(kp.getPrivate());
|
||||||
|
byte[] testMessage = new byte[1024];
|
||||||
|
random.nextBytes(testMessage);
|
||||||
|
sig.update(testMessage);
|
||||||
|
byte[] msgSig = sig.sign();
|
||||||
|
|
||||||
|
// sign again, should return false
|
||||||
|
byte[] x = sig.sign();
|
||||||
|
if (Arrays.compare(msgSig, x) == 0) {
|
||||||
|
throw new RuntimeException("Second sign identical, didn't reset");
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify the signature
|
||||||
|
sig.initVerify(kp.getPublic());
|
||||||
|
sig.update(testMessage);
|
||||||
|
if (!sig.verify(msgSig)) {
|
||||||
|
throw new RuntimeException("Valid signature did not verify");
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify again, should return false
|
||||||
|
if (sig.verify(msgSig)) {
|
||||||
|
throw new RuntimeException("Second verify succeeded, didn't reset");
|
||||||
|
}
|
||||||
|
|
||||||
|
// try verifying an incorrect signature
|
||||||
|
testMessage[0] ^= (byte) 0x01;
|
||||||
|
sig.update(testMessage);
|
||||||
|
if (sig.verify(msgSig)) {
|
||||||
|
throw new RuntimeException("Invalid signature verified");
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyFactory kf = KeyFactory.getInstance(name);
|
||||||
|
// Test with X509 and PKCS8 key specs
|
||||||
|
X509EncodedKeySpec pubSpec =
|
||||||
|
kf.getKeySpec(kp.getPublic(), X509EncodedKeySpec.class);
|
||||||
|
PKCS8EncodedKeySpec priSpec =
|
||||||
|
kf.getKeySpec(kp.getPrivate(), PKCS8EncodedKeySpec.class);
|
||||||
|
|
||||||
|
PublicKey pubKey = kf.generatePublic(pubSpec);
|
||||||
|
PrivateKey priKey = kf.generatePrivate(priSpec);
|
||||||
|
|
||||||
|
sig.initSign(priKey);
|
||||||
|
sig.update(testMessage);
|
||||||
|
msgSig = sig.sign();
|
||||||
|
sig.initVerify(pubKey);
|
||||||
|
sig.update(testMessage);
|
||||||
|
if (!sig.verify(msgSig)) {
|
||||||
|
throw new RuntimeException("Valid signature did not verify");
|
||||||
|
}
|
||||||
|
|
||||||
|
// test with EdEC key specs
|
||||||
|
EdECPublicKeySpec edPublic =
|
||||||
|
kf.getKeySpec(kp.getPublic(), EdECPublicKeySpec.class);
|
||||||
|
EdECPrivateKeySpec edPrivate =
|
||||||
|
kf.getKeySpec(kp.getPrivate(), EdECPrivateKeySpec.class);
|
||||||
|
PublicKey pubKey2 = kf.generatePublic(edPublic);
|
||||||
|
PrivateKey priKey2 = kf.generatePrivate(edPrivate);
|
||||||
|
sig.initSign(priKey2);
|
||||||
|
sig.update(testMessage);
|
||||||
|
msgSig = sig.sign();
|
||||||
|
sig.initVerify(pubKey2);
|
||||||
|
sig.update(testMessage);
|
||||||
|
if (!sig.verify(msgSig)) {
|
||||||
|
throw new RuntimeException("Valid signature did not verify");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ensure that SunEC rejects parameters/points for the wrong curve
|
||||||
|
* when the algorithm ID for a specific curve is specified.
|
||||||
|
*/
|
||||||
|
private static void runCurveMixTest() throws Exception {
|
||||||
|
runCurveMixTest("SunEC", "Ed25519", 448);
|
||||||
|
runCurveMixTest("SunEC", "Ed25519", "Ed448");
|
||||||
|
runCurveMixTest("SunEC", "Ed448", 255);
|
||||||
|
runCurveMixTest("SunEC", "Ed448", "Ed25519");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void runCurveMixTest(String providerName, String name,
|
||||||
|
Object param) throws Exception {
|
||||||
|
|
||||||
|
KeyPairGenerator kpg = KeyPairGenerator.getInstance(name,
|
||||||
|
providerName);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (param instanceof Integer) {
|
||||||
|
kpg.initialize((Integer) param);
|
||||||
|
} else if (param instanceof String) {
|
||||||
|
kpg.initialize(new NamedParameterSpec((String) param));
|
||||||
|
}
|
||||||
|
throw new RuntimeException(name + " KeyPairGenerator accepted "
|
||||||
|
+ param.toString() + " parameters");
|
||||||
|
} catch (InvalidParameterException ex) {
|
||||||
|
if (param instanceof String) {
|
||||||
|
throw new RuntimeException(
|
||||||
|
"InvalidAlgorithmParameterException expected", ex);
|
||||||
|
}
|
||||||
|
// expected
|
||||||
|
|
||||||
|
} catch (InvalidAlgorithmParameterException ex) {
|
||||||
|
if (param instanceof Integer) {
|
||||||
|
throw new RuntimeException("InvalidParameterException expected",
|
||||||
|
ex);
|
||||||
|
}
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
|
||||||
|
// the rest of the test uses the parameter as an algorithm name to
|
||||||
|
// produce keys
|
||||||
|
if (param instanceof Integer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String otherName = (String) param;
|
||||||
|
KeyPairGenerator otherKpg = KeyPairGenerator.getInstance(otherName,
|
||||||
|
providerName);
|
||||||
|
KeyPair otherKp = otherKpg.generateKeyPair();
|
||||||
|
|
||||||
|
// ensure the KeyFactory rejects incorrect keys
|
||||||
|
KeyFactory kf = KeyFactory.getInstance(name, providerName);
|
||||||
|
try {
|
||||||
|
kf.getKeySpec(otherKp.getPublic(), EdECPublicKeySpec.class);
|
||||||
|
throw new RuntimeException(name + " KeyFactory accepted "
|
||||||
|
+ param.toString() + " key");
|
||||||
|
} catch (InvalidKeySpecException ex) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
kf.getKeySpec(otherKp.getPrivate(), EdECPrivateKeySpec.class);
|
||||||
|
throw new RuntimeException(name + " KeyFactory accepted "
|
||||||
|
+ param.toString() + " key");
|
||||||
|
} catch (InvalidKeySpecException ex) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
kf.translateKey(otherKp.getPublic());
|
||||||
|
throw new RuntimeException(name + " KeyFactory accepted "
|
||||||
|
+ param.toString() + " key");
|
||||||
|
} catch (InvalidKeyException ex) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
kf.translateKey(otherKp.getPrivate());
|
||||||
|
throw new RuntimeException(name + " KeyFactory accepted "
|
||||||
|
+ param.toString() + " key");
|
||||||
|
} catch (InvalidKeyException ex) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyFactory otherKf = KeyFactory.getInstance(otherName, providerName);
|
||||||
|
EdECPublicKeySpec otherPubSpec = otherKf.getKeySpec(otherKp.getPublic(),
|
||||||
|
EdECPublicKeySpec.class);
|
||||||
|
try {
|
||||||
|
kf.generatePublic(otherPubSpec);
|
||||||
|
throw new RuntimeException(name + " KeyFactory accepted "
|
||||||
|
+ param.toString() + " key");
|
||||||
|
} catch (InvalidKeySpecException ex) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
EdECPrivateKeySpec otherPriSpec =
|
||||||
|
otherKf.getKeySpec(otherKp.getPrivate(), EdECPrivateKeySpec.class);
|
||||||
|
try {
|
||||||
|
kf.generatePrivate(otherPriSpec);
|
||||||
|
throw new RuntimeException(name + " KeyFactory accepted "
|
||||||
|
+ param.toString() + " key");
|
||||||
|
} catch (InvalidKeySpecException ex) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure the Signature rejects incorrect keys
|
||||||
|
Signature sig = Signature.getInstance(name, providerName);
|
||||||
|
try {
|
||||||
|
sig.initSign(otherKp.getPrivate());
|
||||||
|
throw new RuntimeException(name + " Signature accepted "
|
||||||
|
+ param.toString() + " signing key");
|
||||||
|
} catch (InvalidKeyException ex) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
sig.initVerify(otherKp.getPublic());
|
||||||
|
throw new RuntimeException(name + " Signature accepted "
|
||||||
|
+ param.toString() + " verification key");
|
||||||
|
} catch (InvalidKeyException ex) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
291
test/jdk/sun/security/ec/ed/TestEdOps.java
Normal file
291
test/jdk/sun/security/ec/ed/TestEdOps.java
Normal file
|
@ -0,0 +1,291 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8166597
|
||||||
|
* @summary Test EdDSA basic operations
|
||||||
|
* @library /test/lib
|
||||||
|
* @build jdk.test.lib.Convert
|
||||||
|
* @modules java.base/sun.security.provider
|
||||||
|
* java.base/sun.security.util
|
||||||
|
* java.base/sun.security.util.math
|
||||||
|
* java.base/sun.security.util.math.intpoly
|
||||||
|
* jdk.crypto.ec/sun.security.ec.ed
|
||||||
|
* @run main TestEdOps
|
||||||
|
*/
|
||||||
|
|
||||||
|
import sun.security.ec.ed.*;
|
||||||
|
import java.security.*;
|
||||||
|
import java.security.spec.*;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import sun.security.provider.SHAKE256;
|
||||||
|
import jdk.test.lib.Convert;
|
||||||
|
|
||||||
|
public class TestEdOps {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
|
||||||
|
testShake();
|
||||||
|
testVectors();
|
||||||
|
testRandom(1000);
|
||||||
|
testInvalidPoints();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testShake() {
|
||||||
|
|
||||||
|
runShakeTest(32, "765db6ab3af389b8c775c8eb99fe72",
|
||||||
|
"ccb6564a655c94d714f80b9f8de9e2610c4478778eac1b9256237dbf90e50581");
|
||||||
|
|
||||||
|
runShakeTest(32,
|
||||||
|
"0e3dcd346c68bc5b5cafe3342a7e0e29272e42fba12a51081251abca989c77a1" +
|
||||||
|
"a501e2",
|
||||||
|
"c934ab7f2148da5ca2ce948432fa72be49420f10e3dbc1906016773d9819cff4");
|
||||||
|
|
||||||
|
runShakeTest(32,
|
||||||
|
"7e4c74f480e60565fe39e483b5204e24753841dec9ef3ec0dadd4e3f91584373" +
|
||||||
|
"fc424084f3267b5ffb8342ad6a683c05cc41f26086f18dceb921e1",
|
||||||
|
"a6450836c02f8fdfe841fbcb4b4fc7dca9bd56019b92582095ee5d11eca45fa0");
|
||||||
|
|
||||||
|
System.out.println("SHAKE256 tests passed");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void runShakeTest(int outputLen, String msg, String digest) {
|
||||||
|
byte[] msgBytes = Convert.hexStringToByteArray(msg);
|
||||||
|
byte[] digestBytes = Convert.hexStringToByteArray(digest);
|
||||||
|
SHAKE256 md = new SHAKE256(outputLen);
|
||||||
|
md.update(msgBytes, 0, msgBytes.length);
|
||||||
|
byte[] computed = md.digest();
|
||||||
|
if (!Arrays.equals(digestBytes, computed)) {
|
||||||
|
throw new RuntimeException("hash is incorrect");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testVectors() throws Exception {
|
||||||
|
EdDSAParameters ed25519Params = EdDSAParameters.get(
|
||||||
|
RuntimeException::new, NamedParameterSpec.ED25519);
|
||||||
|
EdDSAOperations ops = new EdDSAOperations(ed25519Params);
|
||||||
|
|
||||||
|
runSignTest(ops,
|
||||||
|
"9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60",
|
||||||
|
"d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a",
|
||||||
|
"",
|
||||||
|
"e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e06522490155" +
|
||||||
|
"5fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b");
|
||||||
|
|
||||||
|
runSignTest(ops,
|
||||||
|
"4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb",
|
||||||
|
"3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c",
|
||||||
|
"72",
|
||||||
|
"92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da" +
|
||||||
|
"085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00");
|
||||||
|
|
||||||
|
runSignTest(ops,
|
||||||
|
"c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7",
|
||||||
|
"fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025",
|
||||||
|
"af82",
|
||||||
|
"6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac" +
|
||||||
|
"18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a");
|
||||||
|
|
||||||
|
runSignTest(ops,
|
||||||
|
"f5e5767cf153319517630f226876b86c8160cc583bc013744c6bf255f5cc0ee5",
|
||||||
|
"278117fc144c72340f67d0f2316e8386ceffbf2b2428c9c51fef7c597f1d426e",
|
||||||
|
"08b8b2b733424243760fe426a4b54908632110a66c2f6591eabd3345e3e4eb98" +
|
||||||
|
"fa6e264bf09efe12ee50f8f54e9f77b1e355f6c50544e23fb1433ddf73be84d8" +
|
||||||
|
"79de7c0046dc4996d9e773f4bc9efe5738829adb26c81b37c93a1b270b20329d" +
|
||||||
|
"658675fc6ea534e0810a4432826bf58c941efb65d57a338bbd2e26640f89ffbc" +
|
||||||
|
"1a858efcb8550ee3a5e1998bd177e93a7363c344fe6b199ee5d02e82d522c4fe" +
|
||||||
|
"ba15452f80288a821a579116ec6dad2b3b310da903401aa62100ab5d1a36553e" +
|
||||||
|
"06203b33890cc9b832f79ef80560ccb9a39ce767967ed628c6ad573cb116dbef" +
|
||||||
|
"efd75499da96bd68a8a97b928a8bbc103b6621fcde2beca1231d206be6cd9ec7" +
|
||||||
|
"aff6f6c94fcd7204ed3455c68c83f4a41da4af2b74ef5c53f1d8ac70bdcb7ed1" +
|
||||||
|
"85ce81bd84359d44254d95629e9855a94a7c1958d1f8ada5d0532ed8a5aa3fb2" +
|
||||||
|
"d17ba70eb6248e594e1a2297acbbb39d502f1a8c6eb6f1ce22b3de1a1f40cc24" +
|
||||||
|
"554119a831a9aad6079cad88425de6bde1a9187ebb6092cf67bf2b13fd65f270" +
|
||||||
|
"88d78b7e883c8759d2c4f5c65adb7553878ad575f9fad878e80a0c9ba63bcbcc" +
|
||||||
|
"2732e69485bbc9c90bfbd62481d9089beccf80cfe2df16a2cf65bd92dd597b07" +
|
||||||
|
"07e0917af48bbb75fed413d238f5555a7a569d80c3414a8d0859dc65a46128ba" +
|
||||||
|
"b27af87a71314f318c782b23ebfe808b82b0ce26401d2e22f04d83d1255dc51a" +
|
||||||
|
"ddd3b75a2b1ae0784504df543af8969be3ea7082ff7fc9888c144da2af58429e" +
|
||||||
|
"c96031dbcad3dad9af0dcbaaaf268cb8fcffead94f3c7ca495e056a9b47acdb7" +
|
||||||
|
"51fb73e666c6c655ade8297297d07ad1ba5e43f1bca32301651339e22904cc8c" +
|
||||||
|
"42f58c30c04aafdb038dda0847dd988dcda6f3bfd15c4b4c4525004aa06eeff8" +
|
||||||
|
"ca61783aacec57fb3d1f92b0fe2fd1a85f6724517b65e614ad6808d6f6ee34df" +
|
||||||
|
"f7310fdc82aebfd904b01e1dc54b2927094b2db68d6f903b68401adebf5a7e08" +
|
||||||
|
"d78ff4ef5d63653a65040cf9bfd4aca7984a74d37145986780fc0b16ac451649" +
|
||||||
|
"de6188a7dbdf191f64b5fc5e2ab47b57f7f7276cd419c17a3ca8e1b939ae49e4" +
|
||||||
|
"88acba6b965610b5480109c8b17b80e1b7b750dfc7598d5d5011fd2dcc5600a3" +
|
||||||
|
"2ef5b52a1ecc820e308aa342721aac0943bf6686b64b2579376504ccc493d97e" +
|
||||||
|
"6aed3fb0f9cd71a43dd497f01f17c0e2cb3797aa2a2f256656168e6c496afc5f" +
|
||||||
|
"b93246f6b1116398a346f1a641f3b041e989f7914f90cc2c7fff357876e506b5" +
|
||||||
|
"0d334ba77c225bc307ba537152f3f1610e4eafe595f6d9d90d11faa933a15ef1" +
|
||||||
|
"369546868a7f3a45a96768d40fd9d03412c091c6315cf4fde7cb68606937380d" +
|
||||||
|
"b2eaaa707b4c4185c32eddcdd306705e4dc1ffc872eeee475a64dfac86aba41c" +
|
||||||
|
"0618983f8741c5ef68d3a101e8a3b8cac60c905c15fc910840b94c00a0b9d0",
|
||||||
|
"0aab4c900501b3e24d7cdf4663326a3a87df5e4843b2cbdb67cbf6e460fec350" +
|
||||||
|
"aa5371b1508f9f4528ecea23c436d94b5e8fcd4f681e30a6ac00a9704a188a03");
|
||||||
|
|
||||||
|
runSignTest(ops,
|
||||||
|
"833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42",
|
||||||
|
"ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf",
|
||||||
|
"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a" +
|
||||||
|
"2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f",
|
||||||
|
"dc2a4459e7369633a52b1bf277839a00201009a3efbf3ecb69bea2186c26b589" +
|
||||||
|
"09351fc9ac90b3ecfdfbc7c66431e0303dca179c138ac17ad9bef1177331a704");
|
||||||
|
|
||||||
|
|
||||||
|
EdDSAParameters ed448Params = EdDSAParameters.get(RuntimeException::new,
|
||||||
|
NamedParameterSpec.ED448);
|
||||||
|
EdDSAOperations ed448Ops = new EdDSAOperations(ed448Params);
|
||||||
|
|
||||||
|
runSignTest(ed448Ops,
|
||||||
|
"c4eab05d357007c632f3dbb48489924d552b08fe0c353a0d4a1f00acda2c463a" +
|
||||||
|
"fbea67c5e8d2877c5e3bc397a659949ef8021e954e0a12274e",
|
||||||
|
"43ba28f430cdff456ae531545f7ecd0ac834a55d9358c0372bfa0c6c6798c086" +
|
||||||
|
"6aea01eb00742802b8438ea4cb82169c235160627b4c3a9480",
|
||||||
|
"03",
|
||||||
|
"26b8f91727bd62897af15e41eb43c377efb9c610d48f2335cb0bd0087810f435" +
|
||||||
|
"2541b143c4b981b7e18f62de8ccdf633fc1bf037ab7cd779805e0dbcc0aae1cb" +
|
||||||
|
"cee1afb2e027df36bc04dcecbf154336c19f0af7e0a6472905e799f1953d2a0f" +
|
||||||
|
"f3348ab21aa4adafd1d234441cf807c03a00");
|
||||||
|
|
||||||
|
System.out.println("All test vectors passed");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void runSignTest(EdDSAOperations ops, String privateKey,
|
||||||
|
String publicKey, String message,
|
||||||
|
String signature) throws Exception {
|
||||||
|
|
||||||
|
EdDSAParameterSpec sigParams = new EdDSAParameterSpec(false);
|
||||||
|
|
||||||
|
byte[] privKeyBytes = Convert.hexStringToByteArray(privateKey);
|
||||||
|
byte[] pubKeyBytes = Convert.hexStringToByteArray(publicKey);
|
||||||
|
byte[] msgBytes = Convert.hexStringToByteArray(message);
|
||||||
|
byte[] computedSig = ops.sign(sigParams, privKeyBytes, msgBytes);
|
||||||
|
if (!Arrays.equals(computedSig,
|
||||||
|
Convert.hexStringToByteArray(signature))) {
|
||||||
|
throw new RuntimeException("Incorrect signature: " +
|
||||||
|
Convert.byteArrayToHexString(computedSig) + " != " + signature);
|
||||||
|
}
|
||||||
|
// Test public key computation
|
||||||
|
EdECPoint pubPoint = ops.computePublic(privKeyBytes);
|
||||||
|
EdDSAPublicKeyImpl pubKey =
|
||||||
|
new EdDSAPublicKeyImpl(ops.getParameters(), pubPoint);
|
||||||
|
byte[] computedPubKey = pubKey.getEncodedPoint();
|
||||||
|
if (!Arrays.equals(computedPubKey, pubKeyBytes)) {
|
||||||
|
throw new RuntimeException("Incorrect public key");
|
||||||
|
}
|
||||||
|
|
||||||
|
// test verification
|
||||||
|
ops.verify(sigParams, pubKeyBytes, msgBytes, computedSig);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testRandom(int count) throws Exception {
|
||||||
|
|
||||||
|
EdDSAParameterSpec sigParams = new EdDSAParameterSpec(false);
|
||||||
|
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
|
||||||
|
random.setSeed(1);
|
||||||
|
|
||||||
|
EdDSAParameters params = EdDSAParameters.get(RuntimeException::new,
|
||||||
|
NamedParameterSpec.ED25519);
|
||||||
|
EdDSAOperations ops = new EdDSAOperations(params);
|
||||||
|
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
byte[] privKey = ops.generatePrivate(random);
|
||||||
|
byte[] message = new byte[1024];
|
||||||
|
random.nextBytes(message);
|
||||||
|
byte[] sig = ops.sign(sigParams, privKey, message);
|
||||||
|
|
||||||
|
EdECPoint pubKeyPoint = ops.computePublic(privKey);
|
||||||
|
EdDSAPublicKeyImpl pubKey =
|
||||||
|
new EdDSAPublicKeyImpl(params, pubKeyPoint);
|
||||||
|
byte[] encodedPubKey = pubKey.getEncodedPoint();
|
||||||
|
if (!ops.verify(sigParams, encodedPubKey, message, sig)) {
|
||||||
|
throw new RuntimeException("signature did not verify");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long endTime = System.currentTimeMillis();
|
||||||
|
double millisPerIter = (double) (endTime - startTime) / count;
|
||||||
|
System.out.println("Time per keygen+sign+verify: " +
|
||||||
|
millisPerIter + " ms");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testInvalidPoints() throws Exception {
|
||||||
|
|
||||||
|
// Ed25519
|
||||||
|
|
||||||
|
// incorrect length
|
||||||
|
testInvalidPoint(NamedParameterSpec.ED25519, "");
|
||||||
|
testInvalidPoint(NamedParameterSpec.ED25519, "ffffff");
|
||||||
|
testInvalidPoint(NamedParameterSpec.ED25519,
|
||||||
|
"abd75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f70751" +
|
||||||
|
"1a");
|
||||||
|
// y value too large
|
||||||
|
testInvalidPoint(NamedParameterSpec.ED25519,
|
||||||
|
"8ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe");
|
||||||
|
// not square
|
||||||
|
testInvalidPoint(NamedParameterSpec.ED25519,
|
||||||
|
"d85a980182b10ac7d54bfed3c964073a0ee172f3daa62325af021a68f707511a");
|
||||||
|
// x = 0, but x mod 2 == 1
|
||||||
|
testInvalidPoint(NamedParameterSpec.ED25519,
|
||||||
|
"0100000000000000000000000000000000000000000000000000000000000080");
|
||||||
|
|
||||||
|
// Ed448
|
||||||
|
testInvalidPoint(NamedParameterSpec.ED448, "");
|
||||||
|
testInvalidPoint(NamedParameterSpec.ED448, "ffffff");
|
||||||
|
testInvalidPoint(NamedParameterSpec.ED448,
|
||||||
|
"ab43ba28f430cdfe456ae531545f7ecd0ac834a55c9358c0372bfa0c6c6798c0" +
|
||||||
|
"866aea01eb00742802b8438ea4cb82169c235160627b4c3a9480");
|
||||||
|
// y value too large
|
||||||
|
testInvalidPoint(NamedParameterSpec.ED448,
|
||||||
|
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" +
|
||||||
|
"fffffffffffffffffffffffffffffffffffffffffffffffffff00");
|
||||||
|
// not square
|
||||||
|
testInvalidPoint(NamedParameterSpec.ED448,
|
||||||
|
"43ba28f430cdfe456ae531545f7ecd0ac834a55c9358c0372bfa0c6c6798c086" +
|
||||||
|
"6aea01eb00742802b8438ea4cb82169c235160627b4c3a9480");
|
||||||
|
// x = 0, but x mod 2 == 1
|
||||||
|
testInvalidPoint(NamedParameterSpec.ED448,
|
||||||
|
"0100000000000000000000000000000000000000000000000000000000000000" +
|
||||||
|
"00000000000000000000000000000000000000000000000080");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testInvalidPoint(NamedParameterSpec curve,
|
||||||
|
String pointStr) throws Exception {
|
||||||
|
|
||||||
|
byte[] encodedPoint = Convert.hexStringToByteArray(pointStr);
|
||||||
|
EdDSAParameters params =
|
||||||
|
EdDSAParameters.get(RuntimeException::new, curve);
|
||||||
|
EdDSAOperations ops = new EdDSAOperations(params);
|
||||||
|
try {
|
||||||
|
ops.decodeAffinePoint(InvalidKeyException::new, encodedPoint);
|
||||||
|
throw new RuntimeException("No exception on invalid point");
|
||||||
|
} catch (InvalidKeyException ex) {
|
||||||
|
// this is expected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -32,6 +32,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import sun.security.ec.*;
|
import sun.security.ec.*;
|
||||||
|
|
||||||
|
import java.security.spec.NamedParameterSpec;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import jdk.test.lib.Convert;
|
import jdk.test.lib.Convert;
|
||||||
|
|
||||||
|
@ -86,7 +88,9 @@ public class TestXECOps {
|
||||||
private void runDiffieHellmanTest(String opName, String a_str,
|
private void runDiffieHellmanTest(String opName, String a_str,
|
||||||
String b_str, String result_str) {
|
String b_str, String result_str) {
|
||||||
|
|
||||||
XECParameters settings = XECParameters.getByName(opName).get();
|
NamedParameterSpec paramSpec = new NamedParameterSpec(opName);
|
||||||
|
XECParameters settings =
|
||||||
|
XECParameters.get(RuntimeException::new, paramSpec);
|
||||||
XECOperations ops = new XECOperations(settings);
|
XECOperations ops = new XECOperations(settings);
|
||||||
|
|
||||||
byte[] basePoint = Convert.byteToByteArray(settings.getBasePoint(),
|
byte[] basePoint = Convert.byteToByteArray(settings.getBasePoint(),
|
||||||
|
@ -118,7 +122,9 @@ public class TestXECOps {
|
||||||
byte[] u_in = Convert.hexStringToByteArray(u_in_str);
|
byte[] u_in = Convert.hexStringToByteArray(u_in_str);
|
||||||
byte[] u_out_expected = Convert.hexStringToByteArray(u_out_str);
|
byte[] u_out_expected = Convert.hexStringToByteArray(u_out_str);
|
||||||
|
|
||||||
XECParameters settings = XECParameters.getByName(opName).get();
|
NamedParameterSpec paramSpec = new NamedParameterSpec(opName);
|
||||||
|
XECParameters settings =
|
||||||
|
XECParameters.get(RuntimeException::new, paramSpec);
|
||||||
XECOperations ops = new XECOperations(settings);
|
XECOperations ops = new XECOperations(settings);
|
||||||
byte[] u_out = ops.encodedPointMultiply(k_in, u_in);
|
byte[] u_out = ops.encodedPointMultiply(k_in, u_in);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -43,6 +43,7 @@
|
||||||
import sun.security.ec.*;
|
import sun.security.ec.*;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import java.security.spec.NamedParameterSpec;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import jdk.test.lib.Convert;
|
import jdk.test.lib.Convert;
|
||||||
|
|
||||||
|
@ -79,7 +80,9 @@ public class XECIterative {
|
||||||
private void runIterativeTest(String opName, long start, long end)
|
private void runIterativeTest(String opName, long start, long end)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
|
||||||
XECParameters settings = XECParameters.getByName(opName).get();
|
NamedParameterSpec paramSpec = new NamedParameterSpec(opName);
|
||||||
|
XECParameters settings =
|
||||||
|
XECParameters.get(RuntimeException::new, paramSpec);
|
||||||
XECOperations ops = new XECOperations(settings);
|
XECOperations ops = new XECOperations(settings);
|
||||||
|
|
||||||
File vectorFile = new File(System.getProperty("test.src", "."),
|
File vectorFile = new File(System.getProperty("test.src", "."),
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -36,6 +36,8 @@
|
||||||
* @run main TestIntegerModuloP sun.security.util.math.intpoly.P256OrderField 32 8
|
* @run main TestIntegerModuloP sun.security.util.math.intpoly.P256OrderField 32 8
|
||||||
* @run main TestIntegerModuloP sun.security.util.math.intpoly.P384OrderField 48 9
|
* @run main TestIntegerModuloP sun.security.util.math.intpoly.P384OrderField 48 9
|
||||||
* @run main TestIntegerModuloP sun.security.util.math.intpoly.P521OrderField 66 10
|
* @run main TestIntegerModuloP sun.security.util.math.intpoly.P521OrderField 66 10
|
||||||
|
* @run main TestIntegerModuloP sun.security.util.math.intpoly.Curve25519OrderField 32 11
|
||||||
|
* @run main TestIntegerModuloP sun.security.util.math.intpoly.Curve448OrderField 56 12
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import sun.security.util.math.*;
|
import sun.security.util.math.*;
|
||||||
|
@ -104,8 +106,10 @@ public class TestIntegerModuloP {
|
||||||
SET_FUNCTIONS.add((a, b, c) ->
|
SET_FUNCTIONS.add((a, b, c) ->
|
||||||
a.setValue(c, 0, c.length, (byte) 0));
|
a.setValue(c, 0, c.length, (byte) 0));
|
||||||
SET_FUNCTIONS.add((a, b, c) ->
|
SET_FUNCTIONS.add((a, b, c) ->
|
||||||
a.setValue(ByteBuffer.wrap(c, 0, c.length).order(ByteOrder.LITTLE_ENDIAN),
|
a.setValue(c, 0, c.length / 2, (byte) 0));
|
||||||
c.length, highByte));
|
SET_FUNCTIONS.add((a, b, c) ->
|
||||||
|
a.setValue(ByteBuffer.wrap(c, 0, c.length / 2).order(ByteOrder.LITTLE_ENDIAN),
|
||||||
|
c.length / 2, highByte));
|
||||||
|
|
||||||
// array functions return the (possibly modified) value as byte array
|
// array functions return the (possibly modified) value as byte array
|
||||||
ARRAY_FUNCTIONS.add((a, b ) -> a.asByteArray(length));
|
ARRAY_FUNCTIONS.add((a, b ) -> a.asByteArray(length));
|
||||||
|
@ -328,7 +332,7 @@ public class TestIntegerModuloP {
|
||||||
|
|
||||||
ElemSetFunction setFunc =
|
ElemSetFunction setFunc =
|
||||||
SET_FUNCTIONS.get(random.nextInt(SET_FUNCTIONS.size()));
|
SET_FUNCTIONS.get(random.nextInt(SET_FUNCTIONS.size()));
|
||||||
byte[] valueArr = new byte[length];
|
byte[] valueArr = new byte[2 * length];
|
||||||
random.nextBytes(valueArr);
|
random.nextBytes(valueArr);
|
||||||
setAndCheck(setFunc, result1, result2, valueArr);
|
setAndCheck(setFunc, result1, result2, valueArr);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -24,10 +24,11 @@
|
||||||
package jdk.test.lib;
|
package jdk.test.lib;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
import java.security.spec.EdECPoint;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility class containing conversions between strings, arrays, and numeric
|
* Utility class containing conversions between strings, arrays, numeric
|
||||||
* values.
|
* values, and other types.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class Convert {
|
public class Convert {
|
||||||
|
@ -80,6 +81,36 @@ public class Convert {
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static EdECPoint byteArrayToEdPoint(byte[] arr) {
|
||||||
|
byte msb = arr[arr.length - 1];
|
||||||
|
boolean xOdd = (msb & 0x80) != 0;
|
||||||
|
arr[arr.length - 1] &= (byte) 0x7F;
|
||||||
|
reverse(arr);
|
||||||
|
BigInteger y = new BigInteger(1, arr);
|
||||||
|
return new EdECPoint(xOdd, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EdECPoint hexStringToEdPoint(String str) {
|
||||||
|
return byteArrayToEdPoint(hexStringToByteArray(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
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--;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -57,7 +57,11 @@ public class SignatureBench extends CryptoBase {
|
||||||
|
|
||||||
|
|
||||||
private String getKeyPairGeneratorName() {
|
private String getKeyPairGeneratorName() {
|
||||||
String tail = algorithm.substring(algorithm.lastIndexOf("with") + 4);
|
int withIndex = algorithm.lastIndexOf("with");
|
||||||
|
if (withIndex < 0) {
|
||||||
|
return algorithm;
|
||||||
|
}
|
||||||
|
String tail = algorithm.substring(withIndex + 4);
|
||||||
return "ECDSA".equals(tail) ? "EC" : tail;
|
return "ECDSA".equals(tail) ? "EC" : tail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,4 +126,14 @@ public class SignatureBench extends CryptoBase {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class EdDSA extends SignatureBench {
|
||||||
|
|
||||||
|
@Param({"EdDSA"})
|
||||||
|
private String algorithm;
|
||||||
|
|
||||||
|
@Param({"255", "448"})
|
||||||
|
private int keyLength;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue