Skip to content

Commit 969f2d7

Browse files
committed
added support for generating EdDSA keys from JVM EdEC key spec classes.
1 parent 47539e2 commit 969f2d7

File tree

3 files changed

+104
-14
lines changed

3 files changed

+104
-14
lines changed

prov/src/main/jdk1.15/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyFactorySpi.java

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,31 @@
55
import java.security.Key;
66
import java.security.PrivateKey;
77
import java.security.PublicKey;
8+
import java.security.spec.EdECPrivateKeySpec;
9+
import java.security.spec.EdECPublicKeySpec;
810
import java.security.spec.InvalidKeySpecException;
911
import java.security.spec.KeySpec;
12+
import java.security.spec.NamedParameterSpec;
1013
import java.security.spec.X509EncodedKeySpec;
1114

1215
import org.bouncycastle.asn1.ASN1Encoding;
13-
import org.bouncycastle.asn1.ASN1InputStream;
1416
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
1517
import org.bouncycastle.asn1.ASN1OctetString;
1618
import org.bouncycastle.asn1.ASN1Primitive;
1719
import org.bouncycastle.asn1.ASN1Sequence;
18-
import org.bouncycastle.asn1.DEROctetString;
19-
import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers;
2020
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
2121
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
2222
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
2323
import org.bouncycastle.crypto.CipherParameters;
24+
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
2425
import org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters;
2526
import org.bouncycastle.crypto.params.Ed25519PublicKeyParameters;
2627
import org.bouncycastle.crypto.params.Ed448PublicKeyParameters;
2728
import org.bouncycastle.crypto.params.X25519PublicKeyParameters;
2829
import org.bouncycastle.crypto.params.X448PublicKeyParameters;
2930
import org.bouncycastle.crypto.util.OpenSSHPrivateKeyUtil;
3031
import org.bouncycastle.crypto.util.OpenSSHPublicKeyUtil;
32+
import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers;
3133
import org.bouncycastle.jcajce.interfaces.EdDSAPublicKey;
3234
import org.bouncycastle.jcajce.interfaces.XDHPublicKey;
3335
import org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi;
@@ -144,7 +146,32 @@ protected PrivateKey engineGeneratePrivate(
144146
{
145147
return new BC15EdDSAPrivateKey((Ed25519PrivateKeyParameters)parameters);
146148
}
147-
throw new IllegalStateException("openssh private key not Ed25519 private key");
149+
throw new InvalidKeySpecException("openssh private key not Ed25519 private key");
150+
}
151+
else if (keySpec instanceof EdECPrivateKeySpec)
152+
{
153+
EdECPrivateKeySpec edSpec = (EdECPrivateKeySpec)keySpec;
154+
try
155+
{
156+
AsymmetricKeyParameter parameters;
157+
if (NamedParameterSpec.ED448.getName().equalsIgnoreCase(edSpec.getParams().getName()))
158+
{
159+
parameters = SignatureSpi.getEd448PrivateKey(edSpec.getBytes());
160+
}
161+
else if (NamedParameterSpec.ED25519.getName().equalsIgnoreCase(edSpec.getParams().getName()))
162+
{
163+
parameters = SignatureSpi.getEd25519PrivateKey(edSpec.getBytes());
164+
}
165+
else
166+
{
167+
throw new InvalidKeySpecException("unrecognized named parameters: " + edSpec.getParams().getName());
168+
}
169+
return new BC15EdDSAPrivateKey(parameters);
170+
}
171+
catch (InvalidKeyException e)
172+
{
173+
throw new InvalidKeySpecException(e.getMessage(), e);
174+
}
148175
}
149176

150177
return super.engineGeneratePrivate(keySpec);
@@ -210,6 +237,31 @@ else if (keySpec instanceof RawEncodedKeySpec)
210237
throw new InvalidKeySpecException("factory not a specific type, cannot recognise raw encoding");
211238
}
212239
}
240+
else if (keySpec instanceof EdECPublicKeySpec)
241+
{
242+
EdECPublicKeySpec edSpec = (EdECPublicKeySpec)keySpec;
243+
try
244+
{
245+
AsymmetricKeyParameter parameters;
246+
if (NamedParameterSpec.ED448.getName().equalsIgnoreCase(edSpec.getParams().getName()))
247+
{
248+
parameters = SignatureSpi.getEd448PublicKey(edSpec.getPoint());
249+
}
250+
else if (NamedParameterSpec.ED25519.getName().equalsIgnoreCase(edSpec.getParams().getName()))
251+
{
252+
parameters = SignatureSpi.getEd25519PublicKey(edSpec.getPoint());
253+
}
254+
else
255+
{
256+
throw new InvalidKeySpecException("unrecognized named parameters: " + edSpec.getParams().getName());
257+
}
258+
return new BC15EdDSAPublicKey(parameters);
259+
}
260+
catch (InvalidKeyException e)
261+
{
262+
throw new InvalidKeySpecException(e.getMessage(), e);
263+
}
264+
}
213265
else if (keySpec instanceof OpenSSHPublicKeySpec)
214266
{
215267
CipherParameters parameters = OpenSSHPublicKeyUtil.parsePublicKey(((OpenSSHPublicKeySpec)keySpec).getEncoded());
@@ -218,7 +270,7 @@ else if (keySpec instanceof OpenSSHPublicKeySpec)
218270
return new BC15EdDSAPublicKey(new byte[0], ((Ed25519PublicKeyParameters)parameters).getEncoded());
219271
}
220272

221-
throw new IllegalStateException("openssh public key not Ed25519 public key");
273+
throw new InvalidKeySpecException("openssh public key not Ed25519 public key");
222274
}
223275

224276
return super.engineGeneratePublic(keySpec);

