diff --git a/src/main/java/com/ibm/crypto/plus/provider/ECPrivateKey.java b/src/main/java/com/ibm/crypto/plus/provider/ECPrivateKey.java index 3b15e4409..f202a9667 100644 --- a/src/main/java/com/ibm/crypto/plus/provider/ECPrivateKey.java +++ b/src/main/java/com/ibm/crypto/plus/provider/ECPrivateKey.java @@ -14,6 +14,8 @@ import java.security.AlgorithmParameters; import java.security.InvalidKeyException; import java.security.Key; +import java.security.ProviderException; +import java.security.PublicKey; import java.security.spec.ECParameterSpec; import java.security.spec.InvalidParameterSpecException; import java.util.Arrays; @@ -578,6 +580,16 @@ ECKey getOCKKey() { return this.ecKey; } + @Override + public PublicKey calculatePublicKey() { + try { + return new ECPublicKey(provider, ecKey); + } catch (InvalidKeyException exc) { + throw new ProviderException( + "Unexpected error calculating public key", exc); + } + } + /** * Parse the key. Called by PKCS8Key. "key" is a byte array containing the * Der-encoded key which resides within the parent class PKCS8Key. The diff --git a/src/main/java/com/ibm/crypto/plus/provider/XDHPrivateKeyImpl.java b/src/main/java/com/ibm/crypto/plus/provider/XDHPrivateKeyImpl.java index 867485f00..644d3eea4 100644 --- a/src/main/java/com/ibm/crypto/plus/provider/XDHPrivateKeyImpl.java +++ b/src/main/java/com/ibm/crypto/plus/provider/XDHPrivateKeyImpl.java @@ -17,6 +17,8 @@ import java.security.InvalidKeyException; import java.security.InvalidParameterException; import java.security.KeyRep; +import java.security.ProviderException; +import java.security.PublicKey; import java.security.interfaces.XECPrivateKey; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.NamedParameterSpec; @@ -94,8 +96,8 @@ public XDHPrivateKeyImpl(OpenJCEPlusProvider provider, byte[] encoded) try { byte[] alteredEncoded = processEncodedPrivateKey(encoded); // Sets params, key, and algid, and alters encoded // to fit with GSKit and sets params - int encodingSize = CurveUtil.getDEREncodingSize(curve); - this.xecKey = XECKey.createPrivateKey(provider.getOCKContext(), alteredEncoded, encodingSize); + int curveSize = CurveUtil.getCurveSize(curve); + this.xecKey = XECKey.createPrivateKey(provider.getOCKContext(), alteredEncoded, curveSize); this.scalar = Optional.of(k); } catch (Exception exception) { InvalidKeyException ike = new InvalidKeyException("Failed to create XEC private key"); @@ -374,7 +376,7 @@ private boolean isCorrectlyFormedOctetString(byte[] keyBytes) throws IOException return true; } - public XECKey getOCKKey() { + XECKey getOCKKey() { return this.xecKey; } @@ -424,6 +426,16 @@ public String getAlgorithm() { return "XDH"; } + @Override + public PublicKey calculatePublicKey() { + try { + return new XDHPublicKeyImpl(provider, xecKey, curve); + } catch (InvalidKeyException exc) { + throw new ProviderException( + "Unexpected error calculating public key", exc); + } + } + /** * Adds a sequence of FFDHE integers (bi1, bi2, and bi3) to the OutputStream param. * DER added: SEQUENCE[INTEGER,INTEGER,INTEGER] diff --git a/src/test/java/ibm/jceplus/junit/base/BaseTestECKeyImportInterop.java b/src/test/java/ibm/jceplus/junit/base/BaseTestECKeyImportInterop.java index ac7c2f1cd..ebd9b6ef6 100644 --- a/src/test/java/ibm/jceplus/junit/base/BaseTestECKeyImportInterop.java +++ b/src/test/java/ibm/jceplus/junit/base/BaseTestECKeyImportInterop.java @@ -24,12 +24,52 @@ import java.security.spec.X509EncodedKeySpec; import java.util.Arrays; import org.junit.jupiter.api.Test; +import sun.security.util.InternalPrivateKey; import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; public class BaseTestECKeyImportInterop extends BaseTestJunit5Interop { static final byte[] origMsg = "this is the original message to be signed".getBytes(); + @Test + public void testCreateKeyPairECGenParamImportCalculatePublic() throws Exception { + doCreateKeyPairECGenParamImportCalculatePublic(getProviderName(), getInteropProviderName()); + doCreateKeyPairECGenParamImportCalculatePublic(getInteropProviderName(), getProviderName()); + } + + private void doCreateKeyPairECGenParamImportCalculatePublic(String generateProviderName, + String importProviderName) throws Exception { + + KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("EC", generateProviderName); + + keyPairGen.initialize(256); + KeyPair keyPair = keyPairGen.generateKeyPair(); + PrivateKey privateKey = keyPair.getPrivate(); + PublicKey publicKey = keyPair.getPublic(); + + // Recreate private key from encoding. + byte[] privKeyBytes = privateKey.getEncoded(); + KeyFactory keyFactory = KeyFactory.getInstance("EC", importProviderName); + EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privKeyBytes); + privateKey = keyFactory.generatePrivate(privateKeySpec); + + // Get public key bytes from private. + byte[] calculatedPublicKey = ((InternalPrivateKey) privateKey).calculatePublicKey().getEncoded(); + + // Get public key bytes from original public key. + byte[] publicKeyBytes = publicKey.getEncoded(); + + System.out.println("---- Comparing EC public key from KeyPair vs calculated from private key ----"); + System.out.println("EC public key from Keypair from " + generateProviderName + ": " + + BaseUtils.bytesToHex(publicKeyBytes)); + System.out.println("EC public key from calculatePublicKey() from " + importProviderName + ": " + + BaseUtils.bytesToHex(calculatedPublicKey)); + + // The original and calculated public keys should be the same + assertArrayEquals(calculatedPublicKey, publicKeyBytes); + } + @Test public void testCreateKeyPairECGenParamImport() throws Exception { doCreateKeyPairECGenParamImport(getProviderName(), getInteropProviderName()); diff --git a/src/test/java/ibm/jceplus/junit/base/BaseTestECKeyPairGenerator.java b/src/test/java/ibm/jceplus/junit/base/BaseTestECKeyPairGenerator.java index 2e89e9476..fd7e0b7d5 100644 --- a/src/test/java/ibm/jceplus/junit/base/BaseTestECKeyPairGenerator.java +++ b/src/test/java/ibm/jceplus/junit/base/BaseTestECKeyPairGenerator.java @@ -11,7 +11,9 @@ import java.security.InvalidAlgorithmParameterException; import java.security.KeyPair; import java.security.KeyPairGenerator; +import java.security.PrivateKey; import java.security.ProviderException; +import java.security.PublicKey; import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; import java.security.spec.ECGenParameterSpec; @@ -20,7 +22,9 @@ import java.security.spec.EllipticCurve; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import sun.security.util.InternalPrivateKey; import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; public class BaseTestECKeyPairGenerator extends BaseTestJunit5 { @@ -101,6 +105,23 @@ public void compareEcParameterSpec(ECParameterSpec ecParameterSpecPub, } + @Test + public void testECPrivateKey_calculatePublicKey() throws Exception { + kpg.initialize(256); + KeyPair kp = kpg.generateKeyPair(); + + PublicKey ecpu = kp.getPublic(); + PrivateKey ecpr = kp.getPrivate(); + + byte[] originalEncoded = ecpu.getEncoded(); + byte[] calculatedEncoded = ((InternalPrivateKey) ecpr).calculatePublicKey().getEncoded(); + + System.out.println("---- Comparing EC public key from KeyPair vs calculated from private key ----"); + System.out.println("EC public key from Keypair: " + BaseUtils.bytesToHex(originalEncoded)); + System.out.println("EC public key from calculatePublicKey(): " + BaseUtils.bytesToHex(calculatedEncoded)); + assertArrayEquals(originalEncoded, calculatedEncoded); + } + @Test public void testECKeyGenCurves_secp192k1() throws Exception { generictestECKeyGenCurve("secp192k1"); diff --git a/src/test/java/ibm/jceplus/junit/base/BaseTestXDHInterop.java b/src/test/java/ibm/jceplus/junit/base/BaseTestXDHInterop.java index 90229ac46..946f77468 100644 --- a/src/test/java/ibm/jceplus/junit/base/BaseTestXDHInterop.java +++ b/src/test/java/ibm/jceplus/junit/base/BaseTestXDHInterop.java @@ -11,6 +11,8 @@ import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.PublicKey; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.EncodedKeySpec; import java.security.spec.NamedParameterSpec; @@ -18,6 +20,8 @@ import java.security.spec.X509EncodedKeySpec; import java.util.Base64; import org.junit.jupiter.api.Test; +import sun.security.util.InternalPrivateKey; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; public class BaseTestXDHInterop extends BaseTestJunit5Interop { @@ -29,6 +33,47 @@ public class BaseTestXDHInterop extends BaseTestJunit5Interop { String openJDK_private_X448 = "MEYCAQAwBwYDK2VvBQAEOOJFsgLYxgAIEWuN1FLAGWDzGQRSataAbPLDc1wv5aky4T8hevyWbYdhggc1OCcqQ93gY8rqVTDb"; // OpenJDK does not currently support FFDHE hence interop testing for FFDHE is not possible + @Test + public void testCreateKeyPairXDHGenParamImportCalculatePublic() throws Exception { + if (!"BC".equals(getInteropProviderName())) { + doCreateKeyPairXDHGenParamImportCalculatePublic(getProviderName(), getInteropProviderName()); + doCreateKeyPairXDHGenParamImportCalculatePublic(getInteropProviderName(), getProviderName()); + } + + } + + private void doCreateKeyPairXDHGenParamImportCalculatePublic(String generateProviderName, + String importProviderName) throws Exception { + + KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("XDH", generateProviderName); + + keyPairGen.initialize(255); + KeyPair keyPair = keyPairGen.generateKeyPair(); + PrivateKey privateKey = keyPair.getPrivate(); + PublicKey publicKey = keyPair.getPublic(); + + // Recreate private key from encoding. + byte[] privKeyBytes = privateKey.getEncoded(); + KeyFactory keyFactory = KeyFactory.getInstance("XDH", importProviderName); + EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privKeyBytes); + privateKey = keyFactory.generatePrivate(privateKeySpec); + + // Get public key bytes from private. + byte[] calculatedPublicKey = ((InternalPrivateKey) privateKey).calculatePublicKey().getEncoded(); + + // Get public key bytes from original public key. + byte[] publicKeyBytes = publicKey.getEncoded(); + + System.out.println("---- Comparing XDH public key from KeyPair vs calculated from private key ----"); + System.out.println("XDH public key from Keypair from " + generateProviderName + ": " + + BaseUtils.bytesToHex(publicKeyBytes)); + System.out.println("XDH public key from calculatePublicKey() from " + importProviderName + ": " + + BaseUtils.bytesToHex(calculatedPublicKey)); + + // The original and calculated public keys should be the same + assertArrayEquals(calculatedPublicKey, publicKeyBytes); + } + @Test public void testXDHInterop_X25519_OpenJDK() throws Exception { byte[] openJDK_public_bytes = Base64.getDecoder().decode(openJDK_public_X25519); diff --git a/src/test/java/ibm/jceplus/junit/base/BaseTestXDHKeyPairGenerator.java b/src/test/java/ibm/jceplus/junit/base/BaseTestXDHKeyPairGenerator.java index fa31d50ab..24f3b3e0e 100644 --- a/src/test/java/ibm/jceplus/junit/base/BaseTestXDHKeyPairGenerator.java +++ b/src/test/java/ibm/jceplus/junit/base/BaseTestXDHKeyPairGenerator.java @@ -10,11 +10,15 @@ import java.security.KeyPair; import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.PublicKey; import java.security.interfaces.XECPrivateKey; import java.security.interfaces.XECPublicKey; import java.security.spec.NamedParameterSpec; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import sun.security.util.InternalPrivateKey; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; public class BaseTestXDHKeyPairGenerator extends BaseTestJunit5 { @@ -82,6 +86,23 @@ public void doXECKeyGen(int keypairSize) throws Exception { //System.out.println("ECPrivate: " + ecpr.getS()); } + @Test + public void testXDHPrivateKey_calculatePublicKey() throws Exception { + kpg.initialize(255); + KeyPair kp = kpg.generateKeyPair(); + + PublicKey ecpu = kp.getPublic(); + PrivateKey ecpr = kp.getPrivate(); + + byte[] originalEncoded = ecpu.getEncoded(); + byte[] calculatedEncoded = ((InternalPrivateKey) ecpr).calculatePublicKey().getEncoded(); + + System.out.println("---- Comparing XDH public key from KeyPair vs calculated from private key ----"); + System.out.println("XDH public key from Keypair: " + BaseUtils.bytesToHex(originalEncoded)); + System.out.println("XDH public key from calculatePublicKey(): " + BaseUtils.bytesToHex(calculatedEncoded)); + assertArrayEquals(originalEncoded, calculatedEncoded); + } + @Test public void testXECKeyGenCurves() throws Exception { generictestXECKeyGenCurve("X25519");