feat(jdk8): move files to new folder to avoid resources compiled.

This commit is contained in:
2025-09-07 15:25:52 +08:00
parent 3f0047bf6f
commit 8c35cfb1c0
17415 changed files with 217 additions and 213 deletions

View File

@@ -0,0 +1,287 @@
/*
* Copyright (c) 2009, 2018, 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 java.math.*;
import java.security.*;
import java.security.interfaces.*;
import java.security.spec.*;
import java.util.Optional;
import javax.crypto.*;
import javax.crypto.spec.*;
import sun.security.util.ArrayUtil;
import sun.security.util.ECUtil;
import sun.security.util.math.*;
import sun.security.ec.point.*;
/**
* KeyAgreement implementation for ECDH.
*
* @since 1.7
*/
public final class ECDHKeyAgreement extends KeyAgreementSpi {
// private key, if initialized
private ECPrivateKey privateKey;
// public key, non-null between doPhase() & generateSecret() only
private ECPublicKey publicKey;
// length of the secret to be derived
private int secretLen;
/**
* Constructs a new ECDHKeyAgreement.
*/
public ECDHKeyAgreement() {
}
// see JCE spec
@Override
protected void engineInit(Key key, SecureRandom random)
throws InvalidKeyException {
if (!(key instanceof PrivateKey)) {
throw new InvalidKeyException
("Key must be instance of PrivateKey");
}
privateKey = (ECPrivateKey) ECKeyFactory.toECKey(key);
publicKey = null;
}
// see JCE spec
@Override
protected void engineInit(Key key, AlgorithmParameterSpec params,
SecureRandom random) throws InvalidKeyException,
InvalidAlgorithmParameterException {
if (params != null) {
throw new InvalidAlgorithmParameterException
("Parameters not supported");
}
engineInit(key, random);
}
// see JCE spec
@Override
protected Key engineDoPhase(Key key, boolean lastPhase)
throws InvalidKeyException, IllegalStateException {
if (privateKey == null) {
throw new IllegalStateException("Not initialized");
}
if (publicKey != null) {
throw new IllegalStateException("Phase already executed");
}
if (!lastPhase) {
throw new IllegalStateException
("Only two party agreement supported, lastPhase must be true");
}
if (!(key instanceof ECPublicKey)) {
throw new InvalidKeyException
("Key must be a PublicKey with algorithm EC");
}
this.publicKey = (ECPublicKey) key;
ECParameterSpec params = publicKey.getParams();
int keyLenBits = params.getCurve().getField().getFieldSize();
secretLen = (keyLenBits + 7) >> 3;
return null;
}
private static void validateCoordinate(BigInteger c, BigInteger mod) {
if (c.compareTo(BigInteger.ZERO) < 0) {
throw new ProviderException("invalid coordinate");
}
if (c.compareTo(mod) >= 0) {
throw new ProviderException("invalid coordinate");
}
}
/*
* Check whether a public key is valid. Throw ProviderException
* if it is not valid or could not be validated.
*/
private static void validate(ECOperations ops, ECPublicKey key) {
// ensure that integers are in proper range
BigInteger x = key.getW().getAffineX();
BigInteger y = key.getW().getAffineY();
BigInteger p = ops.getField().getSize();
validateCoordinate(x, p);
validateCoordinate(y, p);
// ensure the point is on the curve
EllipticCurve curve = key.getParams().getCurve();
BigInteger rhs = x.modPow(BigInteger.valueOf(3), p).add(curve.getA()
.multiply(x)).add(curve.getB()).mod(p);
BigInteger lhs = y.modPow(BigInteger.valueOf(2), p).mod(p);
if (!rhs.equals(lhs)) {
throw new ProviderException("point is not on curve");
}
// check the order of the point
ImmutableIntegerModuloP xElem = ops.getField().getElement(x);
ImmutableIntegerModuloP yElem = ops.getField().getElement(y);
AffinePoint affP = new AffinePoint(xElem, yElem);
byte[] order = key.getParams().getOrder().toByteArray();
ArrayUtil.reverse(order);
Point product = ops.multiply(affP, order);
if (!ops.isNeutral(product)) {
throw new ProviderException("point has incorrect order");
}
}
// see JCE spec
@Override
protected byte[] engineGenerateSecret() throws IllegalStateException {
if ((privateKey == null) || (publicKey == null)) {
throw new IllegalStateException("Not initialized correctly");
}
Optional<byte[]> resultOpt = deriveKeyImpl(privateKey, publicKey);
return resultOpt.orElseGet(
() -> deriveKeyNative(privateKey, publicKey)
);
}
// see JCE spec
@Override
protected int engineGenerateSecret(byte[] sharedSecret, int
offset) throws IllegalStateException, ShortBufferException {
if (offset + secretLen > sharedSecret.length) {
throw new ShortBufferException("Need " + secretLen
+ " bytes, only " + (sharedSecret.length - offset)
+ " available");
}
byte[] secret = engineGenerateSecret();
System.arraycopy(secret, 0, sharedSecret, offset, secret.length);
return secret.length;
}
// see JCE spec
@Override
protected SecretKey engineGenerateSecret(String algorithm)
throws IllegalStateException, NoSuchAlgorithmException,
InvalidKeyException {
if (algorithm == null) {
throw new NoSuchAlgorithmException("Algorithm must not be null");
}
if (!(algorithm.equals("TlsPremasterSecret"))) {
throw new NoSuchAlgorithmException
("Only supported for algorithm TlsPremasterSecret");
}
return new SecretKeySpec(engineGenerateSecret(), "TlsPremasterSecret");
}
private static
Optional<byte[]> deriveKeyImpl(ECPrivateKey priv, ECPublicKey pubKey) {
ECParameterSpec ecSpec = priv.getParams();
EllipticCurve curve = ecSpec.getCurve();
Optional<ECOperations> opsOpt = ECOperations.forParameters(ecSpec);
if (!opsOpt.isPresent()) {
return Optional.empty();
}
ECOperations ops = opsOpt.get();
if (! (priv instanceof ECPrivateKeyImpl)) {
return Optional.empty();
}
ECPrivateKeyImpl privImpl = (ECPrivateKeyImpl) priv;
byte[] sArr = privImpl.getArrayS();
// to match the native implementation, validate the public key here
// and throw ProviderException if it is invalid
validate(ops, pubKey);
IntegerFieldModuloP field = ops.getField();
// convert s array into field element and multiply by the cofactor
MutableIntegerModuloP scalar = field.getElement(sArr).mutable();
SmallValue cofactor =
field.getSmallValue(priv.getParams().getCofactor());
scalar.setProduct(cofactor);
int keySize = (curve.getField().getFieldSize() + 7) / 8;
byte[] privArr = scalar.asByteArray(keySize);
ImmutableIntegerModuloP x =
field.getElement(pubKey.getW().getAffineX());
ImmutableIntegerModuloP y =
field.getElement(pubKey.getW().getAffineY());
AffinePoint affPub = new AffinePoint(x, y);
Point product = ops.multiply(affPub, privArr);
if (ops.isNeutral(product)) {
throw new ProviderException("Product is zero");
}
AffinePoint affProduct = product.asAffine();
byte[] result = affProduct.getX().asByteArray(keySize);
ArrayUtil.reverse(result);
return Optional.of(result);
}
private static
byte[] deriveKeyNative(ECPrivateKey privateKey, ECPublicKey publicKey) {
ECParameterSpec params = privateKey.getParams();
byte[] s = privateKey.getS().toByteArray();
byte[] encodedParams = // DER OID
ECUtil.encodeECParameterSpec(null, params);
byte[] publicValue;
if (publicKey instanceof ECPublicKeyImpl) {
ECPublicKeyImpl ecPub = (ECPublicKeyImpl) publicKey;
publicValue = ecPub.getEncodedPublicValue();
} else { // instanceof ECPublicKey
publicValue =
ECUtil.encodePoint(publicKey.getW(), params.getCurve());
}
try {
return deriveKey(s, publicValue, encodedParams);
} catch (GeneralSecurityException e) {
throw new ProviderException("Could not derive key", e);
}
}
/**
* Generates a secret key using the public and private keys.
*
* @param s the private key's S value.
* @param w the public key's W point (in uncompressed form).
* @param encodedParams the curve's DER encoded object identifier.
*
* @return byte[] the secret key.
*/
private static native byte[] deriveKey(byte[] s, byte[] w,
byte[] encodedParams) throws GeneralSecurityException;
}

View File

