Skip to content

Commit a3df8e0

Browse files
author
gefeili
committed
Solve the bugs related EDDSA_LEGACY with Ed448
1 parent a45fee9 commit a3df8e0

14 files changed

+108
-14
lines changed

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -454,9 +454,8 @@ else if (getKeyAlgorithm() == PublicKeyAlgorithmTags.EDDSA_LEGACY)
454454
{
455455
byte[] a = BigIntegers.asUnsignedByteArray(sigValues[0].getValue());
456456
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);
457+
//TODO: distinguish Ed25519 and Ed448
458+
signature = Arrays.concatenate(a, b);
460459
}
461460
else
462461
{

pg/src/main/java/org/bouncycastle/openpgp/operator/PGPKeyConverter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ protected PGPKeyConverter()
7575
* <td>AES-128</td>
7676
* </tr>
7777
* <tr>
78-
* <td>Curve448</td>
78+
* <td>Curve448Legacy (not in RFC Draft)</td>
7979
* <td>SHA2-512</td>
8080
* <td>AES-256</td>
8181
* </tr>

pg/src/main/java/org/bouncycastle/openpgp/operator/RFC6637Utils.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import java.io.IOException;
55

66
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
7+
import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
78
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
89
import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers;
910
import org.bouncycastle.bcpg.ECDHPublicBCPGKey;
@@ -37,14 +38,15 @@ else if (pubKeyData.getKey() instanceof X448PublicBCPGKey)
3738
return "X448withSHA512CKDF";
3839
}
3940
ECDHPublicBCPGKey ecKey = (ECDHPublicBCPGKey)pubKeyData.getKey();
41+
String curve = ecKey.getCurveOID().equals(EdECObjectIdentifiers.id_X448) ? "X448" : "X25519";
4042
switch (ecKey.getHashAlgorithm())
4143
{
4244
case HashAlgorithmTags.SHA256:
43-
return "X25519withSHA256CKDF";
45+
return curve + "withSHA256CKDF";
4446
case HashAlgorithmTags.SHA384:
45-
return "X25519withSHA384CKDF";
47+
return curve + "withSHA384CKDF";
4648
case HashAlgorithmTags.SHA512:
47-
return "X25519withSHA512CKDF";
49+
return curve + "withSHA512CKDF";
4850
default:
4951
throw new IllegalArgumentException("Unknown hash algorithm specified: " + ecKey.getHashAlgorithm());
5052
}

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

Lines changed: 7 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,11 @@ 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+
return new EdDsaSigner(new Ed448Signer(new byte[0]), createDigest(hashAlgorithm));
99106
case PublicKeyAlgorithmTags.Ed25519:
100107
return new EdDsaSigner(new Ed25519Signer(), createDigest(hashAlgorithm));
101108
case PublicKeyAlgorithmTags.Ed448:

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.io.IOException;
44
import java.math.BigInteger;
55

