8166597: Crypto support for the EdDSA Signature Algorithm

Reviewed-by: weijun, mullan, wetmore
This commit is contained in:
Anthony Scarpino 2020-05-18 09:42:52 -07:00
parent 02293daa64
commit fd28aad72d
47 changed files with 4697 additions and 155 deletions

View file

@ -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();

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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;
/** /**

View file

@ -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;

View file

@ -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),

View file

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

View file

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

View file

@ -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)) {

View file

@ -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.

View file

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

View file

@ -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,

View file

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

View file

@ -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) {

View file

@ -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

View file

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

View file

@ -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

View file

@ -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.");
}
}
}

View file

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

View file

@ -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.");
}
} }
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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();

View file

@ -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 {

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

View 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
}
}
}

View 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
}
}
}

View file

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

View file

@ -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", "."),

View file

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

View file

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

View file

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