@@ -0,0 +1,202 @@
/*
* Copyright (c) 2018, 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.ec.point.*;
import sun.security.util.ArrayUtil;
import sun.security.util.math.*;
import static sun.security.ec.ECOperations.IntermediateValueException;
import java.security.ProviderException;
import java.security.spec.*;
import java.util.Optional;
public class ECDSAOperations {
public static class Seed {
private final byte[] seedValue;
public Seed(byte[] seedValue) {
this.seedValue = seedValue;
}
public byte[] getSeedValue() {
return seedValue;
}
}
public static class Nonce {
private final byte[] nonceValue;
public Nonce(byte[] nonceValue) {
this.nonceValue = nonceValue;
}
public byte[] getNonceValue() {
return nonceValue;
}
}
private final ECOperations ecOps;
private final AffinePoint basePoint;
public ECDSAOperations(ECOperations ecOps, ECPoint basePoint) {
this.ecOps = ecOps;
this.basePoint = toAffinePoint(basePoint, ecOps.getField());
}
public ECOperations getEcOperations() {
return ecOps;
}
public AffinePoint basePointMultiply(byte[] scalar) {
return ecOps.multiply(basePoint, scalar).asAffine();
}
public static AffinePoint toAffinePoint(ECPoint point,
IntegerFieldModuloP field) {
ImmutableIntegerModuloP affineX = field.getElement(point.getAffineX());
ImmutableIntegerModuloP affineY = field.getElement(point.getAffineY());
return new AffinePoint(affineX, affineY);
}
public static
Optional<ECDSAOperations> forParameters(ECParameterSpec ecParams) {
Optional<ECOperations> curveOps =
ECOperations.forParameters(ecParams);
return curveOps.map(
ops -> new ECDSAOperations(ops, ecParams.getGenerator())
);
}
/**
*
* Sign a digest using the provided private key and seed.
* IMPORTANT: The private key is a scalar represented using a
* little-endian byte array. This is backwards from the conventional
* representation in ECDSA. The routines that produce and consume this
* value uses little-endian, so this deviation from convention removes
* the requirement to swap the byte order. The returned signature is in
* the conventional byte order.
*
* @param privateKey the private key scalar as a little-endian byte array
* @param digest the digest to be signed
* @param seed the seed that will be used to produce the nonce. This object
* should contain an array that is at least 64 bits longer than
* the number of bits required to represent the group order.
* @return the ECDSA signature value
* @throws IntermediateValueException if the signature cannot be produced
* due to an unacceptable intermediate or final value. If this
* exception is thrown, then the caller should discard the nonnce and
* try again with an entirely new nonce value.
*/
public byte[] signDigest(byte[] privateKey, byte[] digest, Seed seed)
throws IntermediateValueException {
byte[] nonceArr = ecOps.seedToScalar(seed.getSeedValue());
Nonce nonce = new Nonce(nonceArr);
return signDigest(privateKey, digest, nonce);
}
/**
*
* Sign a digest using the provided private key and nonce.
* IMPORTANT: The private key and nonce are scalars represented by a
* little-endian byte array. This is backwards from the conventional
* representation in ECDSA. The routines that produce and consume these
* values use little-endian, so this deviation from convention removes
* the requirement to swap the byte order. The returned signature is in
* the conventional byte order.
*
* @param privateKey the private key scalar as a little-endian byte array
* @param digest the digest to be signed
* @param nonce the nonce object containing a little-endian scalar value.
* @return the ECDSA signature value
* @throws IntermediateValueException if the signature cannot be produced
* due to an unacceptable intermediate or final value. If this
* exception is thrown, then the caller should discard the nonnce and
* try again with an entirely new nonce value.
*/
public byte[] signDigest(byte[] privateKey, byte[] digest, Nonce nonce)
throws IntermediateValueException {
IntegerFieldModuloP orderField = ecOps.getOrderField();
int orderBits = orderField.getSize().bitLength();
if (orderBits % 8 != 0 && orderBits < digest.length * 8) {
// This implementation does not support truncating digests to
// a length that is not a multiple of 8.
throw new ProviderException("Invalid digest length");
}
byte[] k = nonce.getNonceValue();
// check nonce length
int length = (orderField.getSize().bitLength() + 7) / 8;
if (k.length != length) {
throw new ProviderException("Incorrect nonce length");
}
MutablePoint R = ecOps.multiply(basePoint, k);
IntegerModuloP r = R.asAffine().getX();
// put r into the correct field by fully reducing to an array
byte[] temp = new byte[length];
r.asByteArray(temp);
r = orderField.getElement(temp);
// store r in result
r.asByteArray(temp);
byte[] result = new byte[2 * length];
ArrayUtil.reverse(temp);
System.arraycopy(temp, 0, result, 0, length);
// compare r to 0
if (ECOperations.allZero(temp)) {
throw new IntermediateValueException();
}
IntegerModuloP dU = orderField.getElement(privateKey);
int lengthE = Math.min(length, digest.length);
byte[] E = new byte[lengthE];
System.arraycopy(digest, 0, E, 0, lengthE);
ArrayUtil.reverse(E);
IntegerModuloP e = orderField.getElement(E);
IntegerModuloP kElem = orderField.getElement(k);
IntegerModuloP kInv = kElem.multiplicativeInverse();
MutableIntegerModuloP s = r.mutable();
s.setProduct(dU).setSum(e).setProduct(kInv);
// store s in result
s.asByteArray(temp);
ArrayUtil.reverse(temp);
System.arraycopy(temp, 0, result, length, length);
// compare s to 0
if (ECOperations.allZero(temp)) {
throw new IntermediateValueException();
}
return result;
}
}

View File

