Skip to content

Commit 9aed89e

Browse files
committed
Merge branch 'fixEd448Signing' of https://github.com/pgpainless/bc-java into pgpainless-fixEd448Signing
2 parents 03eb041 + d07266b commit 9aed89e

File tree

6 files changed

+168
-8
lines changed

6 files changed

+168
-8
lines changed

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

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.bouncycastle.bcpg.SignatureSubpacket;
2020
import org.bouncycastle.bcpg.TrustPacket;
2121
import org.bouncycastle.math.ec.rfc8032.Ed25519;
22+
import org.bouncycastle.math.ec.rfc8032.Ed448;
2223
import org.bouncycastle.openpgp.operator.PGPContentVerifier;
2324
import org.bouncycastle.openpgp.operator.PGPContentVerifierBuilder;
2425
import org.bouncycastle.openpgp.operator.PGPContentVerifierBuilderProvider;
@@ -454,9 +455,19 @@ else if (getKeyAlgorithm() == PublicKeyAlgorithmTags.EDDSA_LEGACY)
454455
{
455456
byte[] a = BigIntegers.asUnsignedByteArray(sigValues[0].getValue());
456457
byte[] b = BigIntegers.asUnsignedByteArray(sigValues[1].getValue());
457-
signature = new byte[Ed25519.SIGNATURE_SIZE];
458-
System.arraycopy(a, 0, signature, Ed25519.PUBLIC_KEY_SIZE - a.length, a.length);
459-
System.arraycopy(b, 0, signature, Ed25519.SIGNATURE_SIZE - b.length, b.length);
458+
if (a.length + b.length == Ed25519.SIGNATURE_SIZE)
459+
{
460+
signature = new byte[Ed25519.SIGNATURE_SIZE];
461+
System.arraycopy(a, 0, signature, Ed25519.PUBLIC_KEY_SIZE - a.length, a.length);
462+
System.arraycopy(b, 0, signature, Ed25519.SIGNATURE_SIZE - b.length, b.length);
463+
}
464+
else
465+
{
466+
signature = new byte[Ed448.SIGNATURE_SIZE];
467+
System.arraycopy(a, 0, signature, Ed448.PUBLIC_KEY_SIZE - a.length, a.length);
468+
System.arraycopy(b, 0, signature, Ed448.SIGNATURE_SIZE - b.length, b.length);
469+
}
470+
460471
}
461472
else
462473
{

pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcImplProvider.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
import org.bouncycastle.crypto.engines.RFC3394WrapEngine;
3434
import org.bouncycastle.crypto.engines.RSABlindedEngine;
3535
import org.bouncycastle.crypto.engines.TwofishEngine;
36+
import org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters;
37+
import org.bouncycastle.crypto.params.Ed25519PublicKeyParameters;
3638
import org.bouncycastle.crypto.signers.DSADigestSigner;
3739
import org.bouncycastle.crypto.signers.DSASigner;
3840
import org.bouncycastle.crypto.signers.ECDSASigner;
@@ -96,6 +98,14 @@ static Signer createSigner(int keyAlgorithm, int hashAlgorithm, CipherParameters
9698
case PublicKeyAlgorithmTags.ECDSA:
9799
return new DSADigestSigner(new ECDSASigner(), createDigest(hashAlgorithm));
98100
case PublicKeyAlgorithmTags.EDDSA_LEGACY:
101+
if (keyParam instanceof Ed25519PrivateKeyParameters || keyParam instanceof Ed25519PublicKeyParameters)
102+
{
103+
return new EdDsaSigner(new Ed25519Signer(), createDigest(hashAlgorithm));
104+
}
105+
else
106+
{
107+
return new EdDsaSigner(new Ed448Signer(new byte[0]), createDigest(hashAlgorithm));
108+
}
99109
case PublicKeyAlgorithmTags.Ed25519:
100110
return new EdDsaSigner(new Ed25519Signer(), createDigest(hashAlgorithm));
101111
case PublicKeyAlgorithmTags.Ed448:

pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPContentSignerBuilder.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,14 @@ public PGPContentSigner build(final int signatureType, final long keyID, final P
9595
final PGPDigestCalculator digestCalculator = digestCalculatorProviderBuilder.build().get(hashAlgorithm);
9696
final PGPDigestCalculator edDigestCalculator = digestCalculatorProviderBuilder.build().get(hashAlgorithm);
9797
final Signature signature;
98-
signature = helper.createSignature(keyAlgorithm, hashAlgorithm);
98+
if (keyAlgorithm == PublicKeyAlgorithmTags.EDDSA_LEGACY && privateKey.getAlgorithm().equals("Ed448"))
99+
{
100+
signature = helper.createSignature(PublicKeyAlgorithmTags.Ed448, hashAlgorithm);
101+
}
102+
else
103+
{
104+
signature = helper.createSignature(keyAlgorithm, hashAlgorithm);
105+
}
99106

100107
try
101108
{

pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPContentVerifierBuilderProvider.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
import java.security.SignatureException;
99
import java.security.interfaces.RSAPublicKey;
1010

11-
import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
12-
import org.bouncycastle.bcpg.EdDSAPublicBCPGKey;
1311
import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
1412
import org.bouncycastle.jcajce.io.OutputStreamFactory;
1513
import org.bouncycastle.jcajce.util.DefaultJcaJceHelper;
@@ -73,11 +71,19 @@ public JcaPGPContentVerifierBuilder(int keyAlgorithm, int hashAlgorithm)
7371
public PGPContentVerifier build(final PGPPublicKey publicKey)
7472
throws PGPException
7573
{
76-
final Signature signature = helper.createSignature(keyAlgorithm, hashAlgorithm);
77-
7874
final PGPDigestCalculator digestCalculator = digestCalculatorProviderBuilder.build().get(hashAlgorithm);
7975
final PublicKey jcaKey = keyConverter.getPublicKey(publicKey);
8076

77+
final Signature signature;
78+
if (keyAlgorithm == PublicKeyAlgorithmTags.EDDSA_LEGACY && jcaKey.getAlgorithm().equals("Ed448"))
79+
{
80+
signature = helper.createSignature(PublicKeyAlgorithmTags.Ed448, hashAlgorithm);
81+
}
82+
else
83+
{
84+
signature = helper.createSignature(keyAlgorithm, hashAlgorithm);
85+
}
86+
8187
try
8288
{
8389
signature.initVerify(jcaKey);

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

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,28 @@
22

33
import org.bouncycastle.bcpg.EdDSAPublicBCPGKey;
44
import org.bouncycastle.bcpg.EdSecretBCPGKey;
5+
import org.bouncycastle.bcpg.HashAlgorithmTags;
56
import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
67
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
78
import org.bouncycastle.crypto.generators.Ed25519KeyPairGenerator;
89
import org.bouncycastle.crypto.params.Ed25519KeyGenerationParameters;
910
import org.bouncycastle.jcajce.spec.EdDSAParameterSpec;
1011
import org.bouncycastle.jce.provider.BouncyCastleProvider;
1112
import org.bouncycastle.openpgp.PGPException;
13+
import org.bouncycastle.openpgp.PGPKeyPair;
14+
import org.bouncycastle.openpgp.PGPSignature;
15+
import org.bouncycastle.openpgp.PGPSignatureGenerator;
16+
import org.bouncycastle.openpgp.operator.PGPContentSignerBuilder;
17+
import org.bouncycastle.openpgp.operator.PGPContentVerifierBuilderProvider;
18+
import org.bouncycastle.openpgp.operator.bc.BcPGPContentSignerBuilder;
19+
import org.bouncycastle.openpgp.operator.bc.BcPGPContentVerifierBuilderProvider;
1220
import org.bouncycastle.openpgp.operator.bc.BcPGPKeyPair;
21+
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
22+
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
1323
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyPair;
1424

1525
import java.io.IOException;
26+
import java.nio.charset.StandardCharsets;
1627
import java.security.*;
1728
import java.util.Date;
1829

@@ -31,6 +42,60 @@ public void performTest()
3142
{
3243
testConversionOfJcaKeyPair();
3344
testConversionOfBcKeyPair();
45+
testV4SigningVerificationWithJcaKey();
46+
testV4SigningVerificationWithBcKey();
47+
}
48+
49+
private void testV4SigningVerificationWithJcaKey()
50+
throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, PGPException
51+
{
52+
Date date = currentTimeRounded();
53+
KeyPairGenerator gen = KeyPairGenerator.getInstance("EDDSA", new BouncyCastleProvider());
54+
gen.initialize(new EdDSAParameterSpec("Ed25519"));
55+
KeyPair kp = gen.generateKeyPair();
56+
PGPKeyPair keyPair = new JcaPGPKeyPair(PublicKeyAlgorithmTags.EDDSA_LEGACY, kp, date);
57+
58+
byte[] data = "Hello, World!\n".getBytes(StandardCharsets.UTF_8);
59+
60+
PGPContentSignerBuilder contSigBuilder = new JcaPGPContentSignerBuilder(
61+
keyPair.getPublicKey().getAlgorithm(),
62+
HashAlgorithmTags.SHA512)
63+
.setProvider(new BouncyCastleProvider());
64+
PGPSignatureGenerator sigGen = new PGPSignatureGenerator(contSigBuilder);
65+
sigGen.init(PGPSignature.BINARY_DOCUMENT, keyPair.getPrivateKey());
66+
sigGen.update(data);
67+
PGPSignature signature = sigGen.generate();
68+
69+
PGPContentVerifierBuilderProvider contVerBuilder = new JcaPGPContentVerifierBuilderProvider()
70+
.setProvider(new BouncyCastleProvider());
71+
signature.init(contVerBuilder, keyPair.getPublicKey());
72+
signature.update(data);
73+
isTrue(signature.verify());
74+
}
75+
76+
private void testV4SigningVerificationWithBcKey()
77+
throws PGPException
78+
{
79+
Date date = currentTimeRounded();
80+
Ed25519KeyPairGenerator gen = new Ed25519KeyPairGenerator();
81+
gen.init(new Ed25519KeyGenerationParameters(new SecureRandom()));
82+
AsymmetricCipherKeyPair kp = gen.generateKeyPair();
83+
BcPGPKeyPair keyPair = new BcPGPKeyPair(PublicKeyAlgorithmTags.EDDSA_LEGACY, kp, date);
84+
85+
byte[] data = "Hello, World!\n".getBytes(StandardCharsets.UTF_8);
86+
87+
PGPContentSignerBuilder contSigBuilder = new BcPGPContentSignerBuilder(
88+
keyPair.getPublicKey().getAlgorithm(),
89+
HashAlgorithmTags.SHA512);
90+
PGPSignatureGenerator sigGen = new PGPSignatureGenerator(contSigBuilder);
91+
sigGen.init(PGPSignature.BINARY_DOCUMENT, keyPair.getPrivateKey());
92+
sigGen.update(data);
93+
PGPSignature signature = sigGen.generate();
94+
95+
PGPContentVerifierBuilderProvider contVerBuilder = new BcPGPContentVerifierBuilderProvider();
96+
signature.init(contVerBuilder, keyPair.getPublicKey());
97+
signature.update(data);
98+
isTrue(signature.verify());
3499
}
35100

36101
private void testConversionOfJcaKeyPair()

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

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,17 @@
77
import org.bouncycastle.jcajce.spec.EdDSAParameterSpec;
88
import org.bouncycastle.jce.provider.BouncyCastleProvider;
99
import org.bouncycastle.openpgp.*;
10+
import org.bouncycastle.openpgp.operator.PGPContentSignerBuilder;
11+
import org.bouncycastle.openpgp.operator.PGPContentVerifierBuilderProvider;
12+
import org.bouncycastle.openpgp.operator.bc.BcPGPContentSignerBuilder;
13+
import org.bouncycastle.openpgp.operator.bc.BcPGPContentVerifierBuilderProvider;
1014
import org.bouncycastle.openpgp.operator.bc.BcPGPKeyPair;
15+
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
16+
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
1117
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyPair;
1218

1319
import java.io.IOException;
20+
import java.nio.charset.StandardCharsets;
1421
import java.security.*;
1522
import java.util.Date;
1623

@@ -29,6 +36,60 @@ public void performTest()
2936
{
3037
testConversionOfJcaKeyPair();
3138
testConversionOfBcKeyPair();
39+
testV4SigningVerificationWithJcaKey();
40+
testV4SigningVerificationWithBcKey();
41+
}
42+
43+
private void testV4SigningVerificationWithJcaKey()
44+
throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, PGPException
45+
{
46+
Date date = currentTimeRounded();
47+
KeyPairGenerator gen = KeyPairGenerator.getInstance("EDDSA", new BouncyCastleProvider());
48+
gen.initialize(new EdDSAParameterSpec("Ed448"));
49+
KeyPair kp = gen.generateKeyPair();
50+
PGPKeyPair keyPair = new JcaPGPKeyPair(PublicKeyAlgorithmTags.EDDSA_LEGACY, kp, date);
51+
52+
byte[] data = "Hello, World!\n".getBytes(StandardCharsets.UTF_8);
53+
54+
PGPContentSignerBuilder contSigBuilder = new JcaPGPContentSignerBuilder(
55+
keyPair.getPublicKey().getAlgorithm(),
56+
HashAlgorithmTags.SHA512)
57+
.setProvider(new BouncyCastleProvider());
58+
PGPSignatureGenerator sigGen = new PGPSignatureGenerator(contSigBuilder);
59+
sigGen.init(PGPSignature.BINARY_DOCUMENT, keyPair.getPrivateKey());
60+
sigGen.update(data);
61+
PGPSignature signature = sigGen.generate();
62+
63+
PGPContentVerifierBuilderProvider contVerBuilder = new JcaPGPContentVerifierBuilderProvider()
64+
.setProvider(new BouncyCastleProvider());
65+
signature.init(contVerBuilder, keyPair.getPublicKey());
66+
signature.update(data);
67+
isTrue(signature.verify());
68+
}
69+
70+
private void testV4SigningVerificationWithBcKey()
71+
throws PGPException
72+
{
73+
Date date = currentTimeRounded();
74+
Ed448KeyPairGenerator gen = new Ed448KeyPairGenerator();
75+
gen.init(new Ed448KeyGenerationParameters(new SecureRandom()));
76+
AsymmetricCipherKeyPair kp = gen.generateKeyPair();
77+
BcPGPKeyPair keyPair = new BcPGPKeyPair(PublicKeyAlgorithmTags.EDDSA_LEGACY, kp, date);
78+
79+
byte[] data = "Hello, World!\n".getBytes(StandardCharsets.UTF_8);
80+
81+
PGPContentSignerBuilder contSigBuilder = new BcPGPContentSignerBuilder(
82+
keyPair.getPublicKey().getAlgorithm(),
83+
HashAlgorithmTags.SHA512);
84+
PGPSignatureGenerator sigGen = new PGPSignatureGenerator(contSigBuilder);
85+
sigGen.init(PGPSignature.BINARY_DOCUMENT, keyPair.getPrivateKey());
86+
sigGen.update(data);
87+
PGPSignature signature = sigGen.generate();
88+
89+
PGPContentVerifierBuilderProvider contVerBuilder = new BcPGPContentVerifierBuilderProvider();
90+
signature.init(contVerBuilder, keyPair.getPublicKey());
91+
signature.update(data);
92+
isTrue(signature.verify());
3293
}
3394

3495
private void testConversionOfJcaKeyPair()

0 commit comments

Comments
 (0)