aboutsummaryrefslogtreecommitdiff
path: root/src/share/classes/sun/security/ec/ECKeyPairGenerator.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/share/classes/sun/security/ec/ECKeyPairGenerator.java')
-rw-r--r--src/share/classes/sun/security/ec/ECKeyPairGenerator.java168
1 files changed, 134 insertions, 34 deletions
diff --git a/src/share/classes/sun/security/ec/ECKeyPairGenerator.java b/src/share/classes/sun/security/ec/ECKeyPairGenerator.java
index 72c0994664..f8eacdad33 100644
--- a/src/share/classes/sun/security/ec/ECKeyPairGenerator.java
+++ b/src/share/classes/sun/security/ec/ECKeyPairGenerator.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -25,20 +25,23 @@
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.ec.NamedCurve;
-import sun.security.ec.ECParameters;
-import sun.security.ec.ECPrivateKeyImpl;
-import sun.security.ec.ECPublicKeyImpl;
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.
@@ -86,17 +89,19 @@ public final class ECKeyPairGenerator extends KeyPairGeneratorSpi {
public void initialize(AlgorithmParameterSpec params, SecureRandom random)
throws InvalidAlgorithmParameterException {
+ ECParameterSpec ecSpec = null;
+
if (params instanceof ECParameterSpec) {
- this.params = ECUtil.getECParameterSpec(null,
- (ECParameterSpec)params);
- if (this.params == null) {
+ 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();
- this.params = ECUtil.getECParameterSpec(null, name);
- if (this.params == null) {
+ String name = ((ECGenParameterSpec) params).getName();
+ ecSpec = ECUtil.getECParameterSpec(null, name);
+ if (ecSpec == null) {
throw new InvalidAlgorithmParameterException(
"Unknown curve name: " + name);
}
@@ -104,48 +109,130 @@ public final class ECKeyPairGenerator extends KeyPairGeneratorSpi {
throw new InvalidAlgorithmParameterException(
"ECParameterSpec or ECGenParameterSpec required for EC");
}
- this.keySize =
- ((ECParameterSpec)this.params).getCurve().getField().getFieldSize();
+
+ // 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() {
- byte[] encodedParams =
- ECUtil.encodeECParameterSpec(null, (ECParameterSpec)params);
-
- // seed is twice the key size (in bytes) plus 1
- byte[] seed = new byte[(((keySize + 7) >> 3) + 1) * 2];
if (random == null) {
random = JCAUtil.getSecureRandom();
}
- random.nextBytes(seed);
try {
+ Optional<KeyPair> kp = generateKeyPairImpl(random);
+ if (kp.isPresent()) {
+ return kp.get();
+ }
+ return generateKeyPairNative(random);
+ } catch (Exception ex) {
+ throw new ProviderException(ex);
+ }
+ }
- 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]);
+ 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
+ }
+ }
- PrivateKey privateKey =
- new ECPrivateKeyImpl(s, (ECParameterSpec)params);
+ throw new ProviderException("Unable to produce private key after "
+ + numAttempts + " attempts");
+ }
- // keyBytes[1] is the encoding of the native public key
- ECPoint w = ECUtil.decodePoint((byte[])keyBytes[1],
- ((ECParameterSpec)params).getCurve());
- PublicKey publicKey =
- new ECPublicKeyImpl(w, (ECParameterSpec)params);
+ private Optional<KeyPair> generateKeyPairImpl(SecureRandom random)
+ throws InvalidKeyException {
- return new KeyPair(publicKey, privateKey);
+ ECParameterSpec ecParams = (ECParameterSpec) params;
- } catch (Exception e) {
- throw new ProviderException(e);
+ 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 {
@@ -160,6 +247,19 @@ public final class ECKeyPairGenerator extends KeyPairGeneratorSpi {
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.