@@ -0,0 +1,498 @@
/*
* Copyright (c) 2009, 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 java.nio.ByteBuffer;
import java.security.*;
import java.security.interfaces.*;
import java.security.spec.*;
import java.util.Optional;
import sun.security.jca.JCAUtil;
import sun.security.util.*;
import static sun.security.ec.ECOperations.IntermediateValueException;
/**
* ECDSA signature implementation. This class currently supports the
* following algorithm names:
*
* . "NONEwithECDSA"
* . "SHA1withECDSA"
* . "SHA224withECDSA"
* . "SHA256withECDSA"
* . "SHA384withECDSA"
* . "SHA512withECDSA"
*
* @since 1.7
*/
abstract class ECDSASignature extends SignatureSpi {
// message digest implementation we use
private final MessageDigest messageDigest;
// supplied entropy
private SecureRandom random;
// flag indicating whether the digest has been reset
private boolean needsReset;
// private key, if initialized for signing
private ECPrivateKey privateKey;
// public key, if initialized for verifying
private ECPublicKey publicKey;
// signature parameters
private ECParameterSpec sigParams = null;
/**
* Constructs a new ECDSASignature. Used by Raw subclass.
*
* @exception ProviderException if the native ECC library is unavailable.
*/
ECDSASignature() {
messageDigest = null;
}
/**
* Constructs a new ECDSASignature. Used by subclasses.
*/
ECDSASignature(String digestName) {
try {
messageDigest = MessageDigest.getInstance(digestName);
} catch (NoSuchAlgorithmException e) {
throw new ProviderException(e);
}
needsReset = false;
}
// Nested class for NONEwithECDSA signatures
public static final class Raw extends ECDSASignature {
// the longest supported digest is 512 bits (SHA-512)
private static final int RAW_ECDSA_MAX = 64;
private final byte[] precomputedDigest;
private int offset = 0;
public Raw() {
precomputedDigest = new byte[RAW_ECDSA_MAX];
}
// Stores the precomputed message digest value.
@Override
protected void engineUpdate(byte b) throws SignatureException {
if (offset >= precomputedDigest.length) {
offset = RAW_ECDSA_MAX + 1;
return;
}
precomputedDigest[offset++] = b;
}
// Stores the precomputed message digest value.
@Override
protected void engineUpdate(byte[] b, int off, int len)
throws SignatureException {
if (offset >= precomputedDigest.length) {
offset = RAW_ECDSA_MAX + 1;
return;
}
System.arraycopy(b, off, precomputedDigest, offset, len);
offset += len;
}
// Stores the precomputed message digest value.
@Override
protected void engineUpdate(ByteBuffer byteBuffer) {
int len = byteBuffer.remaining();
if (len <= 0) {
return;
}
if (offset + len >= precomputedDigest.length) {
offset = RAW_ECDSA_MAX + 1;
return;
}
byteBuffer.get(precomputedDigest, offset, len);
offset += len;
}
@Override
protected void resetDigest() {
offset = 0;
}
// Returns the precomputed message digest value.
@Override
protected byte[] getDigestValue() throws SignatureException {
if (offset > RAW_ECDSA_MAX) {
throw new SignatureException("Message digest is too long");
}
byte[] result = new byte[offset];
System.arraycopy(precomputedDigest, 0, result, 0, offset);
offset = 0;
return result;
}
}
// Nested class for SHA1withECDSA signatures
public static final class SHA1 extends ECDSASignature {
public SHA1() {
super("SHA1");
}
}
// Nested class for SHA224withECDSA signatures
public static final class SHA224 extends ECDSASignature {
public SHA224() {
super("SHA-224");
}
}
// Nested class for SHA256withECDSA signatures
public static final class SHA256 extends ECDSASignature {
public SHA256() {
super("SHA-256");
}
}
// Nested class for SHA384withECDSA signatures
public static final class SHA384 extends ECDSASignature {
public SHA384() {
super("SHA-384");
}
}
// Nested class for SHA512withECDSA signatures
public static final class SHA512 extends ECDSASignature {
public SHA512() {
super("SHA-512");
}
}
// initialize for verification. See JCA doc
@Override
protected void engineInitVerify(PublicKey publicKey)
throws InvalidKeyException {
ECPublicKey key = (ECPublicKey) ECKeyFactory.toECKey(publicKey);
if (!isCompatible(this.sigParams, key.getParams())) {
throw new InvalidKeyException("Key params does not match signature params");
}
// Should check that the supplied key is appropriate for signature
// algorithm (e.g. P-256 for SHA256withECDSA)
this.publicKey = key;
this.privateKey = null;
resetDigest();
}
// initialize for signing. See JCA doc
@Override
protected void engineInitSign(PrivateKey privateKey)
throws InvalidKeyException {
engineInitSign(privateKey, null);
}
// initialize for signing. See JCA doc
@Override
protected void engineInitSign(PrivateKey privateKey, SecureRandom random)
throws InvalidKeyException {
ECPrivateKey key = (ECPrivateKey) ECKeyFactory.toECKey(privateKey);
if (!isCompatible(this.sigParams, key.getParams())) {
throw new InvalidKeyException("Key params does not match signature params");
}
// Should check that the supplied key is appropriate for signature
// algorithm (e.g. P-256 for SHA256withECDSA)
this.privateKey = key;
this.publicKey = null;
this.random = random;
resetDigest();
}
/**
* Resets the message digest if needed.
*/
protected void resetDigest() {
if (needsReset) {
if (messageDigest != null) {
messageDigest.reset();
}
needsReset = false;
}
}
/**
* Returns the message digest value.
*/
protected byte[] getDigestValue() throws SignatureException {
needsReset = false;
return messageDigest.digest();
}
// update the signature with the plaintext data. See JCA doc
@Override
protected void engineUpdate(byte b) throws SignatureException {
messageDigest.update(b);
needsReset = true;
}
// update the signature with the plaintext data. See JCA doc
@Override
protected void engineUpdate(byte[] b, int off, int len)
throws SignatureException {
messageDigest.update(b, off, len);
needsReset = true;
}
// update the signature with the plaintext data. See JCA doc
@Override
protected void engineUpdate(ByteBuffer byteBuffer) {
int len = byteBuffer.remaining();
if (len <= 0) {
return;
}
messageDigest.update(byteBuffer);
needsReset = true;
}
private static boolean isCompatible(ECParameterSpec sigParams,
ECParameterSpec keyParams) {
if (sigParams == null) {
// no restriction on key param
return true;
}
return ECUtil.equals(sigParams, keyParams);
}
private byte[] signDigestImpl(ECDSAOperations ops, int seedBits,
byte[] digest, ECPrivateKeyImpl privImpl, SecureRandom random)
throws SignatureException {
byte[] seedBytes = new byte[(seedBits + 7) / 8];
byte[] s = privImpl.getArrayS();
// Attempt to create the signature in a loop that uses new random input
// each time. The chance of failure is very small assuming the
// implementation derives the nonce using extra bits
int numAttempts = 128;
for (int i = 0; i < numAttempts; i++) {
random.nextBytes(seedBytes);
ECDSAOperations.Seed seed = new ECDSAOperations.Seed(seedBytes);
try {
return ops.signDigest(s, digest, seed);
} catch (IntermediateValueException ex) {
// try again in the next iteration
}
}
throw new SignatureException("Unable to produce signature after "
+ numAttempts + " attempts");
}
private Optional<byte[]> signDigestImpl(ECPrivateKey privateKey,
byte[] digest, SecureRandom random) throws SignatureException {
if (! (privateKey instanceof ECPrivateKeyImpl)) {
return Optional.empty();
}
ECPrivateKeyImpl privImpl = (ECPrivateKeyImpl) privateKey;
ECParameterSpec params = privateKey.getParams();
// seed is the key size + 64 bits
int seedBits = params.getOrder().bitLength() + 64;
Optional<ECDSAOperations> opsOpt =
ECDSAOperations.forParameters(params);
if (!opsOpt.isPresent()) {
return Optional.empty();
} else {
byte[] sig = signDigestImpl(opsOpt.get(), seedBits, digest,
privImpl, random);
return Optional.of(sig);
}
}
private byte[] signDigestNative(ECPrivateKey privateKey, byte[] digest,
SecureRandom random) throws SignatureException {
byte[] s = privateKey.getS().toByteArray();
ECParameterSpec params = privateKey.getParams();
// DER OID
byte[] encodedParams = ECUtil.encodeECParameterSpec(null, params);
int orderLength = params.getOrder().bitLength();
// seed is twice the order length (in bytes) plus 1
byte[] seed = new byte[(((orderLength + 7) >> 3) + 1) * 2];
random.nextBytes(seed);
// random bits needed for timing countermeasures
int timingArgument = random.nextInt();
// values must be non-zero to enable countermeasures
timingArgument |= 1;
try {
return signDigest(digest, s, encodedParams, seed,
timingArgument);
} catch (GeneralSecurityException e) {
throw new SignatureException("Could not sign data", e);
}
}
// sign the data and return the signature. See JCA doc
@Override
protected byte[] engineSign() throws SignatureException {
if (random == null) {
random = JCAUtil.getSecureRandom();
}
byte[] digest = getDigestValue();
Optional<byte[]> sigOpt = signDigestImpl(privateKey, digest, random);
byte[] sig;
if (sigOpt.isPresent()) {
sig = sigOpt.get();
} else {
sig = signDigestNative(privateKey, digest, random);
}
return ECUtil.encodeSignature(sig);
}
// verify the data and return the result. See JCA doc
@Override
protected boolean engineVerify(byte[] signature) throws SignatureException {
byte[] w;
ECParameterSpec params = publicKey.getParams();
// DER OID
byte[] encodedParams = ECUtil.encodeECParameterSpec(null, params);
if (publicKey instanceof ECPublicKeyImpl) {
w = ((ECPublicKeyImpl) publicKey).getEncodedPublicValue();
} else { // instanceof ECPublicKey
w = ECUtil.encodePoint(publicKey.getW(), params.getCurve());
}
try {
return verifySignedDigest(
ECUtil.decodeSignature(signature), getDigestValue(),
w, encodedParams);
} catch (GeneralSecurityException e) {
throw new SignatureException("Could not verify signature", e);
}
}
// set parameter, not supported. See JCA doc
@Override
@Deprecated
protected void engineSetParameter(String param, Object value)
throws InvalidParameterException {
throw new UnsupportedOperationException("setParameter() not supported");
}
@Override
protected void engineSetParameter(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
if (params != null && !(params instanceof ECParameterSpec)) {
throw new InvalidAlgorithmParameterException("No parameter accepted");
}
ECKey key = (this.privateKey == null? this.publicKey : this.privateKey);
if ((key != null) && !isCompatible((ECParameterSpec)params, key.getParams())) {
throw new InvalidAlgorithmParameterException
("Signature params does not match key params");
}
sigParams = (ECParameterSpec) params;
}
// get parameter, not supported. See JCA doc
@Override
@Deprecated
protected Object engineGetParameter(String param)
throws InvalidParameterException {
throw new UnsupportedOperationException("getParameter() not supported");
}
@Override
protected AlgorithmParameters engineGetParameters() {
if (sigParams == null) {
return null;
}
try {
AlgorithmParameters ap = AlgorithmParameters.getInstance("EC");
ap.init(sigParams);
return ap;
} catch (Exception e) {
// should never happen
throw new ProviderException("Error retrieving EC parameters", e);
}
}
/**
* Signs the digest using the private key.
*
* @param digest the digest to be signed.
* @param s the private key's S value.
* @param encodedParams the curve's DER encoded object identifier.
* @param seed the random seed.
* @param timing When non-zero, the implmentation will use timing
* countermeasures to hide secrets from timing channels. The EC
* implementation will disable the countermeasures when this value is
* zero, because the underlying EC functions are shared by several
* crypto operations, some of which do not use the countermeasures.
* The high-order 31 bits must be uniformly random. The entropy from
* these bits is used by the countermeasures.
*
* @return byte[] the signature.
*/
private static native byte[] signDigest(byte[] digest, byte[] s,
byte[] encodedParams, byte[] seed, int timing)
throws GeneralSecurityException;
/**
* Verifies the signed digest using the public key.
*
* @param signature the signature to be verified. It is encoded
* as a concatenation of the key's R and S values.
* @param digest the digest to be used.
* @param w the public key's W point (in uncompressed form).
* @param encodedParams the curve's DER encoded object identifier.
*
* @return boolean true if the signature is successfully verified.
*/
private static native boolean verifySignedDigest(byte[] signature,
byte[] digest, byte[] w, byte[] encodedParams)
throws GeneralSecurityException;
}

View File

