Skip to content
Permalink
Browse files

8234465: Encoded elliptic curve private keys should include the publi…

…c point

Reviewed-by: xuelei
  • Loading branch information
wangweij committed Dec 17, 2019
1 parent 924720f commit 31b07b21ae84bf4eb5d7a001c9283db22cf75faa
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2006, 2019, 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
@@ -201,6 +201,7 @@ private PrivateKey implTranslatePrivateKey(PrivateKey key)
ECPrivateKey ecKey = (ECPrivateKey)key;
return new ECPrivateKeyImpl(
ecKey.getS(),
null,
ecKey.getParams()
);
} else if ("PKCS#8".equals(key.getFormat())) {
@@ -237,7 +238,7 @@ private PrivateKey implGeneratePrivate(KeySpec keySpec)
return new ECPrivateKeyImpl(pkcsSpec.getEncoded());
} else if (keySpec instanceof ECPrivateKeySpec) {
ECPrivateKeySpec ecSpec = (ECPrivateKeySpec)keySpec;
return new ECPrivateKeyImpl(ecSpec.getS(), ecSpec.getParams());
return new ECPrivateKeyImpl(ecSpec.getS(), null, ecSpec.getParams());
} else {
throw new InvalidKeySpecException("Only ECPrivateKeySpec "
+ "and PKCS8EncodedKeySpec supported for EC private keys");
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2019, 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
@@ -199,11 +199,10 @@ public KeyPair generateKeyPair() {
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());

PrivateKey privateKey = new ECPrivateKeyImpl(privArr, w, ecParams);
PublicKey publicKey = new ECPublicKeyImpl(w, ecParams);

return Optional.of(new KeyPair(publicKey, privateKey));
@@ -225,11 +224,12 @@ private KeyPair generateKeyPairNative(SecureRandom random)
// 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());

PrivateKey privateKey = new ECPrivateKeyImpl(s, w, ecParams);

PublicKey publicKey = new ECPublicKeyImpl(w, ecParams);

return new KeyPair(publicKey, privateKey);
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2006, 2019, 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
@@ -52,8 +52,8 @@
* }
* </pre>
*
* We currently ignore the optional parameters and publicKey fields. We
* require that the parameters are encoded as part of the AlgorithmIdentifier,
* We currently ignore the optional parameters. We require that the
* parameters are encoded as part of the AlgorithmIdentifier,
* not in the private key structure.
*
* @since 1.6
@@ -66,6 +66,7 @@
private BigInteger s; // private value
private byte[] arrayS; // private value as a little-endian array
private ECParameterSpec params;
private ECPoint pub; // the optional public key

/**
* Construct a key from its encoding. Called by the ECKeyFactory.
@@ -78,18 +79,20 @@
* Construct a key from its components. Used by the
* KeyFactory.
*/
ECPrivateKeyImpl(BigInteger s, ECParameterSpec params)
ECPrivateKeyImpl(BigInteger s, ECPoint pub, ECParameterSpec params)
throws InvalidKeyException {
this.s = s;
this.params = params;
this.pub = pub;
makeEncoding(s);

}

ECPrivateKeyImpl(byte[] s, ECParameterSpec params)
ECPrivateKeyImpl(byte[] s, ECPoint pub, ECParameterSpec params)
throws InvalidKeyException {
this.arrayS = s.clone();
this.params = params;
this.pub = pub;
makeEncoding(s);
}

@@ -102,6 +105,12 @@ private void makeEncoding(byte[] s) throws InvalidKeyException {
byte[] privBytes = s.clone();
ArrayUtil.reverse(privBytes);
out.putOctetString(privBytes);
if (pub != null) {
DerOutputStream pubDer = new DerOutputStream();
pubDer.putBitString(ECUtil.encodePoint(pub, params.getCurve()));
out.write(DerValue.createTag(DerValue.TAG_CONTEXT,
true, (byte) 0x01), pubDer);
}
DerValue val =
new DerValue(DerValue.tag_Sequence, out.toByteArray());
key = val.toByteArray();
@@ -186,22 +195,25 @@ protected void parseKeyBits() throws InvalidKeyException {
byte[] privData = data.getOctetString();
ArrayUtil.reverse(privData);
arrayS = privData;
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);
while (data.available() != 0) {
DerValue value = data.getDerValue();
if (value.isContextSpecific((byte) 0)) {
// ignore for now
// ignore for now. Usually not encoded because
// pkcs8 already has the params
} else if (value.isContextSpecific((byte) 1)) {
// ignore for now
pub = ECUtil.decodePoint(
value.data.getUnalignedBitString().toByteArray(),
params.getCurve());
} 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) {
@@ -0,0 +1,72 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

import jdk.test.lib.Asserts;
import jdk.test.lib.security.DerUtils;
import sun.security.util.DerValue;

import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Arrays;

/*
* @test
* @bug 8234465
* @library /test/lib
* @modules java.base/sun.security.util
* @summary Encoded elliptic curve private keys should include the public point
*/
public class PublicKeyInPrivateKey {

public static void main(String[] args) throws Exception {

KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
kpg.initialize(new ECGenParameterSpec("secp256r1"));
KeyPair kp = kpg.generateKeyPair();
byte[] pubBytes = kp.getPublic().getEncoded();
byte[] privBytes = kp.getPrivate().getEncoded();

// https://tools.ietf.org/html/rfc5480#section-2.
// subjectPublicKey is 2nd in SubjectPublicKeyInfo
DerValue pubPoint = DerUtils.innerDerValue(pubBytes, "1");

// https://tools.ietf.org/html/rfc5208#section-5.
// privateKey as an OCTET STRING is 3rd in PrivateKeyInfo
// https://tools.ietf.org/html/rfc5915#section-3
// publicKey as [1] is 3rd (we do not have parameters) in ECPrivateKey
DerValue pubPointInPriv = DerUtils.innerDerValue(privBytes, "2c20");

// The two public keys should be the same
Asserts.assertEQ(pubPoint, pubPointInPriv);

// And it's reloadable
KeyFactory kf = KeyFactory.getInstance("EC");
byte[] privBytes2 = kf.generatePrivate(
new PKCS8EncodedKeySpec(privBytes)).getEncoded();

Asserts.assertTrue(Arrays.equals(privBytes, privBytes2));
}
}

0 comments on commit 31b07b2

Please sign in to comment.
You can’t perform that action at this time.