Skip to content

Commit e7eea8e

Browse files
author
gefeili
committed
Add PGPKeyPairGeneratorTest
1 parent 6e8f4fd commit e7eea8e

File tree

7 files changed

+901
-12
lines changed

7 files changed

+901
-12
lines changed

pg/src/main/java/org/bouncycastle/openpgp/PGPKeyPair.java

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,32 @@
11
package org.bouncycastle.openpgp;
22

33
import org.bouncycastle.bcpg.KeyIdentifier;
4+
import org.bouncycastle.bcpg.PublicSubkeyPacket;
5+
import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator;
46

57
/**
68
* General class to handle JCA key pairs and convert them into OpenPGP ones.
79
* <p>
810
* A word for the unwary, the KeyID for a OpenPGP public key is calculated from
9-
* a hash that includes the time of creation, if you pass a different date to the
11+
* a hash that includes the time of creation, if you pass a different date to the
1012
* constructor below with the same public private key pair the KeyID will not be the
11-
* same as for previous generations of the key, so ideally you only want to do
13+
* same as for previous generations of the key, so ideally you only want to do
1214
* this once.
1315
*/
1416
public class PGPKeyPair
1517
{
16-
protected PGPPublicKey pub;
17-
protected PGPPrivateKey priv;
18+
protected PGPPublicKey pub;
19+
protected PGPPrivateKey priv;
1820

1921
/**
2022
* Create a key pair from a PGPPrivateKey and a PGPPublicKey.
21-
*
22-
* @param pub the public key
23+
*
24+
* @param pub the public key
2325
* @param priv the private key
2426
*/
2527
public PGPKeyPair(
26-
PGPPublicKey pub,
27-
PGPPrivateKey priv)
28+
PGPPublicKey pub,
29+
PGPPrivateKey priv)
2830
{
2931
this.pub = pub;
3032
this.priv = priv;
@@ -36,7 +38,7 @@ protected PGPKeyPair()
3638

3739
/**
3840
* Return the keyID associated with this key pair.
39-
*
41+
*
4042
* @return keyID
4143
*/
4244
public long getKeyID()
@@ -53,14 +55,32 @@ public KeyIdentifier getKeyIdentifier()
5355
{
5456
return getPublicKey().getKeyIdentifier();
5557
}
56-
58+
5759
public PGPPublicKey getPublicKey()
5860
{
5961
return pub;
6062
}
61-
63+
6264
public PGPPrivateKey getPrivateKey()
6365
{
6466
return priv;
6567
}
68+
69+
public PGPKeyPair asSubkey(KeyFingerPrintCalculator fingerPrintCalculator)
70+
throws PGPException
71+
{
72+
if (pub.getPublicKeyPacket() instanceof PublicSubkeyPacket)
73+
{
74+
return this; // is already subkey
75+
}
76+
77+
PublicSubkeyPacket pubSubPkt = new PublicSubkeyPacket(
78+
pub.getVersion(),
79+
pub.getAlgorithm(),
80+
pub.getCreationTime(),
81+
pub.getPublicKeyPacket().getKey());
82+
return new PGPKeyPair(
83+
new PGPPublicKey(pubSubPkt, fingerPrintCalculator),
84+
new PGPPrivateKey(pub.getKeyID(), pubSubPkt, priv.getPrivateKeyDataPacket()));
85+
}
6686
}
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
package org.bouncycastle.openpgp.operator;
2+
3+
import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
4+
import org.bouncycastle.openpgp.PGPException;
5+
import org.bouncycastle.openpgp.PGPKeyPair;
6+
7+
import java.math.BigInteger;
8+
import java.security.SecureRandom;
9+
import java.util.Date;
10+
11+
public abstract class PGPKeyPairGenerator
12+
{
13+
14+
protected final Date creationTime;
15+
protected final int version;
16+
protected SecureRandom random;
17+
protected final KeyFingerPrintCalculator fingerPrintCalculator;
18+
19+
/**
20+
* Create an instance of the key pair generator.
21+
*
22+
* @param version public key version ({@link org.bouncycastle.bcpg.PublicKeyPacket#VERSION_4}
23+
* or {@link org.bouncycastle.bcpg.PublicKeyPacket#VERSION_6}).
24+
* @param creationTime key creation time
25+
* @param random secure random number generator
26+
*/
27+
public PGPKeyPairGenerator(int version,
28+
Date creationTime,
29+
SecureRandom random,
30+
KeyFingerPrintCalculator fingerPrintCalculator)
31+
{
32+
this.creationTime = new Date((creationTime.getTime() / 1000) * 1000);
33+
this.version = version;
34+
this.random = random;
35+
this.fingerPrintCalculator = fingerPrintCalculator;
36+
}
37+
38+
/**
39+
* Generate a primary key.
40+
* A primary key MUST use a signing-capable public key algorithm.
41+
*
42+
* @return primary key pair
43+
* @throws PGPException if the key pair cannot be generated
44+
*/
45+
public PGPKeyPair generatePrimaryKey()
46+
throws PGPException
47+
{
48+
return generateEd25519KeyPair();
49+
}
50+
51+
/**
52+
* Generate an encryption subkey.
53+
* An encryption subkey MUST use an encryption-capable public key algorithm.
54+
*
55+
* @return encryption subkey pair
56+
* @throws PGPException if the key pair cannot be generated
57+
*/
58+
public PGPKeyPair generateEncryptionSubkey()
59+
throws PGPException
60+
{
61+
return generateX25519KeyPair().asSubkey(fingerPrintCalculator);
62+
}
63+
64+
/**
65+
* Generate a signing subkey.
66+
* A signing subkey MUST use a signing-capable public key algorithm.
67+
*
68+
* @return signing subkey pair
69+
* @throws PGPException if the key pair cannot be generated
70+
*/
71+
public PGPKeyPair generateSigningSubkey()
72+
throws PGPException
73+
{
74+
return generateEd25519KeyPair().asSubkey(fingerPrintCalculator);
75+
}
76+
77+
/**
78+
* Generate a RSA key pair with the given bit-strength.
79+
* It is recommended to use at least 2048 bits or more.
80+
* The key will be generated over the default exponent <pre>65537</pre>.
81+
* RSA keys are deprecated for OpenPGP v6.
82+
*
83+
* @param bitStrength strength of the key pair in bits
84+
* @return rsa key pair
85+
* @throws PGPException if the key pair cannot be generated
86+
*/
87+
public PGPKeyPair generateRsaKeyPair(int bitStrength)
88+
throws PGPException
89+
{
90+
return generateRsaKeyPair(BigInteger.valueOf(0x10001), bitStrength);
91+
}
92+
93+
/**
94+
* Generate a RSA key pair with the given bit-strength over a custom exponent.
95+
* It is recommended to use at least 2048 bits or more.
96+
* RSA keys are deprecated for OpenPGP v6.
97+
*
98+
* @param exponent RSA exponent <pre>e</pre>
99+
* @param bitStrength strength of the key pair in bits
100+
* @return rsa key pair
101+
* @throws PGPException if the key pair cannot be generated
102+
*/
103+
public abstract PGPKeyPair generateRsaKeyPair(BigInteger exponent, int bitStrength)
104+
throws PGPException;
105+
106+
/**
107+
* Generate an elliptic curve signing key over the twisted Edwards curve25519.
108+
* The key will use {@link PublicKeyAlgorithmTags#Ed25519} which was introduced with RFC9580.
109+
* For legacy Ed25519 keys use {@link #generateLegacyEd25519KeyPair()}.
110+
*
111+
* @return Ed25519 key pair
112+
* @throws PGPException if the key pair cannot be generated
113+
* @see <a href="https://www.rfc-editor.org/rfc/rfc9580.html#name-public-key-algorithms">
114+
* RFC9580 - Public Key Algorithms</a>
115+
*/
116+
public abstract PGPKeyPair generateEd25519KeyPair()
117+
throws PGPException;
118+
119+
/**
120+
* Generate an elliptic curve signing key over the twisted Edwards curve448.
121+
* The key will use {@link PublicKeyAlgorithmTags#Ed448} which was introduced with RFC9580.
122+
*
123+
* @return Ed448 signing key pair
124+
* @throws PGPException if the key pair cannot be generated
125+
* @see <a href="https://www.rfc-editor.org/rfc/rfc9580.html#name-public-key-algorithms">
126+
* RFC9580 - Public Key Algorithms</a>
127+
*/
128+
public abstract PGPKeyPair generateEd448KeyPair()
129+
throws PGPException;
130+
131+
/**
132+
* Generate an elliptic curve Diffie-Hellman encryption key over curve25519.
133+
* THe key will use {@link PublicKeyAlgorithmTags#X25519} which was introduced with RFC9580.
134+
* For legacy X25519 keys use {@link #generateLegacyX25519KeyPair()} instead.
135+
*
136+
* @return X25519 encryption key pair
137+
* @throws PGPException if the key pair cannot be generated
138+
* @see <a href="https://www.rfc-editor.org/rfc/rfc9580.html#name-public-key-algorithms">
139+
* RFC9580 - Public Key Algorithms</a>
140+
*/
141+
public abstract PGPKeyPair generateX25519KeyPair()
142+
throws PGPException;
143+
144+
/**
145+
* Generate an elliptic curve Diffie-Hellman encryption key over curve448.
146+
* THe key will use {@link PublicKeyAlgorithmTags#X448} which was introduced with RFC9580.
147+
*
148+
* @return X448 encryption key pair
149+
* @throws PGPException if the key pair cannot be generated
150+
* @see <a href="https://www.rfc-editor.org/rfc/rfc9580.html#name-public-key-algorithms">
151+
* RFC9580 - Public Key Algorithms</a>
152+
*/
153+
public abstract PGPKeyPair generateX448KeyPair()
154+
throws PGPException;
155+
156+
/**
157+
* Generate a legacy elliptic curve signing key pair over the twisted Edwards curve25519.
158+
* Legacy keys have good application support, but MUST NOT be used as OpenPGP v6 keys.
159+
* The key will use {@link PublicKeyAlgorithmTags#EDDSA_LEGACY} as algorithm ID.
160+
* For OpenPGP v6 (RFC9580) use {@link #generateEd25519KeyPair()} instead.
161+
*
162+
* @return legacy Ed25519 key pair
163+
* @throws PGPException if the key pair cannot be generated
164+
* @see <a href="https://datatracker.ietf.org/doc/html/draft-koch-eddsa-for-openpgp-04">
165+
* Legacy Draft: EdDSA for OpenPGP</a>
166+
*/
167+
public abstract PGPKeyPair generateLegacyEd25519KeyPair()
168+
throws PGPException;
169+
170+
/**
171+
* Generate a legacy elliptic curve Diffie-Hellman encryption key pair over curve25519.
172+
* Legacy keys have good application support, but MUST NOT be used as OpenPGP v6 keys.
173+
* The key will use {@link PublicKeyAlgorithmTags#ECDH} as algorithm ID.
174+
* For OpenPGP v6 (RFC9580) use {@link #generateX25519KeyPair()} instead.
175+
*
176+
* @return legacy X25519 key pair
177+
* @throws PGPException if the key pair cannot be generated
178+
*/
179+
public abstract PGPKeyPair generateLegacyX25519KeyPair()
180+
throws PGPException;
181+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package org.bouncycastle.openpgp.operator;
2+
3+
import java.util.Date;
4+
5+
public abstract class PGPKeyPairGeneratorProvider
6+
{
7+
public abstract PGPKeyPairGenerator get(int version, Date creationTime);
8+
}

0 commit comments

Comments
 (0)