@@ -0,0 +1,290 @@
/*
* Copyright (c) 2006, 2021, 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 java.security.*;
import java.security.interfaces.*;
import java.security.spec.*;
/**
* KeyFactory for EC keys. Keys must be instances of PublicKey or PrivateKey
* and getAlgorithm() must return "EC". For such keys, it supports conversion
* between the following:
*
* For public keys:
* . PublicKey with an X.509 encoding
* . ECPublicKey
* . ECPublicKeySpec
* . X509EncodedKeySpec
*
* For private keys:
* . PrivateKey with a PKCS#8 encoding
* . ECPrivateKey
* . ECPrivateKeySpec
* . PKCS8EncodedKeySpec
*
* @since 1.6
* @author Andreas Sterbenz
*/
public final class ECKeyFactory extends KeyFactorySpi {
// Used by translateKey()
private static KeyFactory instance;
private static KeyFactory getInstance() {
if (instance == null) {
try {
instance = KeyFactory.getInstance("EC", "SunEC");
} catch (NoSuchProviderException e) {
throw new RuntimeException(e);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
return instance;
}
public ECKeyFactory() {
// empty
}
/**
* Static method to convert Key into a useable instance of
* ECPublicKey or ECPrivateKey. Check the key and convert it
* to a Sun key if necessary. If the key is not an EC key
* or cannot be used, throw an InvalidKeyException.
*
* The difference between this method and engineTranslateKey() is that
* we do not convert keys of other providers that are already an
* instance of ECPublicKey or ECPrivateKey.
*
* To be used by future Java ECDSA and ECDH implementations.
*/
public static ECKey toECKey(Key key) throws InvalidKeyException {
if (key instanceof ECKey) {
ECKey ecKey = (ECKey)key;
checkKey(ecKey);
return ecKey;
} else {
/*
* We don't call the engineTranslateKey method directly
* because KeyFactory.translateKey adds code to loop through
* all key factories.
*/
return (ECKey)getInstance().translateKey(key);
}
}
/**
* Check that the given EC key is valid.
*/
private static void checkKey(ECKey key) throws InvalidKeyException {
// check for subinterfaces, omit additional checks for our keys
if (key instanceof ECPublicKey) {
if (key instanceof ECPublicKeyImpl) {
return;
}
} else if (key instanceof ECPrivateKey) {
if (key instanceof ECPrivateKeyImpl) {
return;
}
} else {
throw new InvalidKeyException("Neither a public nor a private key");
}
// ECKey does not extend Key, so we need to do a cast
String keyAlg = ((Key)key).getAlgorithm();
if (keyAlg.equals("EC") == false) {
throw new InvalidKeyException("Not an EC key: " + keyAlg);
}
// XXX further sanity checks about whether this key uses supported
// fields, point formats, etc. would go here
}
/**
* Translate an EC key into a Sun EC key. If conversion is
* not possible, throw an InvalidKeyException.
* See also JCA doc.
*/
protected Key engineTranslateKey(Key key) throws InvalidKeyException {
if (key == null) {
throw new InvalidKeyException("Key must not be null");
}
String keyAlg = key.getAlgorithm();
if (keyAlg.equals("EC") == false) {
throw new InvalidKeyException("Not an EC key: " + keyAlg);
}
if (key instanceof PublicKey) {
return implTranslatePublicKey((PublicKey)key);
} else if (key instanceof PrivateKey) {
return implTranslatePrivateKey((PrivateKey)key);
} else {
throw new InvalidKeyException("Neither a public nor a private key");
}
}
// see JCA doc
protected PublicKey engineGeneratePublic(KeySpec keySpec)
throws InvalidKeySpecException {
try {
return implGeneratePublic(keySpec);
} catch (InvalidKeySpecException e) {
throw e;
} catch (GeneralSecurityException e) {
throw new InvalidKeySpecException(e);
}
}
// see JCA doc
protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
throws InvalidKeySpecException {
try {
return implGeneratePrivate(keySpec);
} catch (InvalidKeySpecException e) {
throw e;
} catch (GeneralSecurityException e) {
throw new InvalidKeySpecException(e);
}
}
// internal implementation of translateKey() for public keys. See JCA doc
private PublicKey implTranslatePublicKey(PublicKey key)
throws InvalidKeyException {
if (key instanceof ECPublicKey) {
if (key instanceof ECPublicKeyImpl) {
return key;
}
ECPublicKey ecKey = (ECPublicKey)key;
return new ECPublicKeyImpl(
ecKey.getW(),
ecKey.getParams()
);
} else if ("X.509".equals(key.getFormat())) {
byte[] encoded = key.getEncoded();
return new ECPublicKeyImpl(encoded);
} else {
throw new InvalidKeyException("Public keys must be instance "
+ "of ECPublicKey or have X.509 encoding");
}
}
// internal implementation of translateKey() for private keys. See JCA doc
private PrivateKey implTranslatePrivateKey(PrivateKey key)
throws InvalidKeyException {
if (key instanceof ECPrivateKey) {
if (key instanceof ECPrivateKeyImpl) {
return key;
}
ECPrivateKey ecKey = (ECPrivateKey)key;
return new ECPrivateKeyImpl(
ecKey.getS(),
ecKey.getParams()
);
} else if ("PKCS#8".equals(key.getFormat())) {
return new ECPrivateKeyImpl(key.getEncoded());
} else {
throw new InvalidKeyException("Private keys must be instance "
+ "of ECPrivateKey or have PKCS#8 encoding");
}
}
// internal implementation of generatePublic. See JCA doc
private PublicKey implGeneratePublic(KeySpec keySpec)
throws GeneralSecurityException {
if (keySpec instanceof X509EncodedKeySpec) {
X509EncodedKeySpec x509Spec = (X509EncodedKeySpec)keySpec;
return new ECPublicKeyImpl(x509Spec.getEncoded());
} else if (keySpec instanceof ECPublicKeySpec) {
ECPublicKeySpec ecSpec = (ECPublicKeySpec)keySpec;
return new ECPublicKeyImpl(
ecSpec.getW(),
ecSpec.getParams()
);
} else {
throw new InvalidKeySpecException("Only ECPublicKeySpec "
+ "and X509EncodedKeySpec supported for EC public keys");
}
}
// internal implementation of generatePrivate. See JCA doc
private PrivateKey implGeneratePrivate(KeySpec keySpec)
throws GeneralSecurityException {
if (keySpec instanceof PKCS8EncodedKeySpec) {
PKCS8EncodedKeySpec pkcsSpec = (PKCS8EncodedKeySpec)keySpec;
return new ECPrivateKeyImpl(pkcsSpec.getEncoded());
} else if (keySpec instanceof ECPrivateKeySpec) {
ECPrivateKeySpec ecSpec = (ECPrivateKeySpec)keySpec;
return new ECPrivateKeyImpl(ecSpec.getS(), ecSpec.getParams());
} else {
throw new InvalidKeySpecException("Only ECPrivateKeySpec "
+ "and PKCS8EncodedKeySpec supported for EC private keys");
}
}
protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec)
throws InvalidKeySpecException {
try {
// convert key to one of our keys
// this also verifies that the key is a valid EC key and ensures
// that the encoding is X.509/PKCS#8 for public/private keys
key = engineTranslateKey(key);
} catch (InvalidKeyException e) {
throw new InvalidKeySpecException(e);
}
if (key instanceof ECPublicKey) {
ECPublicKey ecKey = (ECPublicKey)key;
if (keySpec.isAssignableFrom(ECPublicKeySpec.class)) {
return keySpec.cast(new ECPublicKeySpec(
ecKey.getW(),
ecKey.getParams()
));
} else if (keySpec.isAssignableFrom(X509EncodedKeySpec.class)) {
return keySpec.cast(new X509EncodedKeySpec(key.getEncoded()));
} else {
throw new InvalidKeySpecException
("KeySpec must be ECPublicKeySpec or "
+ "X509EncodedKeySpec for EC public keys");
}
} else if (key instanceof ECPrivateKey) {
if (keySpec.isAssignableFrom(PKCS8EncodedKeySpec.class)) {
return keySpec.cast(new PKCS8EncodedKeySpec(key.getEncoded()));
} else if (keySpec.isAssignableFrom(ECPrivateKeySpec.class)) {
ECPrivateKey ecKey = (ECPrivateKey)key;
return keySpec.cast(new ECPrivateKeySpec(
ecKey.getS(),
ecKey.getParams()
));
} else {
throw new InvalidKeySpecException
("KeySpec must be ECPrivateKeySpec or "
+ "PKCS8EncodedKeySpec for EC private keys");
}
} else {
// should not occur, caught in engineTranslateKey()
throw new InvalidKeySpecException("Neither public nor private key");
}
}
}

View File

@@ -0,0 +1,268 @@
/*
* Copyright (c) 2009, 2018, 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 java.io.IOException;
import java.math.BigInteger;
import java.security.*;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.InvalidParameterSpecException;
import java.util.Optional;
import sun.security.jca.JCAUtil;
import sun.security.util.ECUtil;
import sun.security.util.math.*;
import sun.security.ec.point.*;
import static sun.security.util.SecurityProviderConstants.DEF_EC_KEY_SIZE;
import static sun.security.ec.ECOperations.IntermediateValueException;
/**
* EC keypair generator.
* Standard algorithm, minimum key length is 112 bits, maximum is 571 bits.
*
* @since 1.7
*/
public final class ECKeyPairGenerator extends KeyPairGeneratorSpi {
private static final int KEY_SIZE_MIN = 112; // min bits (see ecc_impl.h)
private static final int KEY_SIZE_MAX = 571; // max bits (see ecc_impl.h)
// used to seed the keypair generator
private SecureRandom random;
// size of the key to generate, KEY_SIZE_MIN <= keySize <= KEY_SIZE_MAX
private int keySize;
// parameters specified via init, if any
private AlgorithmParameterSpec params = null;
/**
* Constructs a new ECKeyPairGenerator.
*/
public ECKeyPairGenerator() {
// initialize to default in case the app does not call initialize()
initialize(DEF_EC_KEY_SIZE, null);
}
// initialize the generator. See JCA doc
@Override
public void initialize(int keySize, SecureRandom random) {
checkKeySize(keySize);
this.params = ECUtil.getECParameterSpec(null, keySize);
if (params == null) {
throw new InvalidParameterException(
"No EC parameters available for key size " + keySize + " bits");
}
this.random = random;
}
// second initialize method. See JCA doc
@Override
public void initialize(AlgorithmParameterSpec params, SecureRandom random)
throws InvalidAlgorithmParameterException {
ECParameterSpec ecSpec = null;
if (params instanceof ECParameterSpec) {
ECParameterSpec ecParams = (ECParameterSpec) params;
ecSpec = ECUtil.getECParameterSpec(null, ecParams);
if (ecSpec == null) {
throw new InvalidAlgorithmParameterException(
"Unsupported curve: " + params);
}
} else if (params instanceof ECGenParameterSpec) {
String name = ((ECGenParameterSpec) params).getName();
ecSpec = ECUtil.getECParameterSpec(null, name);
if (ecSpec == null) {
throw new InvalidAlgorithmParameterException(
"Unknown curve name: " + name);
}
} else {
throw new InvalidAlgorithmParameterException(
"ECParameterSpec or ECGenParameterSpec required for EC");
}
// Not all known curves are supported by the native implementation
ensureCurveIsSupported(ecSpec);
this.params = ecSpec;
this.keySize = ecSpec.getCurve().getField().getFieldSize();
this.random = random;
}
private static void ensureCurveIsSupported(ECParameterSpec ecSpec)
throws InvalidAlgorithmParameterException {
AlgorithmParameters ecParams = ECUtil.getECParameters(null);
byte[] encodedParams;
try {
ecParams.init(ecSpec);
encodedParams = ecParams.getEncoded();
} catch (InvalidParameterSpecException ex) {
throw new InvalidAlgorithmParameterException(
"Unsupported curve: " + ecSpec.toString());
} catch (IOException ex) {
throw new RuntimeException(ex);
}
if (!isCurveSupported(encodedParams)) {
throw new InvalidAlgorithmParameterException(
"Unsupported curve: " + ecParams.toString());
}
}
// generate the keypair. See JCA doc
@Override
public KeyPair generateKeyPair() {
if (random == null) {
random = JCAUtil.getSecureRandom();
}
try {
Optional<KeyPair> kp = generateKeyPairImpl(random);
if (kp.isPresent()) {
return kp.get();
}
return generateKeyPairNative(random);
} catch (Exception ex) {
throw new ProviderException(ex);
}
}
private byte[] generatePrivateScalar(SecureRandom random,
ECOperations ecOps, int seedSize) {
// Attempt to create the private scalar in a loop that uses new random
// input each time. The chance of failure is very small assuming the
// implementation derives the nonce using extra bits
int numAttempts = 128;
byte[] seedArr = new byte[seedSize];
for (int i = 0; i < numAttempts; i++) {
random.nextBytes(seedArr);
try {
return ecOps.seedToScalar(seedArr);
} catch (IntermediateValueException ex) {
// try again in the next iteration
}
}
throw new ProviderException("Unable to produce private key after "
+ numAttempts + " attempts");
}
private Optional<KeyPair> generateKeyPairImpl(SecureRandom random)
throws InvalidKeyException {
ECParameterSpec ecParams = (ECParameterSpec) params;
Optional<ECOperations> opsOpt = ECOperations.forParameters(ecParams);
if (!opsOpt.isPresent()) {
return Optional.empty();
}
ECOperations ops = opsOpt.get();
IntegerFieldModuloP field = ops.getField();
int numBits = ecParams.getOrder().bitLength();
int seedBits = numBits + 64;
int seedSize = (seedBits + 7) / 8;
byte[] privArr = generatePrivateScalar(random, ops, seedSize);
ECPoint genPoint = ecParams.getGenerator();
ImmutableIntegerModuloP x = field.getElement(genPoint.getAffineX());
ImmutableIntegerModuloP y = field.getElement(genPoint.getAffineY());
AffinePoint affGen = new AffinePoint(x, y);
Point pub = ops.multiply(affGen, privArr);
AffinePoint affPub = pub.asAffine();
PrivateKey privateKey = new ECPrivateKeyImpl(privArr, ecParams);
ECPoint w = new ECPoint(affPub.getX().asBigInteger(),
affPub.getY().asBigInteger());
PublicKey publicKey = new ECPublicKeyImpl(w, ecParams);
return Optional.of(new KeyPair(publicKey, privateKey));
}
private KeyPair generateKeyPairNative(SecureRandom random)
throws Exception {
ECParameterSpec ecParams = (ECParameterSpec) params;
byte[] encodedParams = ECUtil.encodeECParameterSpec(null, ecParams);
// seed is twice the key size (in bytes) plus 1
byte[] seed = new byte[(((keySize + 7) >> 3) + 1) * 2];
random.nextBytes(seed);
Object[] keyBytes = generateECKeyPair(keySize, encodedParams, seed);
// The 'params' object supplied above is equivalent to the native
// one so there is no need to fetch it.
// keyBytes[0] is the encoding of the native private key
BigInteger s = new BigInteger(1, (byte[]) keyBytes[0]);
PrivateKey privateKey = new ECPrivateKeyImpl(s, ecParams);
// keyBytes[1] is the encoding of the native public key
byte[] pubKey = (byte[]) keyBytes[1];
ECPoint w = ECUtil.decodePoint(pubKey, ecParams.getCurve());
PublicKey publicKey = new ECPublicKeyImpl(w, ecParams);
return new KeyPair(publicKey, privateKey);
}
private void checkKeySize(int keySize) throws InvalidParameterException {
if (keySize < KEY_SIZE_MIN) {
throw new InvalidParameterException
("Key size must be at least " + KEY_SIZE_MIN + " bits");
}
if (keySize > KEY_SIZE_MAX) {
throw new InvalidParameterException
("Key size must be at most " + KEY_SIZE_MAX + " bits");
}
this.keySize = keySize;
}
/**
* Checks whether the curve in the encoded parameters is supported by the
* native implementation. Some curve operations will be performed by the
* Java implementation, but not all of them. So native support is still
* required for all curves.
*
* @param encodedParams encoded parameters in the same form accepted
* by generateECKeyPair
* @return true if and only if generateECKeyPair will succeed for
* the supplied parameters
*/
private static native boolean isCurveSupported(byte[] encodedParams);
/*
* Generates the keypair and returns a 2-element array of encoding bytes.
* The first one is for the private key, the second for the public key.
*/
private static native Object[] generateECKeyPair(int keySize,
byte[] encodedParams, byte[] seed) throws GeneralSecurityException;
}

View File

@@ -0,0 +1,499 @@
/*
* Copyright (c) 2018, 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.ec.point.*;
import sun.security.util.math.*;
import sun.security.util.math.intpoly.*;
import java.math.BigInteger;
import java.security.ProviderException;
import java.security.spec.ECFieldFp;
import java.security.spec.ECParameterSpec;
import java.security.spec.EllipticCurve;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
/*
* Elliptic curve point arithmetic for prime-order curves where a=-3.
* Formulas are derived from "Complete addition formulas for prime order
* elliptic curves" by Renes, Costello, and Batina.
*/
public class ECOperations {
/*
* An exception indicating a problem with an intermediate value produced
* by some part of the computation. For example, the signing operation
* will throw this exception to indicate that the r or s value is 0, and
* that the signing operation should be tried again with a different nonce.
*/
static class IntermediateValueException extends Exception {
private static final long serialVersionUID = 1;
}
static final Map<BigInteger, IntegerFieldModuloP> fields;
static final Map<BigInteger, IntegerFieldModuloP> orderFields;
static {
Map<BigInteger, IntegerFieldModuloP> map = new HashMap<>();
map.put(IntegerPolynomialP256.MODULUS, new IntegerPolynomialP256());
map.put(IntegerPolynomialP384.MODULUS, new IntegerPolynomialP384());
map.put(IntegerPolynomialP521.MODULUS, new IntegerPolynomialP521());
fields = Collections.unmodifiableMap(map);
map = new HashMap<>();
map.put(P256OrderField.MODULUS, new P256OrderField());
map.put(P384OrderField.MODULUS, new P384OrderField());
map.put(P521OrderField.MODULUS, new P521OrderField());
orderFields = Collections.unmodifiableMap(map);
}
public static Optional<ECOperations> forParameters(ECParameterSpec params) {
EllipticCurve curve = params.getCurve();
if (!(curve.getField() instanceof ECFieldFp)) {
return Optional.empty();
}
ECFieldFp primeField = (ECFieldFp) curve.getField();
BigInteger three = BigInteger.valueOf(3);
if (!primeField.getP().subtract(curve.getA()).equals(three)) {
return Optional.empty();
}
IntegerFieldModuloP field = fields.get(primeField.getP());
if (field == null) {
return Optional.empty();
}
IntegerFieldModuloP orderField = orderFields.get(params.getOrder());
if (orderField == null) {
return Optional.empty();
}
ImmutableIntegerModuloP b = field.getElement(curve.getB());
ECOperations ecOps = new ECOperations(b, orderField);
return Optional.of(ecOps);
}
final ImmutableIntegerModuloP b;
final SmallValue one;
final SmallValue two;
final SmallValue three;
final SmallValue four;
final ProjectivePoint.Immutable neutral;
private final IntegerFieldModuloP orderField;
public ECOperations(IntegerModuloP b, IntegerFieldModuloP orderField) {
this.b = b.fixed();
this.orderField = orderField;
this.one = b.getField().getSmallValue(1);
this.two = b.getField().getSmallValue(2);
this.three = b.getField().getSmallValue(3);
this.four = b.getField().getSmallValue(4);
IntegerFieldModuloP field = b.getField();
this.neutral = new ProjectivePoint.Immutable(field.get0(),
field.get1(), field.get0());
}
public IntegerFieldModuloP getField() {
return b.getField();
}
public IntegerFieldModuloP getOrderField() {
return orderField;
}
protected ProjectivePoint.Immutable getNeutral() {
return neutral;
}
public boolean isNeutral(Point p) {
ProjectivePoint<?> pp = (ProjectivePoint<?>) p;
IntegerModuloP z = pp.getZ();
IntegerFieldModuloP field = z.getField();
int byteLength = (field.getSize().bitLength() + 7) / 8;
byte[] zBytes = z.asByteArray(byteLength);
return allZero(zBytes);
}
byte[] seedToScalar(byte[] seedBytes)
throws IntermediateValueException {
// Produce a nonce from the seed using FIPS 186-4,section B.5.1:
// Per-Message Secret Number Generation Using Extra Random Bits
// or
// Produce a scalar from the seed using FIPS 186-4, section B.4.1:
// Key Pair Generation Using Extra Random Bits
// To keep the implementation simple, sample in the range [0,n)
// and throw IntermediateValueException in the (unlikely) event
// that the result is 0.
// Get 64 extra bits and reduce in to the nonce
int seedBits = orderField.getSize().bitLength() + 64;
if (seedBytes.length * 8 < seedBits) {
throw new ProviderException("Incorrect seed length: " +
seedBytes.length * 8 + " < " + seedBits);
}
// input conversion only works on byte boundaries
// clear high-order bits of last byte so they don't influence nonce
int lastByteBits = seedBits % 8;
if (lastByteBits != 0) {
int lastByteIndex = seedBits / 8;
byte mask = (byte) (0xFF >>> (8 - lastByteBits));
seedBytes[lastByteIndex] &= mask;
}
int seedLength = (seedBits + 7) / 8;
IntegerModuloP scalarElem =
orderField.getElement(seedBytes, 0, seedLength, (byte) 0);
int scalarLength = (orderField.getSize().bitLength() + 7) / 8;
byte[] scalarArr = new byte[scalarLength];
scalarElem.asByteArray(scalarArr);
if (ECOperations.allZero(scalarArr)) {
throw new IntermediateValueException();
}
return scalarArr;
}
/*
* Compare all values in the array to 0 without branching on any value
*
*/
public static boolean allZero(byte[] arr) {
byte acc = 0;
for (int i = 0; i < arr.length; i++) {
acc |= arr[i];
}
return acc == 0;
}
/*
* 4-bit branchless array lookup for projective points.
*/
private void lookup4(ProjectivePoint.Immutable[] arr, int index,
ProjectivePoint.Mutable result, IntegerModuloP zero) {
for (int i = 0; i < 16; i++) {
int xor = index ^ i;
int bit3 = (xor & 0x8) >>> 3;
int bit2 = (xor & 0x4) >>> 2;
int bit1 = (xor & 0x2) >>> 1;
int bit0 = (xor & 0x1);
int inverse = bit0 | bit1 | bit2 | bit3;
int set = 1 - inverse;
ProjectivePoint.Immutable pi = arr[i];
result.conditionalSet(pi, set);
}
}
private void double4(ProjectivePoint.Mutable p, MutableIntegerModuloP t0,
MutableIntegerModuloP t1, MutableIntegerModuloP t2,
MutableIntegerModuloP t3, MutableIntegerModuloP t4) {
for (int i = 0; i < 4; i++) {
setDouble(p, t0, t1, t2, t3, t4);
}
}
/**
* Multiply an affine point by a scalar and return the result as a mutable
* point.
*
* @param affineP the point
* @param s the scalar as a little-endian array
* @return the product
*/
public MutablePoint multiply(AffinePoint affineP, byte[] s) {
// 4-bit windowed multiply with branchless lookup.
// The mixed addition is faster, so it is used to construct the array
// at the beginning of the operation.
IntegerFieldModuloP field = affineP.getX().getField();
ImmutableIntegerModuloP zero = field.get0();
// temporaries
MutableIntegerModuloP t0 = zero.mutable();
MutableIntegerModuloP t1 = zero.mutable();
MutableIntegerModuloP t2 = zero.mutable();
MutableIntegerModuloP t3 = zero.mutable();
MutableIntegerModuloP t4 = zero.mutable();
ProjectivePoint.Mutable result = new ProjectivePoint.Mutable(field);
result.getY().setValue(field.get1().mutable());
ProjectivePoint.Immutable[] pointMultiples =
new ProjectivePoint.Immutable[16];
// 0P is neutral---same as initial result value
pointMultiples[0] = result.fixed();
ProjectivePoint.Mutable ps = new ProjectivePoint.Mutable(field);
ps.setValue(affineP);
// 1P = P
pointMultiples[1] = ps.fixed();
// the rest are calculated using mixed point addition
for (int i = 2; i < 16; i++) {
setSum(ps, affineP, t0, t1, t2, t3, t4);
pointMultiples[i] = ps.fixed();
}
ProjectivePoint.Mutable lookupResult = ps.mutable();
for (int i = s.length - 1; i >= 0; i--) {
double4(result, t0, t1, t2, t3, t4);
int high = (0xFF & s[i]) >>> 4;
lookup4(pointMultiples, high, lookupResult, zero);
setSum(result, lookupResult, t0, t1, t2, t3, t4);
double4(result, t0, t1, t2, t3, t4);
int low = 0xF & s[i];
lookup4(pointMultiples, low, lookupResult, zero);
setSum(result, lookupResult, t0, t1, t2, t3, t4);
}
return result;
}
/*
* Point double
*/
private void setDouble(ProjectivePoint.Mutable p, MutableIntegerModuloP t0,
MutableIntegerModuloP t1, MutableIntegerModuloP t2,
MutableIntegerModuloP t3, MutableIntegerModuloP t4) {
t0.setValue(p.getX()).setSquare();
t1.setValue(p.getY()).setSquare();
t2.setValue(p.getZ()).setSquare();
t3.setValue(p.getX()).setProduct(p.getY());
t4.setValue(p.getY()).setProduct(p.getZ());
t3.setSum(t3);
p.getZ().setProduct(p.getX());
p.getZ().setProduct(two);
p.getY().setValue(t2).setProduct(b);
p.getY().setDifference(p.getZ());
p.getX().setValue(p.getY()).setProduct(two);
p.getY().setSum(p.getX());
p.getY().setReduced();
p.getX().setValue(t1).setDifference(p.getY());
p.getY().setSum(t1);
p.getY().setProduct(p.getX());
p.getX().setProduct(t3);
t3.setValue(t2).setProduct(two);
t2.setSum(t3);
p.getZ().setProduct(b);
t2.setReduced();
p.getZ().setDifference(t2);
p.getZ().setDifference(t0);
t3.setValue(p.getZ()).setProduct(two);
p.getZ().setReduced();
p.getZ().setSum(t3);
t0.setProduct(three);
t0.setDifference(t2);
t0.setProduct(p.getZ());
p.getY().setSum(t0);
t4.setSum(t4);
p.getZ().setProduct(t4);
p.getX().setDifference(p.getZ());
p.getZ().setValue(t4).setProduct(t1);
p.getZ().setProduct(four);
}
/*
* Mixed point addition. This method constructs new temporaries each time
* it is called. For better efficiency, the method that reuses temporaries
* should be used if more than one sum will be computed.
*/
public void setSum(MutablePoint p, AffinePoint p2) {
IntegerModuloP zero = p.getField().get0();
MutableIntegerModuloP t0 = zero.mutable();
MutableIntegerModuloP t1 = zero.mutable();
MutableIntegerModuloP t2 = zero.mutable();
MutableIntegerModuloP t3 = zero.mutable();
MutableIntegerModuloP t4 = zero.mutable();
setSum((ProjectivePoint.Mutable) p, p2, t0, t1, t2, t3, t4);
}
/*
* Mixed point addition
*/
private void setSum(ProjectivePoint.Mutable p, AffinePoint p2,
MutableIntegerModuloP t0, MutableIntegerModuloP t1,
MutableIntegerModuloP t2, MutableIntegerModuloP t3,
MutableIntegerModuloP t4) {
t0.setValue(p.getX()).setProduct(p2.getX());
t1.setValue(p.getY()).setProduct(p2.getY());
t3.setValue(p2.getX()).setSum(p2.getY());
t4.setValue(p.getX()).setSum(p.getY());
p.getX().setReduced();
t3.setProduct(t4);
t4.setValue(t0).setSum(t1);
t3.setDifference(t4);
t4.setValue(p2.getY()).setProduct(p.getZ());
t4.setSum(p.getY());
p.getY().setValue(p2.getX()).setProduct(p.getZ());
p.getY().setSum(p.getX());
t2.setValue(p.getZ());
p.getZ().setProduct(b);
p.getX().setValue(p.getY()).setDifference(p.getZ());
p.getX().setReduced();
p.getZ().setValue(p.getX()).setProduct(two);
p.getX().setSum(p.getZ());
p.getZ().setValue(t1).setDifference(p.getX());
p.getX().setSum(t1);
p.getY().setProduct(b);
t1.setValue(t2).setProduct(two);
t2.setSum(t1);
t2.setReduced();
p.getY().setDifference(t2);
p.getY().setDifference(t0);
p.getY().setReduced();
t1.setValue(p.getY()).setProduct(two);
p.getY().setSum(t1);
t1.setValue(t0).setProduct(two);
t0.setSum(t1);
t0.setDifference(t2);
t1.setValue(t4).setProduct(p.getY());
t2.setValue(t0).setProduct(p.getY());
p.getY().setValue(p.getX()).setProduct(p.getZ());
p.getY().setSum(t2);
p.getX().setProduct(t3);
p.getX().setDifference(t1);
p.getZ().setProduct(t4);
t1.setValue(t3).setProduct(t0);
p.getZ().setSum(t1);
}
/*
* Projective point addition
*/
private void setSum(ProjectivePoint.Mutable p, ProjectivePoint.Mutable p2,
MutableIntegerModuloP t0, MutableIntegerModuloP t1,
MutableIntegerModuloP t2, MutableIntegerModuloP t3,
MutableIntegerModuloP t4) {
t0.setValue(p.getX()).setProduct(p2.getX());
t1.setValue(p.getY()).setProduct(p2.getY());
t2.setValue(p.getZ()).setProduct(p2.getZ());
t3.setValue(p.getX()).setSum(p.getY());
t4.setValue(p2.getX()).setSum(p2.getY());
t3.setProduct(t4);
t4.setValue(t0).setSum(t1);
t3.setDifference(t4);
t4.setValue(p.getY()).setSum(p.getZ());
p.getY().setValue(p2.getY()).setSum(p2.getZ());
t4.setProduct(p.getY());
p.getY().setValue(t1).setSum(t2);
t4.setDifference(p.getY());
p.getX().setSum(p.getZ());
p.getY().setValue(p2.getX()).setSum(p2.getZ());
p.getX().setProduct(p.getY());
p.getY().setValue(t0).setSum(t2);
p.getY().setAdditiveInverse().setSum(p.getX());
p.getY().setReduced();
p.getZ().setValue(t2).setProduct(b);
p.getX().setValue(p.getY()).setDifference(p.getZ());
p.getZ().setValue(p.getX()).setProduct(two);
p.getX().setSum(p.getZ());
p.getX().setReduced();
p.getZ().setValue(t1).setDifference(p.getX());
p.getX().setSum(t1);
p.getY().setProduct(b);
t1.setValue(t2).setSum(t2);
t2.setSum(t1);
t2.setReduced();
p.getY().setDifference(t2);
p.getY().setDifference(t0);
p.getY().setReduced();
t1.setValue(p.getY()).setSum(p.getY());
p.getY().setSum(t1);
t1.setValue(t0).setProduct(two);
t0.setSum(t1);
t0.setDifference(t2);
t1.setValue(t4).setProduct(p.getY());
t2.setValue(t0).setProduct(p.getY());
p.getY().setValue(p.getX()).setProduct(p.getZ());
p.getY().setSum(t2);
p.getX().setProduct(t3);
p.getX().setDifference(t1);
p.getZ().setProduct(t4);
t1.setValue(t3).setProduct(t0);
p.getZ().setSum(t1);
}
}

View File

@@ -0,0 +1,233 @@
/*
* Copyright (c) 2006, 2018, 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 java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.math.BigInteger;
import java.security.*;
import java.security.interfaces.*;
import java.security.spec.*;
import sun.security.util.ArrayUtil;
import sun.security.util.DerInputStream;
import sun.security.util.DerOutputStream;
import sun.security.util.DerValue;
import sun.security.util.ECParameters;
import sun.security.util.ECUtil;
import sun.security.x509.AlgorithmId;
import sun.security.pkcs.PKCS8Key;
/**
* Key implementation for EC private keys.
* <p>
* ASN.1 syntax for EC private keys from SEC 1 v1.5 (draft):
*
* <pre>
* EXPLICIT TAGS
*
* ECPrivateKey ::= SEQUENCE {
* version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
* privateKey OCTET STRING,
* parameters [0] ECDomainParameters {{ SECGCurveNames }} OPTIONAL,
* publicKey [1] BIT STRING OPTIONAL
* }
* </pre>
*
* We currently ignore the optional parameters and publicKey fields. We
* require that the parameters are encoded as part of the AlgorithmIdentifier,
* not in the private key structure.
*
* @since 1.6
* @author Andreas Sterbenz
*/
public final class ECPrivateKeyImpl extends PKCS8Key implements ECPrivateKey {
private static final long serialVersionUID = 88695385615075129L;
private BigInteger s; // private value
private byte[] arrayS; // private value as a little-endian array
private ECParameterSpec params;
/**
* Construct a key from its encoding. Called by the ECKeyFactory.
*/
public ECPrivateKeyImpl(byte[] encoded) throws InvalidKeyException {
decode(encoded);
}
/**
* Construct a key from its components. Used by the
* KeyFactory.
*/
public ECPrivateKeyImpl(BigInteger s, ECParameterSpec params)
throws InvalidKeyException {
this.s = s;
this.params = params;
makeEncoding(s);
}
ECPrivateKeyImpl(byte[] s, ECParameterSpec params)
throws InvalidKeyException {
this.arrayS = s.clone();
this.params = params;
makeEncoding(s);
}
private void makeEncoding(byte[] s) throws InvalidKeyException {
algid = new AlgorithmId
(AlgorithmId.EC_oid, ECParameters.getAlgorithmParameters(params));
try {
DerOutputStream out = new DerOutputStream();
out.putInteger(1); // version 1
byte[] privBytes = s.clone();
ArrayUtil.reverse(privBytes);
out.putOctetString(privBytes);
DerValue val =
new DerValue(DerValue.tag_Sequence, out.toByteArray());
key = val.toByteArray();
} catch (IOException exc) {
// should never occur
throw new InvalidKeyException(exc);
}
}
private void makeEncoding(BigInteger s) throws InvalidKeyException {
algid = new AlgorithmId
(AlgorithmId.EC_oid, ECParameters.getAlgorithmParameters(params));
try {
byte[] sArr = s.toByteArray();
// convert to fixed-length array
int numOctets = (params.getOrder().bitLength() + 7) / 8;
byte[] sOctets = new byte[numOctets];
int inPos = Math.max(sArr.length - sOctets.length, 0);
int outPos = Math.max(sOctets.length - sArr.length, 0);
int length = Math.min(sArr.length, sOctets.length);
System.arraycopy(sArr, inPos, sOctets, outPos, length);
DerOutputStream out = new DerOutputStream();
out.putInteger(1); // version 1
out.putOctetString(sOctets);
DerValue val =
new DerValue(DerValue.tag_Sequence, out.toByteArray());
key = val.toByteArray();
} catch (IOException exc) {
// should never occur
throw new InvalidKeyException(exc);
}
}
// see JCA doc
public String getAlgorithm() {
return "EC";
}
// see JCA doc
public BigInteger getS() {
if (s == null) {
byte[] arrCopy = arrayS.clone();
ArrayUtil.reverse(arrCopy);
s = new BigInteger(1, arrCopy);
}
return s;
}
public byte[] getArrayS() {
if (arrayS == null) {
byte[] arr = getS().toByteArray();
ArrayUtil.reverse(arr);
int byteLength = (params.getOrder().bitLength() + 7) / 8;
arrayS = new byte[byteLength];
int length = Math.min(byteLength, arr.length);
System.arraycopy(arr, 0, arrayS, 0, length);
}
return arrayS.clone();
}
// see JCA doc
public ECParameterSpec getParams() {
return params;
}
/**
* Parse the key. Called by PKCS8Key.
*/
protected void parseKeyBits() throws InvalidKeyException {
try {
DerInputStream in = new DerInputStream(key);
DerValue derValue = in.getDerValue();
if (derValue.tag != DerValue.tag_Sequence) {
throw new IOException("Not a SEQUENCE");
}
DerInputStream data = derValue.data;
int version = data.getInteger();
if (version != 1) {
throw new IOException("Version must be 1");
}
byte[] privData = data.getOctetString();
ArrayUtil.reverse(privData);
arrayS = privData;
while (data.available() != 0) {
DerValue value = data.getDerValue();
if (value.isContextSpecific((byte) 0)) {
// ignore for now
} else if (value.isContextSpecific((byte) 1)) {
// ignore for now
} else {
throw new InvalidKeyException("Unexpected value: " + value);
}
}
AlgorithmParameters algParams = this.algid.getParameters();
if (algParams == null) {
throw new InvalidKeyException("EC domain parameters must be "
+ "encoded in the algorithm identifier");
}
params = algParams.getParameterSpec(ECParameterSpec.class);
} catch (IOException e) {
throw new InvalidKeyException("Invalid EC private key", e);
} catch (InvalidParameterSpecException e) {
throw new InvalidKeyException("Invalid EC private key", e);
}
}
/**
* Restores the state of this object from the stream.
* <p>
* Deserialization of this object is not supported.
*
* @param stream the {@code ObjectInputStream} from which data is read
* @throws IOException if an I/O error occurs
* @throws ClassNotFoundException if a serialized class cannot be loaded
*/
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException {
throw new InvalidObjectException(
"ECPrivateKeyImpl keys are not directly deserializable");
}
}

View File

@@ -0,0 +1,148 @@
/*
* Copyright (c) 2006, 2023, 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 java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.security.*;
import java.security.interfaces.*;
import java.security.spec.*;
import sun.security.util.ECParameters;
import sun.security.util.ECUtil;
import sun.security.x509.*;
/**
* Key implementation for EC public keys.
*
* @since 1.6
* @author Andreas Sterbenz
*/
public final class ECPublicKeyImpl extends X509Key implements ECPublicKey {
private static final long serialVersionUID = -2462037275160462289L;
private ECPoint w;
private ECParameterSpec params;
/**
* Construct a key from its components. Used by the
* ECKeyFactory.
*/
@SuppressWarnings("deprecation")
public ECPublicKeyImpl(ECPoint w, ECParameterSpec params)
throws InvalidKeyException {
this.w = w;
this.params = params;
// generate the encoding
algid = new AlgorithmId
(AlgorithmId.EC_oid, ECParameters.getAlgorithmParameters(params));
key = ECUtil.encodePoint(w, params.getCurve());
}
/**
* Construct a key from its encoding.
*/
public ECPublicKeyImpl(byte[] encoded) throws InvalidKeyException {
decode(encoded);
}
// see JCA doc
public String getAlgorithm() {
return "EC";
}
// see JCA doc
public ECPoint getW() {
return w;
}
// see JCA doc
public ECParameterSpec getParams() {
return params;
}
// Internal API to get the encoded point. Currently used by SunPKCS11.
// This may change/go away depending on what we do with the public API.
@SuppressWarnings("deprecation")
public byte[] getEncodedPublicValue() {
return key.clone();
}
/**
* Parse the key. Called by X509Key.
*/
@SuppressWarnings("deprecation")
protected void parseKeyBits() throws InvalidKeyException {
AlgorithmParameters algParams = this.algid.getParameters();
if (algParams == null) {
throw new InvalidKeyException("EC domain parameters must be " +
"encoded in the algorithm identifier");
}
try {
params = algParams.getParameterSpec(ECParameterSpec.class);
w = ECUtil.decodePoint(key, params.getCurve());
} catch (IOException e) {
throw new InvalidKeyException("Invalid EC key", e);
} catch (InvalidParameterSpecException e) {
throw new InvalidKeyException("Invalid EC key", e);
}
}
// return a string representation of this key for debugging
public String toString() {
return "Sun EC public key, " + params.getCurve().getField().getFieldSize()
+ " bits\n public x coord: " + w.getAffineX()
+ "\n public y coord: " + w.getAffineY()
+ "\n parameters: " + params;
}
private Object writeReplace() throws java.io.ObjectStreamException {
return new KeyRep(KeyRep.Type.PUBLIC,
getAlgorithm(),
getFormat(),
getEncoded());
}
/**
* Restores the state of this object from the stream.
* <p>
* Deserialization of this object is not supported.
*
* @param stream the {@code ObjectInputStream} from which data is read
* @throws IOException if an I/O error occurs
* @throws ClassNotFoundException if a serialized class cannot be loaded
*/
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException {
throw new InvalidObjectException(
"ECPublicKeyImpl keys are not directly deserializable");
}
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright (c) 2009, 2013, 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 java.util.*;
import java.security.*;
import sun.security.action.PutAllAction;
/**
* Provider class for the Elliptic Curve provider.
* Supports EC keypair and parameter generation, ECDSA signing and
* ECDH key agreement.
*
* IMPLEMENTATION NOTE:
* The Java classes in this provider access a native ECC implementation
* via JNI to a C++ wrapper class which in turn calls C functions.
* The Java classes are packaged into the signed sunec.jar in the JRE
* extensions directory and the C++ and C functions are packaged into
* libsunec.so or sunec.dll in the JRE native libraries directory.
* If the native library is not present then this provider is registered
* with support for fewer ECC algorithms (KeyPairGenerator, Signature and
* KeyAgreement are omitted).
*
* @since 1.7
*/
public final class SunEC extends Provider {
private static final long serialVersionUID = -2279741672933606418L;
// flag indicating whether the full EC implementation is present
// (when native library is absent then fewer EC algorithms are available)
private static boolean useFullImplementation = true;
static {
try {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
System.loadLibrary("sunec"); // check for native library
return null;
}
});
} catch (UnsatisfiedLinkError e) {
useFullImplementation = false;
}
}
public SunEC() {
super("SunEC", 1.8d, "Sun Elliptic Curve provider (EC, ECDSA, ECDH)");
// if there is no security manager installed, put directly into
// the provider. Otherwise, create a temporary map and use a
// doPrivileged() call at the end to transfer the contents
if (System.getSecurityManager() == null) {
SunECEntries.putEntries(this, useFullImplementation);
} else {
Map<Object, Object> map = new HashMap<Object, Object>();
SunECEntries.putEntries(map, useFullImplementation);
AccessController.doPrivileged(new PutAllAction(this, map));
}
}
}

