diff options
Diffstat (limited to 'src/share/classes/sun/security/ec/ECKeyPairGenerator.java')
-rw-r--r-- | src/share/classes/sun/security/ec/ECKeyPairGenerator.java | 168 |
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. |