8305310: Calculate PublicKey from PrivateKey
Reviewed-by: mullan
This commit is contained in:
parent
50d7335206
commit
97276859ab
src
java.base/share/classes/sun/security
jdk.crypto.ec/share/classes/sun/security/ec
test/jdk/sun/security/util/InternalPrivateKey
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 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
|
||||
@ -58,7 +58,7 @@ import sun.security.util.*;
|
||||
*
|
||||
* We support this format but do not parse attributes and publicKey now.
|
||||
*/
|
||||
public class PKCS8Key implements PrivateKey {
|
||||
public class PKCS8Key implements PrivateKey, InternalPrivateKey {
|
||||
|
||||
/** use serialVersionUID from JDK 1.1. for interoperability */
|
||||
@java.io.Serial
|
||||
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 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.util;
|
||||
|
||||
import java.security.PublicKey;
|
||||
|
||||
/**
|
||||
* Extra private methods on a private key.
|
||||
*/
|
||||
public interface InternalPrivateKey {
|
||||
/**
|
||||
* Calculates a matching public key.
|
||||
* @return the public key
|
||||
* @throws UnsupportedOperationException if not supported
|
||||
*/
|
||||
default PublicKey calculatePublicKey() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
@ -191,15 +191,10 @@ public final class ECKeyPairGenerator extends KeyPairGeneratorSpi {
|
||||
int seedSize = (seedBits + 7) / 8;
|
||||
byte[] privArr = generatePrivateScalar(random, ops, seedSize);
|
||||
|
||||
Point pub = ops.multiply(ecParams.getGenerator(), privArr);
|
||||
AffinePoint affPub = pub.asAffine();
|
||||
|
||||
PrivateKey privateKey = new ECPrivateKeyImpl(privArr, ecParams);
|
||||
ECPrivateKeyImpl privateKey = new ECPrivateKeyImpl(privArr, ecParams);
|
||||
Arrays.fill(privArr, (byte)0);
|
||||
|
||||
ECPoint w = new ECPoint(affPub.getX().asBigInteger(),
|
||||
affPub.getY().asBigInteger());
|
||||
PublicKey publicKey = new ECPublicKeyImpl(w, ecParams);
|
||||
PublicKey publicKey = privateKey.calculatePublicKey();
|
||||
|
||||
return Optional.of(new KeyPair(publicKey, privateKey));
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -33,6 +33,8 @@ import java.security.interfaces.*;
|
||||
import java.security.spec.*;
|
||||
import java.util.Arrays;
|
||||
|
||||
import sun.security.ec.point.AffinePoint;
|
||||
import sun.security.ec.point.MutablePoint;
|
||||
import sun.security.util.*;
|
||||
import sun.security.x509.AlgorithmId;
|
||||
import sun.security.pkcs.PKCS8Key;
|
||||
@ -148,11 +150,15 @@ public final class ECPrivateKeyImpl extends PKCS8Key implements ECPrivateKey {
|
||||
return s;
|
||||
}
|
||||
|
||||
public byte[] getArrayS() {
|
||||
private byte[] getArrayS0() {
|
||||
if (arrayS == null) {
|
||||
arrayS = ECUtil.sArray(getS(), params);
|
||||
}
|
||||
return arrayS.clone();
|
||||
return arrayS;
|
||||
}
|
||||
|
||||
public byte[] getArrayS() {
|
||||
return getArrayS0().clone();
|
||||
}
|
||||
|
||||
// see JCA doc
|
||||
@ -195,4 +201,21 @@ public final class ECPrivateKeyImpl extends PKCS8Key implements ECPrivateKey {
|
||||
throw new InvalidKeyException("Invalid EC private key", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PublicKey calculatePublicKey() {
|
||||
ECParameterSpec ecParams = getParams();
|
||||
ECOperations ops = ECOperations.forParameters(ecParams)
|
||||
.orElseThrow(ProviderException::new);
|
||||
MutablePoint pub = ops.multiply(ecParams.getGenerator(), getArrayS0());
|
||||
AffinePoint affPub = pub.asAffine();
|
||||
ECPoint w = new ECPoint(affPub.getX().asBigInteger(),
|
||||
affPub.getY().asBigInteger());
|
||||
try {
|
||||
return new ECPublicKeyImpl(w, ecParams);
|
||||
} catch (InvalidKeyException e) {
|
||||
throw new ProviderException(
|
||||
"Unexpected error calculating public key", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 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
|
||||
@ -40,7 +40,7 @@ public final class XDHPrivateKeyImpl extends PKCS8Key implements XECPrivateKey {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@SuppressWarnings("serial") // Type of field is not Serializable
|
||||
private final AlgorithmParameterSpec paramSpec;
|
||||
private final NamedParameterSpec paramSpec;
|
||||
private byte[] k;
|
||||
|
||||
XDHPrivateKeyImpl(XECParameters params, byte[] k)
|
||||
@ -100,5 +100,19 @@ public final class XDHPrivateKeyImpl extends PKCS8Key implements XECPrivateKey {
|
||||
public Optional<byte[]> getScalar() {
|
||||
return Optional.of(getK());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PublicKey calculatePublicKey() {
|
||||
XECParameters params = paramSpec.getName().equals("X25519")
|
||||
? XECParameters.X25519
|
||||
: XECParameters.X448;
|
||||
try {
|
||||
return new XDHPublicKeyImpl(params,
|
||||
new XECOperations(params).computePublic(k.clone()));
|
||||
} catch (InvalidKeyException e) {
|
||||
throw new ProviderException(
|
||||
"Unexpected error calculating public key", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,6 +39,9 @@ import sun.security.x509.AlgorithmId;
|
||||
|
||||
public class XECParameters {
|
||||
|
||||
static final XECParameters X25519;
|
||||
static final XECParameters X448;
|
||||
|
||||
static ParametersMap<XECParameters> namedParams = new ParametersMap<>();
|
||||
|
||||
// Naming/identification parameters
|
||||
@ -114,41 +117,27 @@ public class XECParameters {
|
||||
Map<String, XECParameters> byName = new HashMap<>();
|
||||
|
||||
// set up X25519
|
||||
try {
|
||||
BigInteger p = TWO.pow(255).subtract(BigInteger.valueOf(19));
|
||||
addParameters(255, p, 121665, (byte)0x09, 3,
|
||||
KnownOIDs.X25519.value(), NamedParameterSpec.X25519.getName(),
|
||||
bySize, byOid, byName);
|
||||
|
||||
} catch (IOException ex) {
|
||||
// Unable to set X25519 parameters---it will be disabled
|
||||
}
|
||||
BigInteger p2 = TWO.pow(255).subtract(BigInteger.valueOf(19));
|
||||
X25519 = addParameters(255, p2, 121665, (byte)0x09, 3,
|
||||
KnownOIDs.X25519, NamedParameterSpec.X25519.getName());
|
||||
|
||||
// set up X448
|
||||
try {
|
||||
BigInteger p = TWO.pow(448).subtract(TWO.pow(224))
|
||||
.subtract(BigInteger.ONE);
|
||||
addParameters(448, p, 39081, (byte)0x05, 2,
|
||||
KnownOIDs.X448.value(), NamedParameterSpec.X448.getName(),
|
||||
bySize, byOid, byName);
|
||||
|
||||
} catch (IOException ex) {
|
||||
// Unable to set X448 parameters---it will be disabled
|
||||
}
|
||||
BigInteger p4 = TWO.pow(448).subtract(TWO.pow(224))
|
||||
.subtract(BigInteger.ONE);
|
||||
X448 = addParameters(448, p4, 39081, (byte)0x05, 2,
|
||||
KnownOIDs.X448, NamedParameterSpec.X448.getName());
|
||||
|
||||
namedParams.fix();
|
||||
}
|
||||
|
||||
private static void addParameters(int bits, BigInteger p, int a24,
|
||||
byte basePoint, int logCofactor, String objectId, String name,
|
||||
Map<Integer, XECParameters> bySize,
|
||||
Map<ObjectIdentifier, XECParameters> byOid,
|
||||
Map<String, XECParameters> byName) throws IOException {
|
||||
private static XECParameters addParameters(int bits, BigInteger p, int a24,
|
||||
byte basePoint, int logCofactor, KnownOIDs koid, String name) {
|
||||
|
||||
ObjectIdentifier oid = ObjectIdentifier.of(objectId);
|
||||
ObjectIdentifier oid = ObjectIdentifier.of(koid);
|
||||
XECParameters params =
|
||||
new XECParameters(bits, p, a24, basePoint, logCofactor, oid, name);
|
||||
namedParams.put(name.toLowerCase(), oid, bits, params);
|
||||
return params;
|
||||
}
|
||||
|
||||
boolean oidEquals(XECParameters other) {
|
||||
|
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
* 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 sun.security.util.InternalPrivateKey;
|
||||
|
||||
import java.security.*;
|
||||
import java.security.spec.ECGenParameterSpec;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8305310
|
||||
* @library /test/lib
|
||||
* @summary Calculate PublicKey from PrivateKey
|
||||
* @modules java.base/sun.security.util
|
||||
*/
|
||||
public class Correctness {
|
||||
public static void main(String[] args) throws Exception {
|
||||
for (String alg : List.of("secp256r1", "secp384r1", "secp521r1",
|
||||
"X25519", "X448")) {
|
||||
KeyPairGenerator g;
|
||||
if (alg.startsWith("X")) {
|
||||
g = KeyPairGenerator.getInstance(alg);
|
||||
} else {
|
||||
g = KeyPairGenerator.getInstance("EC");
|
||||
g.initialize(new ECGenParameterSpec(alg));
|
||||
}
|
||||
KeyPair kp = g.generateKeyPair();
|
||||
PublicKey p1 = kp.getPublic();
|
||||
PrivateKey s1 = kp.getPrivate();
|
||||
|
||||
if (s1 instanceof InternalPrivateKey ipk) {
|
||||
PublicKey p2 = ipk.calculatePublicKey();
|
||||
Asserts.assertTrue(Arrays.equals(p2.getEncoded(), p1.getEncoded()));
|
||||
Asserts.assertEQ(p2.getAlgorithm(), p1.getAlgorithm());
|
||||
Asserts.assertEQ(p2.getFormat(), p1.getFormat());
|
||||
} else {
|
||||
throw new RuntimeException("Not an InternalPrivateKey: "
|
||||
+ s1.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user