View File

@@ -0,0 +1,171 @@
/*
* Copyright (c) 2009, 2014, 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 java.util.Collection;
import java.util.Map;
import java.util.regex.Pattern;
import sun.security.util.CurveDB;
import sun.security.util.NamedCurve;
/**
* Defines the entries of the SunEC provider.
*
* @since 1.7
*/
final class SunECEntries {
private SunECEntries() {
// empty
}
static void putEntries(Map<Object, Object> map,
boolean useFullImplementation) {
/*
* Key Factory engine
*/
map.put("KeyFactory.EC", "sun.security.ec.ECKeyFactory");
map.put("Alg.Alias.KeyFactory.EllipticCurve", "EC");
map.put("KeyFactory.EC ImplementedIn", "Software");
/*
* Algorithm Parameter engine
*/
map.put("AlgorithmParameters.EC", "sun.security.util.ECParameters");
map.put("Alg.Alias.AlgorithmParameters.EllipticCurve", "EC");
map.put("Alg.Alias.AlgorithmParameters.1.2.840.10045.2.1", "EC");
map.put("AlgorithmParameters.EC KeySize", "256");
map.put("AlgorithmParameters.EC ImplementedIn", "Software");
// "AlgorithmParameters.EC SupportedCurves" prop used by unit test
boolean firstCurve = true;
StringBuilder names = new StringBuilder();
Pattern nameSplitPattern = Pattern.compile(CurveDB.SPLIT_PATTERN);
Collection<? extends NamedCurve> supportedCurves =
CurveDB.getSupportedCurves();
for (NamedCurve namedCurve : supportedCurves) {
if (!firstCurve) {
names.append("|");
} else {
firstCurve = false;
}
names.append("[");
String[] commonNames = nameSplitPattern.split(namedCurve.getName());
for (String commonName : commonNames) {
names.append(commonName.trim());
names.append(",");
}
names.append(namedCurve.getObjectId());
names.append("]");
}
map.put("AlgorithmParameters.EC SupportedCurves", names.toString());
/*
* Register the algorithms below only when the full ECC implementation
* is available
*/
if (!useFullImplementation) {
return;
}
/*
* Signature engines
*/
map.put("Signature.NONEwithECDSA",
"sun.security.ec.ECDSASignature$Raw");
map.put("Signature.SHA1withECDSA",
"sun.security.ec.ECDSASignature$SHA1");
map.put("Alg.Alias.Signature.OID.1.2.840.10045.4.1", "SHA1withECDSA");
map.put("Alg.Alias.Signature.1.2.840.10045.4.1", "SHA1withECDSA");
map.put("Signature.SHA224withECDSA",
"sun.security.ec.ECDSASignature$SHA224");
map.put("Alg.Alias.Signature.OID.1.2.840.10045.4.3.1", "SHA224withECDSA");
map.put("Alg.Alias.Signature.1.2.840.10045.4.3.1", "SHA224withECDSA");
map.put("Signature.SHA256withECDSA",
"sun.security.ec.ECDSASignature$SHA256");
map.put("Alg.Alias.Signature.OID.1.2.840.10045.4.3.2", "SHA256withECDSA");
map.put("Alg.Alias.Signature.1.2.840.10045.4.3.2", "SHA256withECDSA");
map.put("Signature.SHA384withECDSA",
"sun.security.ec.ECDSASignature$SHA384");
map.put("Alg.Alias.Signature.OID.1.2.840.10045.4.3.3", "SHA384withECDSA");
map.put("Alg.Alias.Signature.1.2.840.10045.4.3.3", "SHA384withECDSA");
map.put("Signature.SHA512withECDSA",
"sun.security.ec.ECDSASignature$SHA512");
map.put("Alg.Alias.Signature.OID.1.2.840.10045.4.3.4", "SHA512withECDSA");
map.put("Alg.Alias.Signature.1.2.840.10045.4.3.4", "SHA512withECDSA");
String ecKeyClasses = "java.security.interfaces.ECPublicKey" +
"|java.security.interfaces.ECPrivateKey";
map.put("Signature.NONEwithECDSA SupportedKeyClasses", ecKeyClasses);
map.put("Signature.SHA1withECDSA SupportedKeyClasses", ecKeyClasses);
map.put("Signature.SHA224withECDSA SupportedKeyClasses", ecKeyClasses);
map.put("Signature.SHA256withECDSA SupportedKeyClasses", ecKeyClasses);
map.put("Signature.SHA384withECDSA SupportedKeyClasses", ecKeyClasses);
map.put("Signature.SHA512withECDSA SupportedKeyClasses", ecKeyClasses);
map.put("Signature.SHA1withECDSA KeySize", "256");
map.put("Signature.NONEwithECDSA ImplementedIn", "Software");
map.put("Signature.SHA1withECDSA ImplementedIn", "Software");
map.put("Signature.SHA224withECDSA ImplementedIn", "Software");
map.put("Signature.SHA256withECDSA ImplementedIn", "Software");
map.put("Signature.SHA384withECDSA ImplementedIn", "Software");
map.put("Signature.SHA512withECDSA ImplementedIn", "Software");
/*
* Key Pair Generator engine
*/
map.put("KeyPairGenerator.EC", "sun.security.ec.ECKeyPairGenerator");
map.put("Alg.Alias.KeyPairGenerator.EllipticCurve", "EC");
map.put("KeyPairGenerator.EC KeySize", "256");
map.put("KeyPairGenerator.EC ImplementedIn", "Software");
/*
* Key Agreement engine
*/
map.put("KeyAgreement.ECDH", "sun.security.ec.ECDHKeyAgreement");
map.put("KeyAgreement.ECDH SupportedKeyClasses", ecKeyClasses);
map.put("KeyAgreement.ECDH ImplementedIn", "Software");
}
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright (c) 2018, 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.ImmutableIntegerModuloP;
import java.util.Objects;
/**
* Elliptic curve point represented using affine coordinates (x, y). This class
* is not part of the sun.security.ec.point.Point hierarchy because it is not
* used to hold intermediate values during point arithmetic, and so it does not
* have a mutable form.
*/
public class AffinePoint {
private final ImmutableIntegerModuloP x;
private final ImmutableIntegerModuloP y;
public AffinePoint(ImmutableIntegerModuloP x, ImmutableIntegerModuloP y) {
this.x = x;
this.y = y;
}
public ImmutableIntegerModuloP getX() {
return x;
}
public ImmutableIntegerModuloP getY() {
return y;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof AffinePoint)) {
return false;
}
AffinePoint p = (AffinePoint) obj;
boolean xEquals = x.asBigInteger().equals(p.x.asBigInteger());
boolean yEquals = y.asBigInteger().equals(p.y.asBigInteger());
return xEquals && yEquals;
}
@Override
public int hashCode() {
return Objects.hash(x, y);
}
@Override
public String toString() {
return "(" + x.asBigInteger().toString() + "," +
y.asBigInteger().toString() + ")";
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (c) 2018, 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;
/**
* An interface for immutable points on an elliptic curve over a finite field.
*/
public interface ImmutablePoint extends Point {
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright (c) 2018, 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;
/**
* An interface for mutable points on an elliptic curve over a finite field.
*/
public interface MutablePoint extends Point {
MutablePoint setValue(AffinePoint p);
MutablePoint setValue(Point p);
MutablePoint conditionalSet(Point p, int set);
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (c) 2018, 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.IntegerFieldModuloP;
/**
* A base interface for points on an elliptic curve over a finite field.
* Implementations may use different representations for points, and this
* interface creates a common API for manipulating points. This API has no
* methods for point arithmetic, which depends on group structure and curve
* parameters in addition to point representation.
*/
public interface Point {
IntegerFieldModuloP getField();
AffinePoint asAffine();
ImmutablePoint fixed();
MutablePoint mutable();
}

View File

@@ -0,0 +1,160 @@
/*
* Copyright (c) 2018, 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.*;
/**
* Elliptic curve point in projective coordinates (X, Y, Z) where
* an affine point (x, y) is represented using any (X, Y, Z) s.t.
* x = X/Z and y = Y/Z.
*/
public abstract class ProjectivePoint
<T extends IntegerModuloP> implements Point {
protected final T x;
protected final T y;
protected final T z;
protected ProjectivePoint(T x, T y, T z) {
this.x = x;
this.y = y;
this.z = z;
}
@Override
public IntegerFieldModuloP getField() {
return this.x.getField();
}
@Override
public Immutable fixed() {
return new Immutable(x.fixed(), y.fixed(), z.fixed());
}
@Override
public Mutable mutable() {
return new Mutable(x.mutable(), y.mutable(), z.mutable());
}
public T getX() {
return x;
}
public T getY() {
return y;
}
public T getZ() {
return z;
}
public AffinePoint asAffine() {
IntegerModuloP zInv = z.multiplicativeInverse();
return new AffinePoint(x.multiply(zInv), y.multiply(zInv));
}
public static class Immutable
extends ProjectivePoint<ImmutableIntegerModuloP>
implements ImmutablePoint {
public Immutable(ImmutableIntegerModuloP x,
ImmutableIntegerModuloP y,
ImmutableIntegerModuloP z) {
super(x, y, z);
}
}
public static class Mutable
extends ProjectivePoint<MutableIntegerModuloP>
implements MutablePoint {
public Mutable(MutableIntegerModuloP x,
MutableIntegerModuloP y,
MutableIntegerModuloP z) {
super(x, y, z);
}
public Mutable(IntegerFieldModuloP field) {
super(field.get0().mutable(),
field.get0().mutable(),
field.get0().mutable());
}
@Override
public Mutable conditionalSet(Point p, int set) {
if (!(p instanceof ProjectivePoint)) {
throw new RuntimeException("Incompatible point");
}
@SuppressWarnings("unchecked")
ProjectivePoint<IntegerModuloP> pp =
(ProjectivePoint<IntegerModuloP>) p;
return conditionalSet(pp, set);
}
private <T extends IntegerModuloP>
Mutable conditionalSet(ProjectivePoint<T> pp, int set) {
x.conditionalSet(pp.x, set);
y.conditionalSet(pp.y, set);
z.conditionalSet(pp.z, set);
return this;
}
@Override
public Mutable setValue(AffinePoint p) {
x.setValue(p.getX());
y.setValue(p.getY());
z.setValue(p.getX().getField().get1());
return this;
}
@Override
public Mutable setValue(Point p) {
if (!(p instanceof ProjectivePoint)) {
throw new RuntimeException("Incompatible point");
}
@SuppressWarnings("unchecked")
ProjectivePoint<IntegerModuloP> pp =
(ProjectivePoint<IntegerModuloP>) p;
return setValue(pp);
}
private <T extends IntegerModuloP>
Mutable setValue(ProjectivePoint<T> pp) {
x.setValue(pp.x);
y.setValue(pp.y);
z.setValue(pp.z);
return this;
}
}
}