Skip to content

Commit 058cacf

Browse files
author
gefeili
committed
Merge branch 'main' into pg-synchronize-bc_csharp
2 parents 8693881 + 4cdf535 commit 058cacf

File tree

11 files changed

+707
-22
lines changed

11 files changed

+707
-22
lines changed

pg/src/main/java/org/bouncycastle/bcpg/PaddingPacket.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ public PaddingPacket(int octetLen, SecureRandom random)
3939

4040
private static byte[] randomBytes(int octetCount, SecureRandom random)
4141
{
42+
if (octetCount <= 0)
43+
{
44+
throw new IllegalArgumentException("Octet count MUST NOT be 0 nor negative.");
45+
}
4246
byte[] bytes = new byte[octetCount];
4347
random.nextBytes(bytes);
4448
return bytes;

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
import org.bouncycastle.bcpg.BCPGInputStream;
1212
import org.bouncycastle.bcpg.Packet;
13+
import org.bouncycastle.bcpg.PacketFormat;
1314
import org.bouncycastle.bcpg.PacketTags;
1415
import org.bouncycastle.bcpg.SignaturePacket;
1516
import org.bouncycastle.bcpg.TrustPacket;
@@ -144,6 +145,9 @@ public abstract void encode(OutputStream outStream)
144145
public abstract byte[] getEncoded()
145146
throws IOException;
146147

148+
public abstract byte[] getEncoded(PacketFormat format)
149+
throws IOException;
150+
147151
private static boolean isUserTag(int tag)
148152
{
149153
switch (tag)

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

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
package org.bouncycastle.openpgp;
22

3+
import java.io.ByteArrayOutputStream;
34
import java.io.IOException;
5+
import java.io.OutputStream;
6+
import java.security.SecureRandom;
47

58
import org.bouncycastle.bcpg.BCPGInputStream;
9+
import org.bouncycastle.bcpg.BCPGOutputStream;
610
import org.bouncycastle.bcpg.Packet;
11+
import org.bouncycastle.bcpg.PacketFormat;
712
import org.bouncycastle.bcpg.PaddingPacket;
13+
import org.bouncycastle.crypto.CryptoServicesRegistrar;
814

915
/**
1016
* The PGPPadding contains random data, and can be used to defend against traffic analysis on version 2 SEIPD messages
@@ -16,10 +22,25 @@ public class PGPPadding
1622
{
1723
private PaddingPacket p;
1824

25+
/**
26+
* Minimum random padding length in octets.
27+
* Chosen totally arbitrarily.
28+
*/
29+
public static final int MIN_PADDING_LEN = 16;
30+
31+
/**
32+
* Maximum random padding length.
33+
* Chosen somewhat arbitrarily, as SSH also uses max 255 bytes for random padding.
34+
*
35+
* @see <a href="https://www.rfc-editor.org/rfc/rfc4253.html#section-6">
36+
* rfc4253 - Binary Packet Protocol</a>
37+
*/
38+
public static final int MAX_PADDING_LEN = 255;
39+
1940
/**
2041
* Default constructor.
2142
*
22-
* @param in
43+
* @param in packet input stream
2344
* @throws IOException
2445
*/
2546
public PGPPadding(
@@ -34,8 +55,78 @@ public PGPPadding(
3455
p = (PaddingPacket)packet;
3556
}
3657

58+
/**
59+
* Generate a new, random {@link PGPPadding} object.
60+
* The padding consists of n random bytes, where n is a number between (inclusive) {@link #MIN_PADDING_LEN}
61+
* and {@link #MAX_PADDING_LEN}.
62+
*/
63+
public PGPPadding()
64+
{
65+
this(CryptoServicesRegistrar.getSecureRandom());
66+
}
67+
68+
/**
69+
* Generate a new, random {@link PGPPadding} object.
70+
* The padding consists of n random bytes, where n is a number between (inclusive) {@link #MIN_PADDING_LEN}
71+
* and {@link #MAX_PADDING_LEN}.
72+
*
73+
* @param random random number generator instance
74+
*/
75+
public PGPPadding(SecureRandom random)
76+
{
77+
this(MIN_PADDING_LEN + random.nextInt(MAX_PADDING_LEN - MIN_PADDING_LEN + 1), random);
78+
}
79+
80+
/**
81+
* Generate a new, random {@link PGPPadding} object.
82+
* The padding consists of <pre>len</pre> random bytes.
83+
*/
84+
public PGPPadding(int len)
85+
{
86+
this(len, CryptoServicesRegistrar.getSecureRandom());
87+
}
88+
89+
/**
90+
* Generate a new, random {@link PGPPadding} object.
91+
* The padding consists of <pre>len</pre> random bytes.
92+
*
93+
* @param len number of random octets
94+
* @param random random number generator instance
95+
*/
96+
public PGPPadding(int len, SecureRandom random)
97+
{
98+
this.p = new PaddingPacket(len, random);
99+
}
100+
101+
/**
102+
* Return the padding octets as a byte array.
103+
* @return padding octets
104+
*/
37105
public byte[] getPadding()
38106
{
39107
return p.getPadding();
40108
}
109+
110+
public void encode(OutputStream outStream)
111+
throws IOException
112+
{
113+
BCPGOutputStream pOut = BCPGOutputStream.wrap(outStream);
114+
p.encode(pOut);
115+
}
116+
117+
public byte[] getEncoded()
118+
throws IOException
119+
{
120+
return getEncoded(PacketFormat.ROUNDTRIP);
121+
}
122+
123+
public byte[] getEncoded(PacketFormat format)
124+
throws IOException
125+
{
126+
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
127+
BCPGOutputStream pOut = new BCPGOutputStream(bOut, format);
128+
encode(pOut);
129+
pOut.close();
130+
return bOut.toByteArray();
131+
}
41132
}

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

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717

1818
import org.bouncycastle.bcpg.ArmoredInputException;
1919
import org.bouncycastle.bcpg.BCPGInputStream;
20+
import org.bouncycastle.bcpg.BCPGOutputStream;
2021
import org.bouncycastle.bcpg.Packet;
22+
import org.bouncycastle.bcpg.PacketFormat;
2123
import org.bouncycastle.bcpg.PacketTags;
2224
import org.bouncycastle.bcpg.PublicKeyPacket;
2325
import org.bouncycastle.bcpg.TrustPacket;
@@ -238,10 +240,16 @@ public Iterator<PGPPublicKey> iterator()
238240
public byte[] getEncoded()
239241
throws IOException
240242
{
241-
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
242-
243-
this.encode(bOut);
243+
return getEncoded(PacketFormat.ROUNDTRIP);
244+
}
244245

246+
@Override
247+
public byte[] getEncoded(PacketFormat format) throws IOException
248+
{
249+
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
250+
BCPGOutputStream pOut = new BCPGOutputStream(bOut, format);
251+
this.encode(pOut);
252+
pOut.close();
245253
return bOut.toByteArray();
246254
}
247255

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

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
import org.bouncycastle.bcpg.ArmoredInputException;
1717
import org.bouncycastle.bcpg.BCPGInputStream;
18+
import org.bouncycastle.bcpg.BCPGOutputStream;
19+
import org.bouncycastle.bcpg.PacketFormat;
1820
import org.bouncycastle.bcpg.PacketTags;
1921
import org.bouncycastle.bcpg.PublicSubkeyPacket;
2022
import org.bouncycastle.bcpg.SecretKeyPacket;
@@ -389,10 +391,16 @@ public int size()
389391
public byte[] getEncoded()
390392
throws IOException
391393
{
392-
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
393-
394-
this.encode(bOut);
394+
return getEncoded(PacketFormat.ROUNDTRIP);
395+
}
395396

397+
@Override
398+
public byte[] getEncoded(PacketFormat format) throws IOException
399+
{
400+
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
401+
BCPGOutputStream pOut = new BCPGOutputStream(bOut, format);
402+
this.encode(pOut);
403+
pOut.close();
396404
return bOut.toByteArray();
397405
}
398406

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

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,19 @@
77
import org.bouncycastle.crypto.params.Ed25519KeyGenerationParameters;
88
import org.bouncycastle.jcajce.spec.EdDSAParameterSpec;
99
import org.bouncycastle.jce.provider.BouncyCastleProvider;
10-
import org.bouncycastle.openpgp.PGPException;
11-
import org.bouncycastle.openpgp.PGPPublicKey;
12-
import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator;
13-
import org.bouncycastle.openpgp.operator.bc.BcPGPKeyConverter;
14-
import org.bouncycastle.openpgp.operator.bc.BcPGPKeyPair;
10+
import org.bouncycastle.openpgp.*;
11+
import org.bouncycastle.openpgp.operator.PGPContentSignerBuilder;
12+
import org.bouncycastle.openpgp.operator.PGPContentVerifierBuilderProvider;
13+
import org.bouncycastle.openpgp.operator.bc.*;
14+
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
15+
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
1516
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyConverter;
1617
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyPair;
1718
import org.bouncycastle.util.Pack;
1819
import org.bouncycastle.util.encoders.Hex;
1920

2021
import java.io.IOException;
22+
import java.nio.charset.StandardCharsets;
2123
import java.security.*;
2224
import java.util.Date;
2325

@@ -36,6 +38,8 @@ public void performTest()
3638
{
3739
testConversionOfJcaKeyPair();
3840
testConversionOfBcKeyPair();
41+
testV4SigningVerificationWithJcaKey();
42+
testV4SigningVerificationWithBcKey();
3943

4044
testConversionOfTestVectorKey();
4145
}
@@ -134,6 +138,58 @@ private void testConversionOfBcKeyPair()
134138
}
135139
}
136140

