Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/quite/humla-spongycastle.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Hook <dgh@cryptoworkshop.com>2014-06-21 08:27:50 +0400
committerDavid Hook <dgh@cryptoworkshop.com>2014-06-21 08:27:50 +0400
commit34a4dbfe31020b53486f49c7f3ecd0f824368485 (patch)
treee631d5f77633e9333497eb9459b1781f1d4f619e
parentced5721f840a6d816c81ff9f90cb9cca2efcd427 (diff)
add PGP EC support to BC lightweight implementation.
-rw-r--r--pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcImplProvider.java26
-rw-r--r--pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyConverter.java35
-rw-r--r--pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyPair.java4
-rw-r--r--pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java117
-rw-r--r--pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java85
-rw-r--r--pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java3
-rw-r--r--pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java3
-rw-r--r--pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/PGPUtil.java36
-rw-r--r--pg/src/test/java/org/bouncycastle/openpgp/test/PGPECDHTest.java77
-rw-r--r--pg/src/test/java/org/bouncycastle/openpgp/test/PGPECDSATest.java96
-rw-r--r--pg/src/test/java/org/bouncycastle/openpgp/test/PGPECMessageTest.java84
-rw-r--r--pg/src/test/java/org/bouncycastle/openpgp/test/RegressionTest.java1
12 files changed, 477 insertions, 90 deletions
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcImplProvider.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcImplProvider.java
index 87b303fd..357634f4 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcImplProvider.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcImplProvider.java
@@ -7,6 +7,7 @@ import org.bouncycastle.crypto.AsymmetricBlockCipher;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.Signer;
+import org.bouncycastle.crypto.Wrapper;
import org.bouncycastle.crypto.digests.MD2Digest;
import org.bouncycastle.crypto.digests.MD5Digest;
import org.bouncycastle.crypto.digests.RIPEMD160Digest;
@@ -18,6 +19,7 @@ import org.bouncycastle.crypto.digests.SHA512Digest;
import org.bouncycastle.crypto.digests.TigerDigest;
import org.bouncycastle.crypto.encodings.PKCS1Encoding;
import org.bouncycastle.crypto.engines.AESEngine;
+import org.bouncycastle.crypto.engines.AESFastEngine;
import org.bouncycastle.crypto.engines.BlowfishEngine;
import org.bouncycastle.crypto.engines.CAST5Engine;
import org.bouncycastle.crypto.engines.CamelliaEngine;
@@ -25,10 +27,12 @@ import org.bouncycastle.crypto.engines.DESEngine;
import org.bouncycastle.crypto.engines.DESedeEngine;
import org.bouncycastle.crypto.engines.ElGamalEngine;
import org.bouncycastle.crypto.engines.IDEAEngine;
+import org.bouncycastle.crypto.engines.RFC3394WrapEngine;
import org.bouncycastle.crypto.engines.RSABlindedEngine;
import org.bouncycastle.crypto.engines.TwofishEngine;
import org.bouncycastle.crypto.signers.DSADigestSigner;
import org.bouncycastle.crypto.signers.DSASigner;
+import org.bouncycastle.crypto.signers.ECDSASigner;
import org.bouncycastle.crypto.signers.RSADigestSigner;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKey;
@@ -73,8 +77,10 @@ class BcImplProvider
return new RSADigestSigner(createDigest(hashAlgorithm));
case PublicKeyAlgorithmTags.DSA:
return new DSADigestSigner(new DSASigner(), createDigest(hashAlgorithm));
+ case PublicKeyAlgorithmTags.ECDSA:
+ return new DSADigestSigner(new ECDSASigner(), createDigest(hashAlgorithm));
default:
- throw new PGPException("cannot recognise keyAlgorithm");
+ throw new PGPException("cannot recognise keyAlgorithm: " + keyAlgorithm);
}
}
@@ -120,6 +126,24 @@ class BcImplProvider
return engine;
}
+ static Wrapper createWrapper(int encAlgorithm)
+ throws PGPException
+ {
+ switch (encAlgorithm)
+ {
+ case SymmetricKeyAlgorithmTags.AES_128:
+ case SymmetricKeyAlgorithmTags.AES_192:
+ case SymmetricKeyAlgorithmTags.AES_256:
+ return new RFC3394WrapEngine(new AESFastEngine());
+ case SymmetricKeyAlgorithmTags.CAMELLIA_128:
+ case SymmetricKeyAlgorithmTags.CAMELLIA_192:
+ case SymmetricKeyAlgorithmTags.CAMELLIA_256:
+ return new RFC3394WrapEngine(new CamelliaEngine());
+ default:
+ throw new PGPException("unknown wrap algorithm: " + encAlgorithm);
+ }
+ }
+
static AsymmetricBlockCipher createPublicKeyCipher(int encAlgorithm)
throws PGPException
{
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyConverter.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyConverter.java
index 035c823a..0e346eed 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyConverter.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyConverter.java
@@ -2,21 +2,29 @@ package org.bouncycastle.openpgp.operator.bc;
import java.util.Date;
+import org.bouncycastle.asn1.x9.ECNamedCurveTable;
+import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.bcpg.BCPGKey;
import org.bouncycastle.bcpg.DSAPublicBCPGKey;
import org.bouncycastle.bcpg.DSASecretBCPGKey;
import org.bouncycastle.bcpg.ECDHPublicBCPGKey;
import org.bouncycastle.bcpg.ECDSAPublicBCPGKey;
+import org.bouncycastle.bcpg.ECPublicBCPGKey;
+import org.bouncycastle.bcpg.ECSecretBCPGKey;
import org.bouncycastle.bcpg.ElGamalPublicBCPGKey;
import org.bouncycastle.bcpg.ElGamalSecretBCPGKey;
+import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyPacket;
import org.bouncycastle.bcpg.RSAPublicBCPGKey;
import org.bouncycastle.bcpg.RSASecretBCPGKey;
+import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.DSAParameters;
import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
+import org.bouncycastle.crypto.params.ECNamedDomainParameters;
+import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.ElGamalParameters;
import org.bouncycastle.crypto.params.ElGamalPrivateKeyParameters;
@@ -70,12 +78,12 @@ public class BcPGPKeyConverter
ECPublicKeyParameters eK = (ECPublicKeyParameters)pubKey;
if (algorithm == PGPPublicKey.EC)
- { // TODO: KDF parameters
- bcpgKey = new ECDHPublicBCPGKey(null, eK.getQ(), 0, 0);
+ { // TODO: KDF parameters setting
+ bcpgKey = new ECDHPublicBCPGKey(((ECNamedDomainParameters)eK.getParameters()).getName(), eK.getQ(), HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
}
else
{
- bcpgKey = new ECDSAPublicBCPGKey(null, eK.getQ());
+ bcpgKey = new ECDSAPublicBCPGKey(((ECNamedDomainParameters)eK.getParameters()).getName(), eK.getQ());
}
}
else
@@ -111,6 +119,12 @@ public class BcPGPKeyConverter
privPk = new ElGamalSecretBCPGKey(esK.getX());
break;
+ case PGPPublicKey.ECDH:
+ case PGPPublicKey.ECDSA:
+ ECPrivateKeyParameters ecK = (ECPrivateKeyParameters)privKey;
+
+ privPk = new ECSecretBCPGKey(ecK.getD());
+ break;
default:
throw new PGPException("unknown key class");
}
@@ -141,6 +155,13 @@ public class BcPGPKeyConverter
ElGamalPublicBCPGKey elK = (ElGamalPublicBCPGKey)publicPk.getKey();
return new ElGamalPublicKeyParameters(elK.getY(), new ElGamalParameters(elK.getP(), elK.getG()));
+ case PGPPublicKey.ECDH:
+ case PGPPublicKey.ECDSA:
+ ECPublicBCPGKey ecPub = (ECPublicBCPGKey)publicPk.getKey();
+
+ X9ECParameters ecParams = ECNamedCurveTable.getByOID(ecPub.getCurveOID());
+
+ return new ECPublicKeyParameters(ecPub.getPoint(), new ECNamedDomainParameters(ecPub.getCurveOID(), ecParams.getCurve(), ecParams.getG(), ecParams.getN(), ecParams.getH()));
default:
throw new PGPException("unknown public key algorithm encountered");
}
@@ -183,6 +204,14 @@ public class BcPGPKeyConverter
ElGamalSecretBCPGKey elPriv = (ElGamalSecretBCPGKey)privPk;
return new ElGamalPrivateKeyParameters(elPriv.getX(), new ElGamalParameters(elPub.getP(), elPub.getG()));
+ case PGPPublicKey.ECDH:
+ case PGPPublicKey.ECDSA:
+ ECPublicBCPGKey ecPub = (ECPublicBCPGKey)pubPk.getKey();
+ ECSecretBCPGKey ecPriv = (ECSecretBCPGKey)privPk;
+
+ X9ECParameters ecParams = ECNamedCurveTable.getByOID(ecPub.getCurveOID());
+
+ return new ECPrivateKeyParameters(ecPriv.getX(), new ECNamedDomainParameters(ecPub.getCurveOID(), ecParams.getCurve(), ecParams.getG(), ecParams.getN(), ecParams.getH()));
default:
throw new PGPException("unknown public key algorithm encountered");
}
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyPair.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyPair.java
index ebf0fa0b..29460894 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyPair.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyPair.java
@@ -27,7 +27,7 @@ public class BcPGPKeyPair
public BcPGPKeyPair(int algorithm, AsymmetricCipherKeyPair keyPair, Date date)
throws PGPException
{
- this.pub = getPublicKey(algorithm, (AsymmetricKeyParameter)keyPair.getPublic(), date);
- this.priv = getPrivateKey(this.pub, (AsymmetricKeyParameter)keyPair.getPrivate());
+ this.pub = getPublicKey(algorithm, keyPair.getPublic(), date);
+ this.priv = getPrivateKey(this.pub, keyPair.getPrivate());
}
}
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java
index faf782d5..1d77ff09 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java
@@ -1,16 +1,25 @@
package org.bouncycastle.openpgp.operator.bc;
+import org.bouncycastle.asn1.nist.NISTNamedCurves;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.bcpg.ECDHPublicBCPGKey;
+import org.bouncycastle.bcpg.ECSecretBCPGKey;
import org.bouncycastle.crypto.AsymmetricBlockCipher;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.BufferedAsymmetricBlockCipher;
import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.Wrapper;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.ElGamalPrivateKeyParameters;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPrivateKey;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.operator.PGPDataDecryptor;
+import org.bouncycastle.openpgp.operator.PGPPad;
import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
+import org.bouncycastle.openpgp.operator.RFC6637KDFCalculator;
/**
* A decryptor factory for handling public key decryption operations.
@@ -31,57 +40,87 @@ public class BcPublicKeyDataDecryptorFactory
{
try
{
- AsymmetricBlockCipher c = BcImplProvider.createPublicKeyCipher(keyAlgorithm);
-
- AsymmetricKeyParameter key = keyConverter.getPrivateKey(privKey);
-
- BufferedAsymmetricBlockCipher c1 = new BufferedAsymmetricBlockCipher(c);
-
- c1.init(false, key);
-
- if (keyAlgorithm == PGPPublicKey.RSA_ENCRYPT
- || keyAlgorithm == PGPPublicKey.RSA_GENERAL)
+ if (keyAlgorithm != PGPPublicKey.ECDH)
{
- byte[] bi = secKeyData[0];
+ AsymmetricBlockCipher c = BcImplProvider.createPublicKeyCipher(keyAlgorithm);
- c1.processBytes(bi, 2, bi.length - 2);
- }
- else
- {
- BcPGPKeyConverter converter = new BcPGPKeyConverter();
- ElGamalPrivateKeyParameters parms = (ElGamalPrivateKeyParameters) converter.getPrivateKey(privKey);
- int size = (parms.getParameters().getP().bitLength() + 7) / 8;
- byte[] tmp = new byte[size];
+ AsymmetricKeyParameter key = keyConverter.getPrivateKey(privKey);
- byte[] bi = secKeyData[0]; // encoded MPI
- if (bi.length - 2 > size) // leading Zero? Shouldn't happen but...
- {
- c1.processBytes(bi, 3, bi.length - 3);
- }
- else
- {
- System.arraycopy(bi, 2, tmp, tmp.length - (bi.length - 2), bi.length - 2);
- c1.processBytes(tmp, 0, tmp.length);
- }
+ BufferedAsymmetricBlockCipher c1 = new BufferedAsymmetricBlockCipher(c);
- bi = secKeyData[1]; // encoded MPI
- for (int i = 0; i != tmp.length; i++)
- {
- tmp[i] = 0;
- }
+ c1.init(false, key);
- if (bi.length - 2 > size) // leading Zero? Shouldn't happen but...
+ if (keyAlgorithm == PGPPublicKey.RSA_ENCRYPT
+ || keyAlgorithm == PGPPublicKey.RSA_GENERAL)
{
- c1.processBytes(bi, 3, bi.length - 3);
+ byte[] bi = secKeyData[0];
+
+ c1.processBytes(bi, 2, bi.length - 2);
}
else
{
- System.arraycopy(bi, 2, tmp, tmp.length - (bi.length - 2), bi.length - 2);
- c1.processBytes(tmp, 0, tmp.length);
+ BcPGPKeyConverter converter = new BcPGPKeyConverter();
+ ElGamalPrivateKeyParameters parms = (ElGamalPrivateKeyParameters)converter.getPrivateKey(privKey);
+ int size = (parms.getParameters().getP().bitLength() + 7) / 8;
+ byte[] tmp = new byte[size];
+
+ byte[] bi = secKeyData[0]; // encoded MPI
+ if (bi.length - 2 > size) // leading Zero? Shouldn't happen but...
+ {
+ c1.processBytes(bi, 3, bi.length - 3);
+ }
+ else
+ {
+ System.arraycopy(bi, 2, tmp, tmp.length - (bi.length - 2), bi.length - 2);
+ c1.processBytes(tmp, 0, tmp.length);
+ }
+
+ bi = secKeyData[1]; // encoded MPI
+ for (int i = 0; i != tmp.length; i++)
+ {
+ tmp[i] = 0;
+ }
+
+ if (bi.length - 2 > size) // leading Zero? Shouldn't happen but...
+ {
+ c1.processBytes(bi, 3, bi.length - 3);
+ }
+ else
+ {
+ System.arraycopy(bi, 2, tmp, tmp.length - (bi.length - 2), bi.length - 2);
+ c1.processBytes(tmp, 0, tmp.length);
+ }
}
+
+ return c1.doFinal();
}
+ else
+ {
+ ECDHPublicBCPGKey ecKey = (ECDHPublicBCPGKey)privKey.getPublicKeyPacket().getKey();
+ X9ECParameters x9Params = NISTNamedCurves.getByOID(ecKey.getCurveOID());
+
+ byte[] enc = secKeyData[0];
+
+ int pLen = ((((enc[0] & 0xff) << 8) + (enc[1] & 0xff)) + 7) / 8;
+ byte[] pEnc = new byte[pLen];
+
+ System.arraycopy(enc, 2, pEnc, 0, pLen);
- return c1.doFinal();
+ byte[] keyEnc = new byte[enc[pLen + 2]];
+
+ System.arraycopy(enc, 2 + pLen + 1, keyEnc, 0, keyEnc.length);
+
+ Wrapper c = BcImplProvider.createWrapper(ecKey.getSymmetricKeyAlgorithm());
+
+ ECPoint S = x9Params.getCurve().decodePoint(pEnc).multiply(((ECSecretBCPGKey)privKey.getPrivateKeyDataPacket()).getX()).normalize();
+
+ RFC6637KDFCalculator rfc6637KDFCalculator = new RFC6637KDFCalculator(new BcPGPDigestCalculatorProvider().get(ecKey.getHashAlgorithm()), ecKey.getSymmetricKeyAlgorithm());
+ KeyParameter key = new KeyParameter(rfc6637KDFCalculator.createKey(ecKey.getCurveOID(), S, new BcKeyFingerprintCalculator().calculateFingerprint(privKey.getPublicKeyPacket())));
+
+ c.init(false, key);
+
+ return PGPPad.unpadSessionData(c.unwrap(keyEnc, 0, keyEnc.length));
+ }
}
catch (InvalidCipherTextException e)
{
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
index 53e71ad2..b1fa548d 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
@@ -1,14 +1,33 @@
package org.bouncycastle.openpgp.operator.bc;
+import java.io.IOException;
+import java.math.BigInteger;
import java.security.SecureRandom;
+import org.bouncycastle.asn1.nist.NISTNamedCurves;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.bcpg.ECDHPublicBCPGKey;
+import org.bouncycastle.bcpg.MPInteger;
import org.bouncycastle.crypto.AsymmetricBlockCipher;
+import org.bouncycastle.crypto.EphemeralKeyPair;
import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.KeyEncoder;
+import org.bouncycastle.crypto.Wrapper;
+import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
+import org.bouncycastle.crypto.generators.EphemeralKeyPairGenerator;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.crypto.params.ECDomainParameters;
+import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
+import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+import org.bouncycastle.crypto.params.ECPublicKeyParameters;
+import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKey;
+import org.bouncycastle.openpgp.operator.PGPPad;
import org.bouncycastle.openpgp.operator.PublicKeyKeyEncryptionMethodGenerator;
+import org.bouncycastle.openpgp.operator.RFC6637KDFCalculator;
/**
* A method generator for supporting public key based encryption operations.
@@ -47,22 +66,74 @@ public class BcPublicKeyKeyEncryptionMethodGenerator
{
try
{
- AsymmetricBlockCipher c = BcImplProvider.createPublicKeyCipher(pubKey.getAlgorithm());
+ if (pubKey.getAlgorithm() != PGPPublicKey.ECDH)
+ {
+ AsymmetricBlockCipher c = BcImplProvider.createPublicKeyCipher(pubKey.getAlgorithm());
- AsymmetricKeyParameter key = keyConverter.getPublicKey(pubKey);
+ AsymmetricKeyParameter key = keyConverter.getPublicKey(pubKey);
- if (random == null)
- {
- random = new SecureRandom();
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ c.init(true, new ParametersWithRandom(key, random));
+
+ return c.processBlock(sessionInfo, 0, sessionInfo.length);
}
+ else
+ {
+ ECDHPublicBCPGKey ecKey = (ECDHPublicBCPGKey)pubKey.getPublicKeyPacket().getKey();
+ X9ECParameters x9Params = NISTNamedCurves.getByOID(ecKey.getCurveOID());
+ ECDomainParameters ecParams = new ECDomainParameters(x9Params.getCurve(), x9Params.getG(), x9Params.getN());
+
+ // Generate the ephemeral key pair
+ ECKeyPairGenerator gen = new ECKeyPairGenerator();
+ gen.init(new ECKeyGenerationParameters(ecParams, random));
+
+ EphemeralKeyPairGenerator kGen = new EphemeralKeyPairGenerator(gen, new KeyEncoder()
+ {
+ public byte[] getEncoded(AsymmetricKeyParameter keyParameter)
+ {
+ return ((ECPublicKeyParameters)keyParameter).getQ().getEncoded(false);
+ }
+ });
+
+ EphemeralKeyPair ephKp = kGen.generate();
+
+ ECPrivateKeyParameters ephPriv = (ECPrivateKeyParameters)ephKp.getKeyPair().getPrivate();
+
+ ECPoint S = ecKey.getPoint().multiply(ephPriv.getD()).normalize();
+
+ RFC6637KDFCalculator rfc6637KDFCalculator = new RFC6637KDFCalculator(new BcPGPDigestCalculatorProvider().get(ecKey.getHashAlgorithm()), ecKey.getSymmetricKeyAlgorithm());
- c.init(true, new ParametersWithRandom(key, random));
+ KeyParameter key = new KeyParameter(rfc6637KDFCalculator.createKey(ecKey.getCurveOID(), S, pubKey.getFingerprint()));
- return c.processBlock(sessionInfo, 0, sessionInfo.length);
+ Wrapper c = BcImplProvider.createWrapper(ecKey.getSymmetricKeyAlgorithm());
+
+ c.init(true, new ParametersWithRandom(key, random));
+
+ byte[] paddedSessionData = PGPPad.padSessionData(sessionInfo);
+
+ byte[] C = c.wrap(paddedSessionData, 0, paddedSessionData.length);
+ byte[] VB = new MPInteger(new BigInteger(1, ephKp.getEncodedPublicKey())).getEncoded();
+
+ byte[] rv = new byte[VB.length + 1 + C.length];
+
+ System.arraycopy(VB, 0, rv, 0, VB.length);
+ rv[VB.length] = (byte)C.length;
+ System.arraycopy(C, 0, rv, VB.length + 1, C.length);
+
+ return rv;
+ }
}
catch (InvalidCipherTextException e)
{
throw new PGPException("exception encrypting session info: " + e.getMessage(), e);
}
+ catch (IOException e)
+ {
+ throw new PGPException("exception encrypting session info: " + e.getMessage(), e);
+ }
}
}
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java
index f626012b..589d17c3 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java
@@ -25,6 +25,7 @@ import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPrivateKey;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.operator.PGPDataDecryptor;
+import org.bouncycastle.openpgp.operator.PGPPad;
import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
import org.bouncycastle.openpgp.operator.RFC6637KDFCalculator;
@@ -159,7 +160,7 @@ public class JcePublicKeyDataDecryptorFactoryBuilder
Key paddedSessionKey = c.unwrap(keyEnc, "Session", Cipher.SECRET_KEY);
- return PGPUtil.unpadSessionData(paddedSessionKey.getEncoded());
+ return PGPPad.unpadSessionData(paddedSessionKey.getEncoded());
}
catch (InvalidKeyException e)
{
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
index f15faa8e..c229f9f6 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
@@ -32,6 +32,7 @@ import org.bouncycastle.jcajce.util.ProviderJcaJceHelper;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKey;
+import org.bouncycastle.openpgp.operator.PGPPad;
import org.bouncycastle.openpgp.operator.PublicKeyKeyEncryptionMethodGenerator;
import org.bouncycastle.openpgp.operator.RFC6637KDFCalculator;
@@ -121,7 +122,7 @@ public class JcePublicKeyKeyEncryptionMethodGenerator
c.init(Cipher.WRAP_MODE, key, random);
- byte[] paddedSessionData = PGPUtil.padSessionData(sessionInfo);
+ byte[] paddedSessionData = PGPPad.padSessionData(sessionInfo);
byte[] C = c.wrap(new SecretKeySpec(paddedSessionData, PGPUtil.getSymmetricCipherName(sessionInfo[0])));
byte[] VB = new MPInteger(new BigInteger(1, ephKp.getEncodedPublicKey())).getEncoded();
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/PGPUtil.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/PGPUtil.java
index d58ff012..7da5bc5d 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/PGPUtil.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/PGPUtil.java
@@ -121,40 +121,4 @@ class PGPUtil
return new SecretKeySpec(keyBytes, algName);
}
-
- public static byte[] padSessionData(byte[] sessionInfo)
- {
- byte[] result = new byte[40];
-
- System.arraycopy(sessionInfo, 0, result, 0, sessionInfo.length);
-
- byte padValue = (byte)(result.length -sessionInfo.length);
-
- for (int i = sessionInfo.length; i != result.length; i++)
- {
- result[i] = padValue;
- }
-
- return result;
- }
-
- public static byte[] unpadSessionData(byte[] encoded)
- throws PGPException
- {
- byte padValue = encoded[encoded.length - 1];
-
- for (int i = encoded.length - padValue; i != encoded.length; i++)
- {
- if (encoded[i] != padValue)
- {
- throw new PGPException("bad padding found in session data");
- }
- }
-
- byte[] taggedKey = new byte[encoded.length - padValue];
-
- System.arraycopy(encoded, 0, taggedKey, 0, taggedKey.length);
-
- return taggedKey;
- }
}
diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/PGPECDHTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/PGPECDHTest.java
index 595c97d2..77fc1e36 100644
--- a/pg/src/test/java/org/bouncycastle/openpgp/test/PGPECDHTest.java
+++ b/pg/src/test/java/org/bouncycastle/openpgp/test/PGPECDHTest.java
@@ -12,8 +12,14 @@ import java.security.spec.ECGenParameterSpec;
import java.util.Date;
import java.util.Iterator;
+import org.bouncycastle.asn1.nist.NISTNamedCurves;
+import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
+import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
+import org.bouncycastle.crypto.params.ECNamedDomainParameters;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.PGPEncryptedData;
import org.bouncycastle.openpgp.PGPEncryptedDataGenerator;
@@ -34,6 +40,10 @@ import org.bouncycastle.openpgp.PGPUtil;
import org.bouncycastle.openpgp.jcajce.JcaPGPObjectFactory;
import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator;
import org.bouncycastle.openpgp.operator.PGPDigestCalculator;
+import org.bouncycastle.openpgp.operator.bc.BcPGPDataEncryptorBuilder;
+import org.bouncycastle.openpgp.operator.bc.BcPGPKeyPair;
+import org.bouncycastle.openpgp.operator.bc.BcPublicKeyDataDecryptorFactory;
+import org.bouncycastle.openpgp.operator.bc.BcPublicKeyKeyEncryptionMethodGenerator;
import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
@@ -242,6 +252,72 @@ public class PGPECDHTest
}
}
+ private void encryptDecryptBCTest()
+ throws Exception
+ {
+ byte[] text = { (byte)'h', (byte)'e', (byte)'l', (byte)'l', (byte)'o', (byte)' ', (byte)'w', (byte)'o', (byte)'r', (byte)'l', (byte)'d', (byte)'!', (byte)'\n' };
+
+
+ ECKeyPairGenerator keyGen = new ECKeyPairGenerator();
+
+ X9ECParameters x9ECParameters = NISTNamedCurves.getByName("P-256");
+ keyGen.init(new ECKeyGenerationParameters(new ECNamedDomainParameters(NISTNamedCurves.getOID("P-256"), x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN()), new SecureRandom()));
+
+ AsymmetricCipherKeyPair kpEnc = keyGen.generateKeyPair();
+
+ PGPKeyPair ecdhKeyPair = new BcPGPKeyPair(PGPPublicKey.ECDH, kpEnc, new Date());
+
+ PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator();
+ ByteArrayOutputStream ldOut = new ByteArrayOutputStream();
+ OutputStream pOut = lData.open(ldOut, PGPLiteralDataGenerator.UTF8, PGPLiteralData.CONSOLE, text.length, new Date());
+
+ pOut.write(text);
+
+ pOut.close();
+
+ byte[] data = ldOut.toByteArray();
+
+ ByteArrayOutputStream cbOut = new ByteArrayOutputStream();
+
+ PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(new BcPGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.CAST5).setSecureRandom(new SecureRandom()));
+
+ cPk.addMethod(new BcPublicKeyKeyEncryptionMethodGenerator(ecdhKeyPair.getPublicKey()));
+
+ OutputStream cOut = cPk.open(new UncloseableOutputStream(cbOut), data.length);
+
+ cOut.write(data);
+
+ cOut.close();
+
+ JcaPGPObjectFactory pgpF = new JcaPGPObjectFactory(cbOut.toByteArray());
+
+ PGPEncryptedDataList encList = (PGPEncryptedDataList)pgpF.nextObject();
+
+ PGPPublicKeyEncryptedData encP = (PGPPublicKeyEncryptedData)encList.get(0);
+
+ InputStream clear = encP.getDataStream(new BcPublicKeyDataDecryptorFactory(ecdhKeyPair.getPrivateKey()));
+
+ pgpF = new JcaPGPObjectFactory(clear);
+
+ PGPLiteralData ld = (PGPLiteralData)pgpF.nextObject();
+
+ clear = ld.getInputStream();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ int ch;
+ while ((ch = clear.read()) >= 0)
+ {
+ bOut.write(ch);
+ }
+
+ byte[] out = bOut.toByteArray();
+
+ if (!areEqual(out, text))
+ {
+ fail("wrong plain text in generated packet");
+ }
+ }
+
public void performTest()
throws Exception
{
@@ -262,6 +338,7 @@ public class PGPECDHTest
testDecrypt(secretKeyRing);
encryptDecryptTest();
+ encryptDecryptBCTest();
generate();
}
diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/PGPECDSATest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/PGPECDSATest.java
index 0e7ba9aa..e59c9760 100644
--- a/pg/src/test/java/org/bouncycastle/openpgp/test/PGPECDSATest.java
+++ b/pg/src/test/java/org/bouncycastle/openpgp/test/PGPECDSATest.java
@@ -3,12 +3,19 @@ package org.bouncycastle.openpgp.test;
import java.io.ByteArrayInputStream;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
+import java.security.SecureRandom;
import java.security.Security;
import java.security.spec.ECGenParameterSpec;
import java.util.Date;
import java.util.Iterator;
+import org.bouncycastle.asn1.nist.NISTNamedCurves;
+import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.bcpg.HashAlgorithmTags;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
+import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
+import org.bouncycastle.crypto.params.ECNamedDomainParameters;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.PGPEncryptedData;
import org.bouncycastle.openpgp.PGPKeyPair;
@@ -22,6 +29,12 @@ import org.bouncycastle.openpgp.PGPSignatureGenerator;
import org.bouncycastle.openpgp.PGPUtil;
import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator;
import org.bouncycastle.openpgp.operator.PGPDigestCalculator;
+import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator;
+import org.bouncycastle.openpgp.operator.bc.BcPBESecretKeyDecryptorBuilder;
+import org.bouncycastle.openpgp.operator.bc.BcPGPContentSignerBuilder;
+import org.bouncycastle.openpgp.operator.bc.BcPGPContentVerifierBuilderProvider;
+import org.bouncycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider;
+import org.bouncycastle.openpgp.operator.bc.BcPGPKeyPair;
import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
@@ -151,6 +164,88 @@ public class PGPECDSATest
}
}
+ private void generateAndSignBC()
+ throws Exception
+ {
+ ECKeyPairGenerator keyGen = new ECKeyPairGenerator();
+
+ X9ECParameters x9ECParameters = NISTNamedCurves.getByName("P-256");
+ keyGen.init(new ECKeyGenerationParameters(new ECNamedDomainParameters(NISTNamedCurves.getOID("P-256"), x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN()), new SecureRandom()));
+
+ AsymmetricCipherKeyPair kpEnc = keyGen.generateKeyPair();
+
+ PGPKeyPair ecdsaKeyPair = new BcPGPKeyPair(PGPPublicKey.ECDSA, kpEnc, new Date());
+
+ //
+ // try a signature
+ //
+ PGPSignatureGenerator signGen = new PGPSignatureGenerator(new BcPGPContentSignerBuilder(PGPPublicKey.ECDSA, HashAlgorithmTags.SHA256));
+
+ signGen.init(PGPSignature.BINARY_DOCUMENT, ecdsaKeyPair.getPrivateKey());
+
+ signGen.update("hello world!".getBytes());
+
+ PGPSignature sig = signGen.generate();
+
+ sig.init(new BcPGPContentVerifierBuilderProvider(), ecdsaKeyPair.getPublicKey());
+
+ sig.update("hello world!".getBytes());
+
+ if (!sig.verify())
+ {
+ fail("signature failed to verify!");
+ }
+
+ //
+ // generate a key ring
+ //
+ char[] passPhrase = "test".toCharArray();
+ PGPDigestCalculator sha1Calc = new BcPGPDigestCalculatorProvider().get(HashAlgorithmTags.SHA1);
+ PGPKeyRingGenerator keyRingGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION, ecdsaKeyPair,
+ "test@bouncycastle.org", sha1Calc, null, null, new BcPGPContentSignerBuilder(ecdsaKeyPair.getPublicKey().getAlgorithm(), HashAlgorithmTags.SHA1), new JcePBESecretKeyEncryptorBuilder(PGPEncryptedData.AES_256, sha1Calc).setProvider("BC").build(passPhrase));
+
+ PGPPublicKeyRing pubRing = keyRingGen.generatePublicKeyRing();
+
+ PGPSecretKeyRing secRing = keyRingGen.generateSecretKeyRing();
+
+ KeyFingerPrintCalculator fingerCalc = new BcKeyFingerprintCalculator();
+
+ PGPPublicKeyRing pubRingEnc = new PGPPublicKeyRing(pubRing.getEncoded(), fingerCalc);
+
+ if (!Arrays.areEqual(pubRing.getEncoded(), pubRingEnc.getEncoded()))
+ {
+ fail("public key ring encoding failed");
+ }
+
+ PGPSecretKeyRing secRingEnc = new PGPSecretKeyRing(secRing.getEncoded(), fingerCalc);
+
+ if (!Arrays.areEqual(secRing.getEncoded(), secRingEnc.getEncoded()))
+ {
+ fail("secret key ring encoding failed");
+ }
+
+
+ //
+ // try a signature using encoded key
+ //
+ signGen = new PGPSignatureGenerator(new BcPGPContentSignerBuilder(PGPPublicKey.ECDSA, HashAlgorithmTags.SHA256));
+
+ signGen.init(PGPSignature.BINARY_DOCUMENT, secRing.getSecretKey().extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(passPhrase)));
+
+ signGen.update("hello world!".getBytes());
+
+ sig = signGen.generate();
+
+ sig.init(new BcPGPContentVerifierBuilderProvider(), secRing.getSecretKey().getPublicKey());
+
+ sig.update("hello world!".getBytes());
+
+ if (!sig.verify())
+ {
+ fail("re-encoded signature failed to verify!");
+ }
+ }
+
public void performTest()
throws Exception
{
@@ -179,6 +274,7 @@ public class PGPECDSATest
PGPSecretKeyRing secretKeyRing = new PGPSecretKeyRing(testPrivKey, new JcaKeyFingerprintCalculator());
generateAndSign();
+ generateAndSignBC();
//
// sExpr
diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/PGPECMessageTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/PGPECMessageTest.java
index 40743d13..7183b91f 100644
--- a/pg/src/test/java/org/bouncycastle/openpgp/test/PGPECMessageTest.java
+++ b/pg/src/test/java/org/bouncycastle/openpgp/test/PGPECMessageTest.java
@@ -21,6 +21,7 @@ import org.bouncycastle.openpgp.PGPSignatureList;
import org.bouncycastle.openpgp.jcajce.JcaPGPObjectFactory;
import org.bouncycastle.openpgp.jcajce.JcaPGPPublicKeyRing;
import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator;
+import org.bouncycastle.openpgp.operator.bc.BcPublicKeyDataDecryptorFactory;
import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
@@ -189,12 +190,95 @@ public class PGPECMessageTest
}
}
+ private void testBCEncMessage()
+ throws Exception
+ {
+ PGPObjectFactory pgpFact = new JcaPGPObjectFactory(encMessage);
+
+ PGPEncryptedDataList encList = (PGPEncryptedDataList)pgpFact.nextObject();
+
+ PGPPublicKeyEncryptedData encP = (PGPPublicKeyEncryptedData)encList.get(0);
+
+ PGPPublicKey publicKey = new JcaPGPPublicKeyRing(testPubKey).getPublicKey(encP.getKeyID());
+
+ PGPSecretKey secretKey = PGPSecretKey.parseSecretKeyFromSExpr(new ByteArrayInputStream(sExprKeySub), new JcePBEProtectionRemoverFactory("test".toCharArray()), publicKey);
+
+ InputStream clear = encP.getDataStream(new BcPublicKeyDataDecryptorFactory(secretKey.extractPrivateKey(null)));
+
+ PGPObjectFactory plainFact = new PGPObjectFactory(clear, new BcKeyFingerprintCalculator());
+
+ PGPCompressedData cData = (PGPCompressedData)plainFact.nextObject();
+
+ PGPObjectFactory compFact = new PGPObjectFactory(cData.getDataStream(), new BcKeyFingerprintCalculator());
+
+ PGPLiteralData lData = (PGPLiteralData)compFact.nextObject();
+
+ if (!"test.txt".equals(lData.getFileName()))
+ {
+ fail("wrong file name detected");
+ }
+ }
+
+ private void testBCSignedEncMessage()
+ throws Exception
+ {
+ PGPObjectFactory pgpFact = new JcaPGPObjectFactory(signedEncMessage);
+
+ PGPEncryptedDataList encList = (PGPEncryptedDataList)pgpFact.nextObject();
+
+ PGPPublicKeyEncryptedData encP = (PGPPublicKeyEncryptedData)encList.get(0);
+
+ JcaPGPPublicKeyRing publicKeyRing = new JcaPGPPublicKeyRing(testPubKey);
+
+ PGPPublicKey publicKey = publicKeyRing.getPublicKey(encP.getKeyID());
+
+ PGPSecretKey secretKey = PGPSecretKey.parseSecretKeyFromSExpr(new ByteArrayInputStream(sExprKeySub), new JcePBEProtectionRemoverFactory("test".toCharArray()), publicKey);
+
+ InputStream clear = encP.getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("BC").build(secretKey.extractPrivateKey(null)));
+
+ PGPObjectFactory plainFact = new PGPObjectFactory(clear, new BcKeyFingerprintCalculator());
+
+ PGPCompressedData cData = (PGPCompressedData)plainFact.nextObject();
+
+ PGPObjectFactory compFact = new PGPObjectFactory(cData.getDataStream(), new BcKeyFingerprintCalculator());
+
+ PGPOnePassSignatureList sList = (PGPOnePassSignatureList)compFact.nextObject();
+
+ PGPOnePassSignature ops = sList.get(0);
+
+ PGPLiteralData lData = (PGPLiteralData)compFact.nextObject();
+
+ if (!"test.txt".equals(lData.getFileName()))
+ {
+ fail("wrong file name detected");
+ }
+
+ InputStream dIn = lData .getInputStream();
+ int ch;
+
+ ops.init(new JcaPGPContentVerifierBuilderProvider().setProvider("BC"), publicKeyRing.getPublicKey(ops.getKeyID()));
+
+ while ((ch = dIn.read()) >= 0)
+ {
+ ops.update((byte)ch);
+ }
+
+ PGPSignatureList p3 = (PGPSignatureList)compFact.nextObject();
+
+ if (!ops.verify(p3.get(0)))
+ {
+ fail("Failed signature check");
+ }
+ }
+
public void performTest()
throws Exception
{
testMasterKey();
testEncMessage();
testSignedEncMessage();
+ testBCEncMessage();
+ testBCSignedEncMessage();
}
public String getName()
diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/RegressionTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/RegressionTest.java
index 35ae0355..b0990d62 100644
--- a/pg/src/test/java/org/bouncycastle/openpgp/test/RegressionTest.java
+++ b/pg/src/test/java/org/bouncycastle/openpgp/test/RegressionTest.java
@@ -27,6 +27,7 @@ public class RegressionTest
new PGPNoPrivateKeyTest(),
new PGPECDSATest(),
new PGPECDHTest(),
+ new PGPECMessageTest(),
new PGPParsingTest()
};