Skip to content

Commit

Permalink
Add support for X25519 algorithm alias to XDH
Browse files Browse the repository at this point in the history
* Added X25519 aliases for KeyPairGenerator, KeyFactory, and KeyAgreement in OpenSSLProvider
  • Loading branch information
exceptionfactory committed Aug 7, 2023
1 parent 92a8a67 commit e24a0ce
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 14 deletions.
8 changes: 8 additions & 0 deletions common/src/main/java/org/conscrypt/OpenSSLProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ public OpenSSLProvider(String providerName) {
put("Alg.Alias.KeyPairGenerator.1.2.840.10045.2.1", "EC");
put("Alg.Alias.KeyPairGenerator.1.3.133.16.840.63.0.2", "EC");

put("KeyPairGenerator.X25519", PREFIX + "OpenSSLXDHKeyPairGenerator");
put("KeyPairGenerator.XDH", PREFIX + "OpenSSLXDHKeyPairGenerator");
put("Alg.Alias.KeyPairGenerator.1.3.101.110", "XDH");

Expand All @@ -209,6 +210,7 @@ public OpenSSLProvider(String providerName) {
put("Alg.Alias.KeyFactory.1.2.840.10045.2.1", "EC");
put("Alg.Alias.KeyFactory.1.3.133.16.840.63.0.2", "EC");

put("KeyFactory.X25519", PREFIX + "OpenSSLXDHKeyFactory");
put("KeyFactory.XDH", PREFIX + "OpenSSLXDHKeyFactory");
put("Alg.Alias.KeyFactory.1.3.101.110", "XDH");

Expand Down Expand Up @@ -624,6 +626,12 @@ private void putXDHKeyAgreementImplClass(String className) {
PREFIX + className,
supportedKeyClasses,
supportedKeyFormats);

putImplClassWithKeyConstraints(
"KeyAgreement.X25519",
PREFIX + className,
supportedKeyClasses,
supportedKeyFormats);
}

private void putImplClassWithKeyConstraints(String typeAndAlgName,
Expand Down
5 changes: 3 additions & 2 deletions common/src/main/java/org/conscrypt/OpenSSLXDHKeyFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,9 @@ protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec)
throw new InvalidKeySpecException("keySpec == null");
}

