--- old/src/jdk.crypto.ec/share/classes/sun/security/ec/ECKeyPairGenerator.java 2019-05-28 09:11:59.982799200 +0200 +++ new/src/jdk.crypto.ec/share/classes/sun/security/ec/ECKeyPairGenerator.java 2019-05-28 09:11:59.024427800 +0200 @@ -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 @@ -33,13 +33,15 @@ import java.security.spec.ECParameterSpec; import java.security.spec.ECPoint; import java.security.spec.InvalidParameterSpecException; +import java.security.spec.*; +import java.util.Optional; -import sun.security.ec.ECPrivateKeyImpl; -import sun.security.ec.ECPublicKeyImpl; import sun.security.jca.JCAUtil; -import sun.security.util.ECParameters; 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. @@ -90,14 +92,14 @@ ECParameterSpec ecSpec = null; if (params instanceof ECParameterSpec) { - ecSpec = ECUtil.getECParameterSpec(null, - (ECParameterSpec)params); + 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(); + String name = ((ECGenParameterSpec) params).getName(); ecSpec = ECUtil.getECParameterSpec(null, name); if (ecSpec == null) { throw new InvalidAlgorithmParameterException( @@ -112,8 +114,7 @@ ensureCurveIsSupported(ecSpec); this.params = ecSpec; - this.keySize = - ((ECParameterSpec)this.params).getCurve().getField().getFieldSize(); + this.keySize = ecSpec.getCurve().getField().getFieldSize(); this.random = random; } @@ -141,39 +142,97 @@ @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 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 + } + } - Object[] keyBytes = generateECKeyPair(keySize, encodedParams, seed); + throw new ProviderException("Unable to produce private key after " + + numAttempts + " attempts"); + } - // 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, (ECParameterSpec)params); - - // 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 generateKeyPairImpl(SecureRandom random) + throws InvalidKeyException { - return new KeyPair(publicKey, privateKey); + ECParameterSpec ecParams = (ECParameterSpec) params; - } catch (Exception e) { - throw new ProviderException(e); + Optional opsOpt = ECOperations.forParameters(ecParams); + if (opsOpt.isEmpty()) { + 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 { @@ -190,7 +249,9 @@ /** * Checks whether the curve in the encoded parameters is supported by the - * native implementation. + * 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