6+
import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
67
import org.bouncycastle.bcpg.AEADEncDataPacket;
78
import org.bouncycastle.bcpg.ECDHPublicBCPGKey;
89
import org.bouncycastle.bcpg.HashAlgorithmTags;
@@ -118,6 +119,15 @@ else if (keyAlgorithm == PublicKeyAlgorithmTags.ECDH)
118119
// skip the 0x40 header byte.
119120
secret = BcUtil.getSecret(new X25519Agreement(), privKey, new X25519PublicKeyParameters(pEnc, 1));
120121
}
122+
else if (ecPubKey.getCurveOID().equals(EdECObjectIdentifiers.id_X448))
123+
{
124+
if (pEnc.length != 1 + X448PublicKeyParameters.KEY_SIZE || 0x40 != pEnc[0])
125+
{
126+
throw new IllegalArgumentException("Invalid Curve25519 public key");
127+
}
128+
// skip the 0x40 header byte.
129+
secret = BcUtil.getSecret(new X448Agreement(), privKey, new X448PublicKeyParameters(pEnc, 1));
130+
}
121131
else
122132
{
123133
ECDomainParameters ecParameters = ((ECPrivateKeyParameters)privKey).getParameters();

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import java.math.BigInteger;
55
import java.security.SecureRandom;
66

7+
import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
78
import org.bouncycastle.bcpg.ECDHPublicBCPGKey;
89
import org.bouncycastle.bcpg.HashAlgorithmTags;
910
import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
@@ -94,6 +95,17 @@ protected byte[] encryptSessionInfo(PGPPublicKey pubKey, byte[] sessionInfo)
9495
((X25519PublicKeyParameters)ephKp.getPublic()).encode(ephPubEncoding, 1);
9596
return encryptSessionInfo(sessionInfo, secret, userKeyingMaterial, ephPubEncoding, ecPubKey.getHashAlgorithm(), ecPubKey.getSymmetricKeyAlgorithm());
9697
}
98+
else if (ecPubKey.getCurveOID().equals(EdECObjectIdentifiers.id_X448))
99+
{
100+
AsymmetricCipherKeyPair ephKp = getAsymmetricCipherKeyPair(new X448KeyPairGenerator(), new X448KeyGenerationParameters(random));
101+
102+
byte[] secret = BcUtil.getSecret(new X448Agreement(), ephKp.getPrivate(), cryptoPublicKey);
103+
104+
byte[] ephPubEncoding = new byte[1 + X448PublicKeyParameters.KEY_SIZE];
105+
ephPubEncoding[0] = X_HDR;
106+
((X448PublicKeyParameters)ephKp.getPublic()).encode(ephPubEncoding, 1);
107+
return encryptSessionInfo(sessionInfo, secret, userKeyingMaterial, ephPubEncoding, ecPubKey.getHashAlgorithm(), ecPubKey.getSymmetricKeyAlgorithm());
108+
}
97109
else
98110
{
99111
AsymmetricCipherKeyPair ephKp = getAsymmetricCipherKeyPair(new ECKeyPairGenerator(),

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,17 @@ 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+
99+
if (keyAlgorithm == PublicKeyAlgorithmTags.EDDSA_LEGACY && privateKey.getAlgorithm().equals("Ed448"))
100+
{
101+
// Try my best to solve Ed448Legacy issue
102+
signature = helper.createSignature("Ed448");
103+
}
104+
else
105+
{
106+
signature = helper.createSignature(keyAlgorithm, hashAlgorithm);
107+
}
108+
99109

100110
try
101111
{

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,18 @@ public JcaPGPContentVerifierBuilder(int keyAlgorithm, int hashAlgorithm)
7373
public PGPContentVerifier build(final PGPPublicKey publicKey)
7474
throws PGPException
7575
{
76-
final Signature signature = helper.createSignature(keyAlgorithm, hashAlgorithm);
76+
final Signature signature;
77+
78+
if (keyAlgorithm == PublicKeyAlgorithmTags.EDDSA_LEGACY
79+
&& ((EdDSAPublicBCPGKey)publicKey.getPublicKeyPacket().getKey()).getCurveOID().equals(EdECObjectIdentifiers.id_Ed448))
80+
{
81+
// Try my best to solve Ed448Legacy issue
82+
signature = helper.createSignature("Ed448");
83+
}
84+
else
85+
{
86+
signature = helper.createSignature(keyAlgorithm, hashAlgorithm);
87+
}
7788

7889
final PGPDigestCalculator digestCalculator = digestCalculatorProviderBuilder.build().get(hashAlgorithm);
7990
final PublicKey jcaKey = keyConverter.getPublicKey(publicKey);

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -728,11 +728,12 @@ private BCPGKey getPublicBCPGKey(PublicKey pubKey, int keySize, BCPGKeyOperation
728728

729729
private byte[] getPointEncUncompressed(PublicKey pubKey, int publicKeySize)
730730
{
731-
SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfo.getInstance(pubKey.getEncoded());
731+
byte[] pubInfo = SubjectPublicKeyInfo.getInstance(pubKey.getEncoded()).getPublicKeyData().getBytes();
732732
byte[] pointEnc = new byte[1 + publicKeySize];
733733

734734
pointEnc[0] = 0x40;
735-
System.arraycopy(pubInfo.getPublicKeyData().getBytes(), 0, pointEnc, 1, pointEnc.length - 1);
735+
//offset with pointEnc.length - pubInfo.length to avoid leading zero issue
736+
System.arraycopy(pubInfo, 0, pointEnc, pointEnc.length - pubInfo.length , pubInfo.length);
736737
return pointEnc;
737738
}
738739

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,15 @@ private byte[] decryptSessionData(JcaPGPKeyConverter converter, PGPPrivateKey pr
264264
}
265265
publicKey = getPublicKey(pEnc, EdECObjectIdentifiers.id_X25519, 1);
266266
}
267+
else if (ecKey.getCurveOID().equals(EdECObjectIdentifiers.id_X448))
268+
{
269+
agreementName = RFC6637Utils.getXDHAlgorithm(pubKeyData);
270+
if (pEnc.length != (1 + X448PublicBCPGKey.LENGTH) || 0x40 != pEnc[0])
271+
{
272+
throw new IllegalArgumentException("Invalid Curve25519 public key");
273+
}
274+
publicKey = getPublicKey(pEnc, EdECObjectIdentifiers.id_X448, 1);
275+
}
267276
else
268277
{
269278
X9ECParametersHolder x9Params = ECNamedCurveTable.getByOIDLazy(ecKey.getCurveOID());
@@ -318,7 +327,7 @@ private Key getSessionKey(JcaPGPKeyConverter converter, PGPPrivateKey privKey, S
318327
throws PGPException, GeneralSecurityException
319328
{
320329
PrivateKey privateKey = converter.getPrivateKey(privKey);
321-
Key key = JcaJcePGPUtil.getSecret(helper, publicKey, RFC6637Utils.getKeyEncryptionOID(symmetricKeyAlgorithm).getId(), agreementName, ukms, privateKey);
330+
Key key = JcaJcePGPUtil.getSecret(helper, publicKey, RFC6637Utils.getKeyEncryptionOID(symmetricKeyAlgorithm).getId(), agreementName, ukms, privateKey);
322331
Cipher c = helper.createKeyWrapper(symmetricKeyAlgorithm);
323332
c.init(Cipher.UNWRAP_MODE, key);
324333
return c.unwrap(keyEnc, "Session", Cipher.SECRET_KEY);

0 commit comments

Comments
 (0)