Skip to content

Commit 8e6038e

Browse files
committed
Add test for EC curve key conversion
1 parent 22f6fec commit 8e6038e

File tree

2 files changed

+258
-1
lines changed

2 files changed

+258
-1
lines changed

pg/src/test/java/org/bouncycastle/openpgp/test/AbstractPgpKeyPairTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import org.bouncycastle.bcpg.test.AbstractPacketTest;
44
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
5+
import org.bouncycastle.jce.provider.BouncyCastleProvider;
56
import org.bouncycastle.openpgp.PGPException;
67
import org.bouncycastle.openpgp.operator.bc.BcPGPKeyConverter;
78
import org.bouncycastle.openpgp.operator.bc.BcPGPKeyPair;
@@ -35,7 +36,7 @@ public BcPGPKeyPair toBcKeyPair(JcaPGPKeyPair keyPair)
3536
public JcaPGPKeyPair toJcaKeyPair(BcPGPKeyPair keyPair)
3637
throws PGPException
3738
{
38-
JcaPGPKeyConverter c = new JcaPGPKeyConverter();
39+
JcaPGPKeyConverter c = new JcaPGPKeyConverter().setProvider(new BouncyCastleProvider());
3940
return new JcaPGPKeyPair(keyPair.getPublicKey().getAlgorithm(),
4041
new KeyPair(
4142
c.getPublicKey(keyPair.getPublicKey()),
Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
package org.bouncycastle.openpgp.test;
2+
3+
import org.bouncycastle.bcpg.*;
4+
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
5+
import org.bouncycastle.jce.provider.BouncyCastleProvider;
6+
import org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec;
7+
import org.bouncycastle.openpgp.*;
8+
import org.bouncycastle.openpgp.bc.BcPGPSecretKeyRing;
9+
import org.bouncycastle.openpgp.jcajce.JcaPGPSecretKeyRing;
10+
import org.bouncycastle.openpgp.operator.bc.BcPGPKeyConverter;
11+
import org.bouncycastle.openpgp.operator.bc.BcPGPKeyPair;
12+
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyConverter;
13+
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyPair;
14+
15+
import java.io.ByteArrayInputStream;
16+
import java.io.IOException;
17+
import java.nio.charset.StandardCharsets;
18+
import java.security.*;
19+
import java.util.Date;
20+
21+
public class ECDSAKeyPairTest extends AbstractPgpKeyPairTest
22+
{
23+
24+
private static final String PRIME256v1 = "" +
25+
"-----BEGIN PGP PRIVATE KEY BLOCK-----\n" +
26+
"Version: BCPG v@RELEASE_NAME@\n" +
27+
"\n" +
28+
"lHcEZkH7VRMIKoZIzj0DAQcCAwQee5wkHVVrG7u7CcrHoZOaC+reK0wn2Y5XPJoU\n" +
29+
"O6geh1j2qXHj4+f+a6lav5hzKIJZHkgBYcS0aeABgWNjKsHbAAD/b4K93MJF7c2l\n" +
30+
"4Y7ojBqTuZAOOD0Dyqe8MTXXyDUWN/0R/w==\n" +
31+
"=mPB9\n" +
32+
"-----END PGP PRIVATE KEY BLOCK-----";
33+
private static final String SECP384r1 = "" +
34+
"-----BEGIN PGP PRIVATE KEY BLOCK-----\n" +
35+
"Version: BCPG v@RELEASE_NAME@\n" +
36+
"\n" +
37+
"lKQEZkH7VhMFK4EEACIDAwQgkKs+EzJaFLgMZH5Fp1S8DCXZC0OildnuQX6F7Jzt\n" +
38+
"BgkYyfDZ/F2KNistCqfsmxWnwAxtdRuuY2PfehWktQBQaID0OfXUnOC2E5961b3/\n" +
39+
"7xoZU26T0npmTqX0P/wuXawAAX9S2V72/xeShrcIwIwy2QvCcsW9ATBSQ6U+T7KZ\n" +
40+
"zzFisUiqCgYa/9hoSNnu7iNrnrcYlQ==\n" +
41+
"=SyFg\n" +
42+
"-----END PGP PRIVATE KEY BLOCK-----";
43+
private static final String SECP521r1 = "" +
44+
"-----BEGIN PGP PRIVATE KEY BLOCK-----\n" +
45+
"Version: BCPG v@RELEASE_NAME@\n" +
46+
"\n" +
47+
"lNkEZkH7VhMFK4EEACMEIwQBxt7DenSWrjuJGR0ouSwylW3ZC6mX4S+A5Cav7nz3\n" +
48+
"DninA8Rdt3Cd5sHQ1IWea+J05NUZDKbOL417lUSPkAVLot0B/Qis90wODcGnAXbc\n" +
49+
"m+m7rN2/Waryj/EsxLxub4UNtyZ405C8dDo9ch2JRfHiH6R1dwyqD9+yY2lOPYO+\n" +
50+
"tn5fx/4AAgIDG9+DPtDf91tBMhBKc0f++t6aV115HLlyIpnEipThSwMTgzWm0uPZ\n" +
51+
"KD3CifJeUU/TMk9IGFYvRlaWBQfrB3V/Ahz4\n" +
52+
"=DD95\n" +
53+
"-----END PGP PRIVATE KEY BLOCK-----";
54+
private static final String BRAINPOOLP256r1 = "" +
55+
"-----BEGIN PGP PRIVATE KEY BLOCK-----\n" +
56+
"Version: BCPG v@RELEASE_NAME@\n" +
57+
"\n" +
58+
"lHgEZkH7VhMJKyQDAwIIAQEHAgMEj7YxVg4/2p4uuhcpRqGl2i+vDhjx8YhUUNJX\n" +
59+
"RNFozBuIWJ6zkW3wRKdD/7Y7tzKNwyHmZ4FBFCcUoLliLeD4SAABAIkEm4iT1g0B\n" +
60+
"Bo9vkUrUcP2b+vtOuwtmrvGrT0VzVXYlD5M=\n" +
61+
"=vZRh\n" +
62+
"-----END PGP PRIVATE KEY BLOCK-----";
63+
private static final String BRAINPOOLP384r1 = "" +
64+
"-----BEGIN PGP PRIVATE KEY BLOCK-----\n" +
65+
"Version: BCPG v@RELEASE_NAME@\n" +
66+
"\n" +
67+
"lKgEZkH7VhMJKyQDAwIIAQELAwMEYm1fhilklF53Pj91awsoO0aZsppmPk9KNESD\n" +
68+
"H7/gSK86gl+yhf4/oKSxeOFDHCU2es6Iijq/TCIaAjeFH3ITEyQ4tPdnDqQSz2xq\n" +
69+
"o6wtRTW3cRD9oyoOT8bAMdm+RYpJAAF5AXAfxp3VtxqVVxnR1mC3Z3nL25zmvdu1\n" +
70+
"oPRvA9fenVxTOlyU6X9qCycSuxamkPO7Gic=\n" +
71+
"=2eJn\n" +
72+
"-----END PGP PRIVATE KEY BLOCK-----";
73+
private static final String BRAINPOOLP521r1 = "" +
74+
"-----BEGIN PGP PRIVATE KEY BLOCK-----\n" +
75+
"Version: BCPG v@RELEASE_NAME@\n" +
76+
"\n" +
77+
"lNgEZkH7VhMJKyQDAwIIAQENBAMEbSjn4lQKNnC50PzeUtenikvF62KR7HfOLJTA\n" +
78+
"r/T17tFx3Qb6Ek/xQWIJ5nIHroOrduZjLigPOXqQ+GNhCgdNPGUqAWw1sfQ86nrx\n" +
79+
"jqlr67na3F3eaTJr9ajr2V37/5uHnuryJnkyy2laFdOGD0Ad9/bQkvXYoWVm0P07\n" +
80+
"uCPnexEAAgCSUoeS3c+DAZlWETdyuSDyvHK7GLO67+CgVsEyqBF/Kch/vhBZFWXA\n" +
81+
"Cs9lph8la5B0faKH5XSbeReudKGh/MjfIJo=\n" +
82+
"=MZeT\n" +
83+
"-----END PGP PRIVATE KEY BLOCK-----";
84+
85+
@Override
86+
public String getName()
87+
{
88+
return "ECDSAKeyPairTest";
89+
}
90+
91+
@Override
92+
public void performTest()
93+
throws Exception
94+
{
95+
Security.addProvider(new BouncyCastleProvider());
96+
testConversionOfParsedJcaKeyPair();
97+
testConversionOfParsedBcKeyPair();
98+
99+
testConversionOfFreshJcaKeyPair();
100+
}
101+
102+
private void testConversionOfParsedJcaKeyPair() throws PGPException, IOException {
103+
// parseAndConvertJca(PRIME256v1);
104+
// parseAndConvertJca(SECP384r1);
105+
// parseAndConvertJca(SECP521r1);
106+
parseAndConvertJca(BRAINPOOLP256r1);
107+
parseAndConvertJca(BRAINPOOLP384r1);
108+
parseAndConvertJca(BRAINPOOLP521r1);
109+
}
110+
111+
private void parseAndConvertJca(String curve) throws IOException, PGPException {
112+
JcaPGPKeyConverter c = new JcaPGPKeyConverter();
113+
PGPKeyPair parsed = parseJca(curve);
114+
byte[] pubEnc = parsed.getPublicKey().getEncoded();
115+
byte[] privEnc = parsed.getPrivateKey().getPrivateKeyDataPacket().getEncoded();
116+
117+
JcaPGPKeyPair j1 = new JcaPGPKeyPair(
118+
parsed.getPublicKey().getAlgorithm(),
119+
new KeyPair(c.getPublicKey(parsed.getPublicKey()),
120+
c.getPrivateKey(parsed.getPrivateKey())),
121+
parsed.getPublicKey().getCreationTime());
122+
isEncodingEqual(pubEnc, j1.getPublicKey().getEncoded());
123+
isEncodingEqual(privEnc, j1.getPrivateKey().getPrivateKeyDataPacket().getEncoded());
124+
125+
BcPGPKeyPair b1 = toBcKeyPair(j1);
126+
isEncodingEqual(pubEnc, b1.getPublicKey().getEncoded());
127+
isEncodingEqual(privEnc, b1.getPrivateKey().getPrivateKeyDataPacket().getEncoded());
128+
129+
JcaPGPKeyPair j2 = toJcaKeyPair(b1);
130+
isEncodingEqual(pubEnc, j2.getPublicKey().getEncoded());
131+
isEncodingEqual(privEnc, j2.getPrivateKey().getPrivateKeyDataPacket().getEncoded());
132+
133+
BcPGPKeyPair b2 = toBcKeyPair(j2);
134+
isEncodingEqual(pubEnc, b2.getPublicKey().getEncoded());
135+
isEncodingEqual(privEnc, b2.getPrivateKey().getPrivateKeyDataPacket().getEncoded());
136+
}
137+
138+
private void testConversionOfParsedBcKeyPair() throws PGPException, IOException {
139+
parseAndConvertBc(PRIME256v1);
140+
parseAndConvertBc(SECP384r1);
141+
parseAndConvertBc(SECP521r1);
142+
parseAndConvertBc(BRAINPOOLP256r1);
143+
parseAndConvertBc(BRAINPOOLP384r1);
144+
parseAndConvertBc(BRAINPOOLP521r1);
145+
}
146+
147+
private void parseAndConvertBc(String curve) throws IOException, PGPException {
148+
BcPGPKeyConverter c = new BcPGPKeyConverter();
149+
PGPKeyPair parsed = parseBc(curve);
150+
byte[] pubEnc = parsed.getPublicKey().getEncoded();
151+
byte[] privEnc = parsed.getPrivateKey().getPrivateKeyDataPacket().getEncoded();
152+
153+
BcPGPKeyPair b1 = new BcPGPKeyPair(
154+
parsed.getPublicKey().getAlgorithm(),
155+
new AsymmetricCipherKeyPair(
156+
c.getPublicKey(parsed.getPublicKey()),
157+
c.getPrivateKey(parsed.getPrivateKey())),
158+
parsed.getPublicKey().getCreationTime());
159+
isEncodingEqual(pubEnc, b1.getPublicKey().getEncoded());
160+
isEncodingEqual(privEnc, b1.getPrivateKey().getPrivateKeyDataPacket().getEncoded());
161+
162+
JcaPGPKeyPair j1 = toJcaKeyPair(b1);
163+
isEncodingEqual(pubEnc, j1.getPublicKey().getEncoded());
164+
isEncodingEqual(privEnc, j1.getPrivateKey().getPrivateKeyDataPacket().getEncoded());
165+
166+
BcPGPKeyPair b2 = toBcKeyPair(j1);
167+
isEncodingEqual(pubEnc, b2.getPublicKey().getEncoded());
168+
isEncodingEqual(privEnc, b2.getPrivateKey().getPrivateKeyDataPacket().getEncoded());
169+
170+
JcaPGPKeyPair j2 = toJcaKeyPair(b2);
171+
isEncodingEqual(pubEnc, j2.getPublicKey().getEncoded());
172+
isEncodingEqual(privEnc, j2.getPrivateKey().getPrivateKeyDataPacket().getEncoded());
173+
174+
}
175+
176+
private PGPKeyPair parseJca(String armored) throws IOException, PGPException {
177+
ByteArrayInputStream bIn = new ByteArrayInputStream(armored.getBytes(StandardCharsets.UTF_8));
178+
ArmoredInputStream aIn = new ArmoredInputStream(bIn);
179+
BCPGInputStream pIn = new BCPGInputStream(aIn);
180+
JcaPGPSecretKeyRing ring = new JcaPGPSecretKeyRing(pIn);
181+
PGPSecretKey sk = ring.getSecretKey();
182+
return new PGPKeyPair(sk.getPublicKey(), sk.extractPrivateKey(null));
183+
}
184+
185+
private PGPKeyPair parseBc(String armored) throws IOException, PGPException {
186+
ByteArrayInputStream bIn = new ByteArrayInputStream(armored.getBytes(StandardCharsets.UTF_8));
187+
ArmoredInputStream aIn = new ArmoredInputStream(bIn);
188+
BCPGInputStream pIn = new BCPGInputStream(aIn);
189+
BcPGPSecretKeyRing ring = new BcPGPSecretKeyRing(pIn);
190+
PGPSecretKey sk = ring.getSecretKey();
191+
return new PGPKeyPair(sk.getPublicKey(), sk.extractPrivateKey(null));
192+
}
193+
194+
private void testConversionOfFreshJcaKeyPair()
195+
throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, PGPException, IOException
196+
{
197+
for (String curve : new String[] {"prime256v1", "secp384r1", "secp521r1", "brainpoolP256r1", "brainpoolP384r1", "brainpoolP512r1"})
198+
{
199+
try {
200+
testConversionOfFreshJcaKeyPair(curve);
201+
} catch (Exception e) {
202+
203+
}
204+
}
205+
206+
}
207+
208+
private void testConversionOfFreshJcaKeyPair(String curve)
209+
throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException, PGPException
210+
{
211+
Date date = currentTimeRounded();
212+
KeyPairGenerator gen = KeyPairGenerator.getInstance("ECDSA", new BouncyCastleProvider());
213+
gen.initialize(new ECNamedCurveGenParameterSpec(curve));
214+
KeyPair kp = gen.generateKeyPair();
215+
216+
JcaPGPKeyPair j1 = new JcaPGPKeyPair(PublicKeyAlgorithmTags.ECDSA, kp, date);
217+
byte[] pubEnc = j1.getPublicKey().getEncoded();
218+
byte[] privEnc = j1.getPrivateKey().getPrivateKeyDataPacket().getEncoded();
219+
isTrue("Legacy ECDSA public key MUST be instanceof ECDSAPublicBCPGKey",
220+
j1.getPublicKey().getPublicKeyPacket().getKey() instanceof ECDSAPublicBCPGKey);
221+
isTrue("Legacy ECDSA secret key MUST be instanceof ECSecretBCPGKey",
222+
j1.getPrivateKey().getPrivateKeyDataPacket() instanceof ECSecretBCPGKey);
223+
224+
BcPGPKeyPair b1 = toBcKeyPair(j1);
225+
isEncodingEqual(pubEnc, b1.getPublicKey().getEncoded());
226+
isEncodingEqual(privEnc, b1.getPrivateKey().getPrivateKeyDataPacket().getEncoded());
227+
isTrue("Legacy ECDSA public key MUST be instanceof ECDSAPublicBCPGKey",
228+
b1.getPublicKey().getPublicKeyPacket().getKey() instanceof ECDSAPublicBCPGKey);
229+
isTrue(" Legacy ECDSA secret key MUST be instanceof ECSecretBCPGKey",
230+
b1.getPrivateKey().getPrivateKeyDataPacket() instanceof ECSecretBCPGKey);
231+
232+
JcaPGPKeyPair j2 = toJcaKeyPair(b1);
233+
isEncodingEqual(pubEnc, j2.getPublicKey().getEncoded());
234+
isEncodingEqual(privEnc, j2.getPrivateKey().getPrivateKeyDataPacket().getEncoded());
235+
isTrue("Legacy ECDSA public key MUST be instanceof ECDSAPublicBCPGKey",
236+
j2.getPublicKey().getPublicKeyPacket().getKey() instanceof ECDSAPublicBCPGKey);
237+
isTrue("Legacy ECDSA secret key MUST be instanceof ECSecretBCPGKey",
238+
j2.getPrivateKey().getPrivateKeyDataPacket() instanceof ECSecretBCPGKey);
239+
240+
BcPGPKeyPair b2 = toBcKeyPair(j2);
241+
isEncodingEqual(pubEnc, b2.getPublicKey().getEncoded());
242+
isEncodingEqual(privEnc, b2.getPrivateKey().getPrivateKeyDataPacket().getEncoded());
243+
isTrue("Legacy ECDSA public key MUST be instanceof ECDSAPublicBCPGKey",
244+
b2.getPublicKey().getPublicKeyPacket().getKey() instanceof ECDSAPublicBCPGKey);
245+
isTrue("Legacy ECDSA secret key MUST be instanceof ECSecretBCPGKey",
246+
b2.getPrivateKey().getPrivateKeyDataPacket() instanceof ECSecretBCPGKey);
247+
248+
isEquals("Creation time is preserved",
249+
date.getTime(), b2.getPublicKey().getCreationTime().getTime());
250+
}
251+
252+
public static void main(String[] args)
253+
{
254+
runTest(new ECDSAKeyPairTest());
255+
}
256+
}

0 commit comments

Comments
 (0)