if (!"XDH".equals(key.getAlgorithm())) {
throw new InvalidKeySpecException("Key must be an XDH key");
// Support XDH or X25519 algorithm names per JEP 324
if (!"XDH".equals(key.getAlgorithm()) || !"X25519".equals(key.getAlgorithm()) ) {
throw new InvalidKeySpecException("Key must be an XDH or X25519 key");
}

Class<?> publicKeySpec = getJavaPublicKeySpec();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.conscrypt.java.security;

import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.List;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import tests.util.ServiceTester;

@RunWith(JUnit4.class)
public class KeyFactoryTestX25519 extends KeyFactoryTestXDH {

public KeyFactoryTestX25519() {
super("X25519");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,16 @@ public class KeyFactoryTestXDH extends
AbstractKeyFactoryTest<X509EncodedKeySpec, PKCS8EncodedKeySpec> {

public KeyFactoryTestXDH() {
super("XDH", X509EncodedKeySpec.class, PKCS8EncodedKeySpec.class);
this("XDH");
}

public KeyFactoryTestXDH(final String algorithmName) {
super(algorithmName, X509EncodedKeySpec.class, PKCS8EncodedKeySpec.class);
}

@Override
protected void check(KeyPair keyPair) throws Exception {
new KeyAgreementHelper("XDH").test(keyPair);
new KeyAgreementHelper(algorithmName).test(keyPair);
}

@Override
Expand All @@ -49,12 +53,12 @@ protected ServiceTester customizeTester(ServiceTester tester) {
protected List<KeyPair> getKeys() throws NoSuchAlgorithmException, InvalidKeySpecException {
return Arrays.asList(
new KeyPair(
DefaultKeys.getPublicKey("XDH"),
DefaultKeys.getPrivateKey("XDH")
DefaultKeys.getPublicKey(algorithmName),
DefaultKeys.getPrivateKey(algorithmName)
),
new KeyPair(
new TestPublicKey(DefaultKeys.getPublicKey("XDH")),
new TestPrivateKey(DefaultKeys.getPrivateKey("XDH"))
new TestPublicKey(DefaultKeys.getPublicKey(algorithmName)),
new TestPrivateKey(DefaultKeys.getPrivateKey(algorithmName))
)
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,15 @@ public void test(Provider provider, String algorithm) throws Exception {
}
// KeyPairGenerator.getInstance(String)
KeyPairGenerator kpg1 = KeyPairGenerator.getInstance(algorithm);
assertEquals(algorithm, kpg1.getAlgorithm());
assertAlgorithmMatched(algorithm, kpg1);
if (params != null) {
kpg1.initialize(params);
}
test_KeyPairGenerator(kpg1);

// KeyPairGenerator.getInstance(String, Provider)
KeyPairGenerator kpg2 = KeyPairGenerator.getInstance(algorithm, provider);
assertEquals(algorithm, kpg2.getAlgorithm());
assertAlgorithmMatched(algorithm, kpg2);
assertEquals(provider, kpg2.getProvider());
if (params != null) {
kpg2.initialize(params);
Expand All @@ -107,7 +107,7 @@ public void test(Provider provider, String algorithm) throws Exception {
// KeyPairGenerator.getInstance(String, String)
KeyPairGenerator kpg3 = KeyPairGenerator.getInstance(algorithm,
provider.getName());
assertEquals(algorithm, kpg3.getAlgorithm());
assertAlgorithmMatched(algorithm, kpg3);
assertEquals(provider, kpg3.getProvider());
if (params != null) {
kpg3.initialize(params);
Expand Down Expand Up @@ -361,6 +361,17 @@ private static void assertECParametersEquals(ECParameterSpec expected, ECParamet
assertEquals(expected.getCofactor(), actual.getCofactor());
}

private static void assertAlgorithmMatched(final String algorithm, final KeyPairGenerator keyPairGenerator) {
final String expectedAlgorithm;
// X25519 KeyPairGenerator is an alias for XDH requiring this alternative expected algorithm
if ("X25519".equals(algorithm)) {
expectedAlgorithm = "XDH";
} else {
expectedAlgorithm = algorithm;
}
assertEquals(expectedAlgorithm, keyPairGenerator.getAlgorithm());
}

/**
* DH parameters pre-generated so that the test doesn't take too long.
* These parameters were generated with:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.conscrypt.javax.crypto;

import static org.junit.Assert.assertArrayEquals;

import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.Security;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.KeyAgreement;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;


/**
* Tests for all registered X25519 {@link KeyAgreement} providers.
*/
@RunWith(JUnit4.class)
public class X25519KeyAgreementTest extends XDHKeyAgreementTest {

@Override
protected String getAlgorithm() {
return "X25519";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public class XDHKeyAgreementTest {
private PublicKey rfc7748X25519PublicKey;

private void setupKeys(Provider p) throws Exception {
KeyFactory kf = KeyFactory.getInstance("XDH", p);
KeyFactory kf = KeyFactory.getInstance(getAlgorithm(), p);

byte[] privateKey;
if ("SunEC".equalsIgnoreCase(p.getName())
Expand All @@ -84,15 +84,20 @@ private void setupKeys(Provider p) throws Exception {

@Test
public void test_XDHKeyAgreement() throws Exception {
for (Provider p : Security.getProviders("KeyAgreement.XDH")) {
final String keyAgreementAlgorithm = String.format("KeyAgreement.%s", getAlgorithm());
for (Provider p : Security.getProviders(keyAgreementAlgorithm)) {
setupKeys(p);

KeyAgreement ka = KeyAgreement.getInstance("XDH", p);
KeyAgreement ka = KeyAgreement.getInstance(getAlgorithm(), p);

test_x25519_keyAgreement_rfc7748_kat_success(ka);
}
}

protected String getAlgorithm() {
return "XDH";
}

private void test_x25519_keyAgreement_rfc7748_kat_success(KeyAgreement ka) throws Exception {
ka.init(rfc7748X25519PrivateKey);
ka.doPhase(rfc7748X25519PublicKey, true);
Expand Down

0 comments on commit e24a0ce

Please sign in to comment.