141+
private void testV4SigningVerificationWithJcaKey()
142+
throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, PGPException
143+
{
144+
Date date = currentTimeRounded();
145+
KeyPairGenerator gen = KeyPairGenerator.getInstance("EDDSA", new BouncyCastleProvider());
146+
gen.initialize(new EdDSAParameterSpec("Ed25519"));
147+
KeyPair kp = gen.generateKeyPair();
148+
PGPKeyPair keyPair = new JcaPGPKeyPair(PublicKeyAlgorithmTags.Ed25519, kp, date);
149+
150+
byte[] data = "Hello, World!\n".getBytes(StandardCharsets.UTF_8);
151+
152+
PGPContentSignerBuilder contSigBuilder = new JcaPGPContentSignerBuilder(
153+
keyPair.getPublicKey().getAlgorithm(),
154+
HashAlgorithmTags.SHA512)
155+
.setProvider(new BouncyCastleProvider());
156+
PGPSignatureGenerator sigGen = new PGPSignatureGenerator(contSigBuilder);
157+
sigGen.init(PGPSignature.BINARY_DOCUMENT, keyPair.getPrivateKey());
158+
sigGen.update(data);
159+
PGPSignature signature = sigGen.generate();
160+
161+
PGPContentVerifierBuilderProvider contVerBuilder = new JcaPGPContentVerifierBuilderProvider()
162+
.setProvider(new BouncyCastleProvider());
163+
signature.init(contVerBuilder, keyPair.getPublicKey());
164+
signature.update(data);
165+
isTrue(signature.verify());
166+
}
167+
168+
private void testV4SigningVerificationWithBcKey()
169+
throws PGPException
170+
{
171+
Date date = currentTimeRounded();
172+
Ed25519KeyPairGenerator gen = new Ed25519KeyPairGenerator();
173+
gen.init(new Ed25519KeyGenerationParameters(new SecureRandom()));
174+
AsymmetricCipherKeyPair kp = gen.generateKeyPair();
175+
BcPGPKeyPair keyPair = new BcPGPKeyPair(PublicKeyAlgorithmTags.Ed25519, kp, date);
176+
177+
byte[] data = "Hello, World!\n".getBytes(StandardCharsets.UTF_8);
178+
179+
PGPContentSignerBuilder contSigBuilder = new BcPGPContentSignerBuilder(
180+
keyPair.getPublicKey().getAlgorithm(),
181+
HashAlgorithmTags.SHA512);
182+
PGPSignatureGenerator sigGen = new PGPSignatureGenerator(contSigBuilder);
183+
sigGen.init(PGPSignature.BINARY_DOCUMENT, keyPair.getPrivateKey());
184+
sigGen.update(data);
185+
PGPSignature signature = sigGen.generate();
186+
187+
PGPContentVerifierBuilderProvider contVerBuilder = new BcPGPContentVerifierBuilderProvider();
188+
signature.init(contVerBuilder, keyPair.getPublicKey());
189+
signature.update(data);
190+
isTrue(signature.verify());
191+
}
192+
137193
private void testConversionOfTestVectorKey() throws PGPException, IOException {
138194
JcaPGPKeyConverter jc = new JcaPGPKeyConverter().setProvider(new BouncyCastleProvider());
139195
BcPGPKeyConverter bc = new BcPGPKeyConverter();

0 commit comments

Comments
 (0)