Skip to content

Commit

Permalink
Merge branch 'main' into pg-synchronize-bc_csharp
Browse files Browse the repository at this point in the history
  • Loading branch information
gefeili committed Jul 25, 2024
2 parents 8693881 + 4cdf535 commit 058cacf
Show file tree
Hide file tree
Showing 11 changed files with 707 additions and 22 deletions.
4 changes: 4 additions & 0 deletions pg/src/main/java/org/bouncycastle/bcpg/PaddingPacket.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ public PaddingPacket(int octetLen, SecureRandom random)

private static byte[] randomBytes(int octetCount, SecureRandom random)
{
if (octetCount <= 0)
{
throw new IllegalArgumentException("Octet count MUST NOT be 0 nor negative.");
}
byte[] bytes = new byte[octetCount];
random.nextBytes(bytes);
return bytes;
Expand Down
4 changes: 4 additions & 0 deletions pg/src/main/java/org/bouncycastle/openpgp/PGPKeyRing.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import org.bouncycastle.bcpg.BCPGInputStream;
import org.bouncycastle.bcpg.Packet;
import org.bouncycastle.bcpg.PacketFormat;
import org.bouncycastle.bcpg.PacketTags;
import org.bouncycastle.bcpg.SignaturePacket;
import org.bouncycastle.bcpg.TrustPacket;
Expand Down Expand Up @@ -144,6 +145,9 @@ public abstract void encode(OutputStream outStream)
public abstract byte[] getEncoded()
throws IOException;

public abstract byte[] getEncoded(PacketFormat format)
throws IOException;

private static boolean isUserTag(int tag)
{
switch (tag)
Expand Down
93 changes: 92 additions & 1 deletion pg/src/main/java/org/bouncycastle/openpgp/PGPPadding.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
package org.bouncycastle.openpgp;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.security.SecureRandom;

import org.bouncycastle.bcpg.BCPGInputStream;
import org.bouncycastle.bcpg.BCPGOutputStream;
import org.bouncycastle.bcpg.Packet;
import org.bouncycastle.bcpg.PacketFormat;
import org.bouncycastle.bcpg.PaddingPacket;
import org.bouncycastle.crypto.CryptoServicesRegistrar;

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

/**
* Minimum random padding length in octets.
* Chosen totally arbitrarily.
*/
public static final int MIN_PADDING_LEN = 16;

/**
* Maximum random padding length.
* Chosen somewhat arbitrarily, as SSH also uses max 255 bytes for random padding.
*
* @see <a href="https://www.rfc-editor.org/rfc/rfc4253.html#section-6">
* rfc4253 - Binary Packet Protocol</a>
*/
public static final int MAX_PADDING_LEN = 255;

/**
* Default constructor.
*
* @param in
* @param in packet input stream
* @throws IOException
*/
public PGPPadding(
Expand All @@ -34,8 +55,78 @@ public PGPPadding(
p = (PaddingPacket)packet;
}

/**
* Generate a new, random {@link PGPPadding} object.
* The padding consists of n random bytes, where n is a number between (inclusive) {@link #MIN_PADDING_LEN}
* and {@link #MAX_PADDING_LEN}.
*/
public PGPPadding()
{
this(CryptoServicesRegistrar.getSecureRandom());
}

/**
* Generate a new, random {@link PGPPadding} object.
* The padding consists of n random bytes, where n is a number between (inclusive) {@link #MIN_PADDING_LEN}
* and {@link #MAX_PADDING_LEN}.
*
* @param random random number generator instance
*/
public PGPPadding(SecureRandom random)
{
this(MIN_PADDING_LEN + random.nextInt(MAX_PADDING_LEN - MIN_PADDING_LEN + 1), random);
}

/**
* Generate a new, random {@link PGPPadding} object.
* The padding consists of <pre>len</pre> random bytes.
*/
public PGPPadding(int len)
{
this(len, CryptoServicesRegistrar.getSecureRandom());
}

/**
* Generate a new, random {@link PGPPadding} object.
* The padding consists of <pre>len</pre> random bytes.
*
* @param len number of random octets
* @param random random number generator instance
*/
public PGPPadding(int len, SecureRandom random)
{
this.p = new PaddingPacket(len, random);
}

/**
* Return the padding octets as a byte array.
* @return padding octets
*/
public byte[] getPadding()
{
return p.getPadding();
}

public void encode(OutputStream outStream)
throws IOException
{
BCPGOutputStream pOut = BCPGOutputStream.wrap(outStream);
p.encode(pOut);
}

public byte[] getEncoded()
throws IOException
{
return getEncoded(PacketFormat.ROUNDTRIP);
}

public byte[] getEncoded(PacketFormat format)
throws IOException
{
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
BCPGOutputStream pOut = new BCPGOutputStream(bOut, format);
encode(pOut);
pOut.close();
return bOut.toByteArray();
}
}
14 changes: 11 additions & 3 deletions pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKeyRing.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@

import org.bouncycastle.bcpg.ArmoredInputException;
import org.bouncycastle.bcpg.BCPGInputStream;
import org.bouncycastle.bcpg.BCPGOutputStream;
import org.bouncycastle.bcpg.Packet;
import org.bouncycastle.bcpg.PacketFormat;
import org.bouncycastle.bcpg.PacketTags;
import org.bouncycastle.bcpg.PublicKeyPacket;
import org.bouncycastle.bcpg.TrustPacket;
Expand Down Expand Up @@ -238,10 +240,16 @@ public Iterator<PGPPublicKey> iterator()
public byte[] getEncoded()
throws IOException
{
ByteArrayOutputStream bOut = new ByteArrayOutputStream();

this.encode(bOut);
return getEncoded(PacketFormat.ROUNDTRIP);
}

@Override
public byte[] getEncoded(PacketFormat format) throws IOException
{
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
BCPGOutputStream pOut = new BCPGOutputStream(bOut, format);
this.encode(pOut);
pOut.close();
return bOut.toByteArray();
}

Expand Down
14 changes: 11 additions & 3 deletions pg/src/main/java/org/bouncycastle/openpgp/PGPSecretKeyRing.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

import org.bouncycastle.bcpg.ArmoredInputException;
import org.bouncycastle.bcpg.BCPGInputStream;
import org.bouncycastle.bcpg.BCPGOutputStream;
import org.bouncycastle.bcpg.PacketFormat;
import org.bouncycastle.bcpg.PacketTags;
import org.bouncycastle.bcpg.PublicSubkeyPacket;
import org.bouncycastle.bcpg.SecretKeyPacket;
Expand Down Expand Up @@ -389,10 +391,16 @@ public int size()
public byte[] getEncoded()
throws IOException
{
ByteArrayOutputStream bOut = new ByteArrayOutputStream();

this.encode(bOut);
return getEncoded(PacketFormat.ROUNDTRIP);
}

@Override
public byte[] getEncoded(PacketFormat format) throws IOException
{
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
BCPGOutputStream pOut = new BCPGOutputStream(bOut, format);
this.encode(pOut);
pOut.close();
return bOut.toByteArray();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,19 @@
import org.bouncycastle.crypto.params.Ed25519KeyGenerationParameters;
import org.bouncycastle.jcajce.spec.EdDSAParameterSpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator;
import org.bouncycastle.openpgp.operator.bc.BcPGPKeyConverter;
import org.bouncycastle.openpgp.operator.bc.BcPGPKeyPair;
import org.bouncycastle.openpgp.*;
import org.bouncycastle.openpgp.operator.PGPContentSignerBuilder;
import org.bouncycastle.openpgp.operator.PGPContentVerifierBuilderProvider;
import org.bouncycastle.openpgp.operator.bc.*;
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyConverter;
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyPair;
import org.bouncycastle.util.Pack;
import org.bouncycastle.util.encoders.Hex;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.Date;

Expand All @@ -36,6 +38,8 @@ public void performTest()
{
testConversionOfJcaKeyPair();
testConversionOfBcKeyPair();
testV4SigningVerificationWithJcaKey();
testV4SigningVerificationWithBcKey();

testConversionOfTestVectorKey();
}
Expand Down Expand Up @@ -134,6 +138,58 @@ private void testConversionOfBcKeyPair()
}
}

private void testV4SigningVerificationWithJcaKey()
throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, PGPException
{
Date date = currentTimeRounded();
KeyPairGenerator gen = KeyPairGenerator.getInstance("EDDSA", new BouncyCastleProvider());
gen.initialize(new EdDSAParameterSpec("Ed25519"));
KeyPair kp = gen.generateKeyPair();
PGPKeyPair keyPair = new JcaPGPKeyPair(PublicKeyAlgorithmTags.Ed25519, kp, date);

byte[] data = "Hello, World!\n".getBytes(StandardCharsets.UTF_8);

PGPContentSignerBuilder contSigBuilder = new JcaPGPContentSignerBuilder(
keyPair.getPublicKey().getAlgorithm(),
HashAlgorithmTags.SHA512)
.setProvider(new BouncyCastleProvider());
PGPSignatureGenerator sigGen = new PGPSignatureGenerator(contSigBuilder);
sigGen.init(PGPSignature.BINARY_DOCUMENT, keyPair.getPrivateKey());
sigGen.update(data);
PGPSignature signature = sigGen.generate();

PGPContentVerifierBuilderProvider contVerBuilder = new JcaPGPContentVerifierBuilderProvider()
.setProvider(new BouncyCastleProvider());
signature.init(contVerBuilder, keyPair.getPublicKey());
signature.update(data);
isTrue(signature.verify());
}

private void testV4SigningVerificationWithBcKey()
throws PGPException
{
Date date = currentTimeRounded();
Ed25519KeyPairGenerator gen = new Ed25519KeyPairGenerator();
gen.init(new Ed25519KeyGenerationParameters(new SecureRandom()));
AsymmetricCipherKeyPair kp = gen.generateKeyPair();
BcPGPKeyPair keyPair = new BcPGPKeyPair(PublicKeyAlgorithmTags.Ed25519, kp, date);

byte[] data = "Hello, World!\n".getBytes(StandardCharsets.UTF_8);

PGPContentSignerBuilder contSigBuilder = new BcPGPContentSignerBuilder(
keyPair.getPublicKey().getAlgorithm(),
HashAlgorithmTags.SHA512);
PGPSignatureGenerator sigGen = new PGPSignatureGenerator(contSigBuilder);
sigGen.init(PGPSignature.BINARY_DOCUMENT, keyPair.getPrivateKey());
sigGen.update(data);
PGPSignature signature = sigGen.generate();

PGPContentVerifierBuilderProvider contVerBuilder = new BcPGPContentVerifierBuilderProvider();
signature.init(contVerBuilder, keyPair.getPublicKey());
signature.update(data);
isTrue(signature.verify());
}

private void testConversionOfTestVectorKey() throws PGPException, IOException {
JcaPGPKeyConverter jc = new JcaPGPKeyConverter().setProvider(new BouncyCastleProvider());
BcPGPKeyConverter bc = new BcPGPKeyConverter();
Expand Down
Loading

0 comments on commit 058cacf

Please sign in to comment.