prov/src/main/jdk1.15/org/bouncycastle/jcajce/provider/asymmetric/edec/SignatureSpi.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ else if (priv instanceof Ed448PrivateKeyParameters)
8383
signer.init(true, priv);
8484
}
8585

86-
private static Ed25519PrivateKeyParameters getEd25519PrivateKey(byte[] keyData)
86+
static Ed25519PrivateKeyParameters getEd25519PrivateKey(byte[] keyData)
8787
throws InvalidKeyException
8888
{
8989
if (Ed25519PrivateKeyParameters.KEY_SIZE != keyData.length)
@@ -94,15 +94,15 @@ private static Ed25519PrivateKeyParameters getEd25519PrivateKey(byte[] keyData)
9494
return new Ed25519PrivateKeyParameters(keyData, 0);
9595
}
9696

97-
private static Ed25519PublicKeyParameters getEd25519PublicKey(EdECPoint point)
97+
static Ed25519PublicKeyParameters getEd25519PublicKey(EdECPoint point)
9898
throws InvalidKeyException
9999
{
100100
byte[] keyData = getPublicKeyData(Ed25519PublicKeyParameters.KEY_SIZE, point);
101101

102102
return new Ed25519PublicKeyParameters(keyData, 0);
103103
}
104104

105-
private static Ed448PrivateKeyParameters getEd448PrivateKey(byte[] keyData)
105+
static Ed448PrivateKeyParameters getEd448PrivateKey(byte[] keyData)
106106
throws InvalidKeyException
107107
{
108108
if (Ed448PrivateKeyParameters.KEY_SIZE != keyData.length)
@@ -113,7 +113,7 @@ private static Ed448PrivateKeyParameters getEd448PrivateKey(byte[] keyData)
113113
return new Ed448PrivateKeyParameters(keyData, 0);
114114
}
115115

116-
private static Ed448PublicKeyParameters getEd448PublicKey(EdECPoint point)
116+
static Ed448PublicKeyParameters getEd448PublicKey(EdECPoint point)
117117
throws InvalidKeyException
118118
{
119119
byte[] keyData = getPublicKeyData(Ed448PublicKeyParameters.KEY_SIZE, point);

prov/src/test/jdk1.15/org/bouncycastle/jcajce/provider/test/EdDSA15Test.java

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,27 @@
66
import java.security.KeyFactory;
77
import java.security.KeyPair;
88
import java.security.KeyPairGenerator;
9+
import java.security.PrivateKey;
910
import java.security.PublicKey;
1011
import java.security.Signature;
1112
import java.security.cert.Certificate;
1213
import java.security.cert.CertificateFactory;
1314
import java.security.interfaces.EdECKey;
1415
import java.security.spec.AlgorithmParameterSpec;
16+
import java.security.spec.EdECPrivateKeySpec;
17+
import java.security.spec.EdECPublicKeySpec;
18+
import java.security.spec.KeySpec;
1519
import java.security.spec.NamedParameterSpec;
1620
import java.util.Base64;
1721

18-
import org.bouncycastle.jcajce.interfaces.EdDSAPrivateKey;
19-
import org.bouncycastle.jcajce.spec.RawEncodedKeySpec;
20-
import org.bouncycastle.jcajce.spec.EdDSAParameterSpec;
21-
import org.bouncycastle.jce.provider.BouncyCastleProvider;
22-
2322
import junit.framework.Test;
2423
import junit.framework.TestCase;
2524
import junit.framework.TestSuite;
25+
import org.bouncycastle.jcajce.interfaces.EdDSAPrivateKey;
26+
import org.bouncycastle.jcajce.spec.EdDSAParameterSpec;
27+
import org.bouncycastle.jcajce.spec.RawEncodedKeySpec;
28+
import org.bouncycastle.jce.provider.BouncyCastleProvider;
29+
import org.bouncycastle.util.Strings;
2630

2731
public class EdDSA15Test
2832
extends TestCase
@@ -149,6 +153,40 @@ private void implTestInterop(String algorithm)
149153
implTestInteropCase(kpSunEC, sigSunEC, sigBC);
150154
// implTestInteropCase(kpSunEC, sigSunEC, sigSunEC);
151155
}
156+
157+
KeyFactory sunKeyFact = KeyFactory.getInstance(algorithm, "SunEC");
158+
KeyFactory bcKeyFact = KeyFactory.getInstance(algorithm, bc);
159+
KeyPair kpSunEC = kpGenSunEC.generateKeyPair();
160+
161+
KeySpec pubSpec = sunKeyFact.getKeySpec(kpSunEC.getPublic(), EdECPublicKeySpec.class);
162+
PublicKey pubKey = bcKeyFact.generatePublic(pubSpec);
163+
164+
KeySpec privSpec = sunKeyFact.getKeySpec(kpSunEC.getPrivate(), EdECPrivateKeySpec.class);
165+
PrivateKey privKey = bcKeyFact.generatePrivate(privSpec);
166+
167+
sigBC.initSign(kpSunEC.getPrivate());
168+
169+
sigBC.update(Strings.toByteArray("Hello, world!"));
170+
171+
byte[] sig = sigBC.sign();
172+
173+
sigBC.initVerify(pubKey);
174+
175+
sigBC.update(Strings.toByteArray("Hello, world!"));
176+
177+
sigBC.verify(sig);
178+
179+
sigBC.initSign(privKey);
180+
181+
sigBC.update(Strings.toByteArray("Hello, world!"));
182+
183+
sig = sigBC.sign();
184+
185+
sigBC.initVerify(pubKey);
186+
187+
sigBC.update(Strings.toByteArray("Hello, world!"));
188+
189+
sigBC.verify(sig);
152190
}
153191

154192
private void implTestInteropCase(KeyPair kp, Signature signer, Signature verifier)

0 commit comments

Comments
 (0)