org.bouncycastle.openpgp.operator.bc.BcPGPKeyConverter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bcpg-jdk15on Show documentation
Show all versions of bcpg-jdk15on Show documentation
The Bouncy Castle Java API for handling the OpenPGP protocol. This jar contains the OpenPGP API for JDK 1.5 to JDK 1.7. The APIs can be used in conjunction with a JCE/JCA provider such as the one provided with the Bouncy Castle Cryptography APIs.
package org.bouncycastle.openpgp.operator.bc;
import java.io.IOException;
import java.math.BigInteger;
import java.util.Date;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.cryptlib.CryptlibObjectIdentifiers;
import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.asn1.gnu.GNUObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
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.EdDSAPublicBCPGKey;
import org.bouncycastle.bcpg.EdSecretBCPGKey;
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.Ed25519PrivateKeyParameters;
import org.bouncycastle.crypto.params.Ed25519PublicKeyParameters;
import org.bouncycastle.crypto.params.ElGamalParameters;
import org.bouncycastle.crypto.params.ElGamalPrivateKeyParameters;
import org.bouncycastle.crypto.params.ElGamalPublicKeyParameters;
import org.bouncycastle.crypto.params.RSAKeyParameters;
import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
import org.bouncycastle.crypto.params.X25519PrivateKeyParameters;
import org.bouncycastle.crypto.params.X25519PublicKeyParameters;
import org.bouncycastle.crypto.util.PrivateKeyFactory;
import org.bouncycastle.crypto.util.PublicKeyFactory;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.openpgp.PGPAlgorithmParameters;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPKdfParameters;
import org.bouncycastle.openpgp.PGPPrivateKey;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.BigIntegers;
public class BcPGPKeyConverter
{
// We default to these as they are specified as mandatory in RFC 6631.
private static final PGPKdfParameters DEFAULT_KDF_PARAMETERS = new PGPKdfParameters(HashAlgorithmTags.SHA256,
SymmetricKeyAlgorithmTags.AES_128);
public PGPPrivateKey getPGPPrivateKey(PGPPublicKey pubKey, AsymmetricKeyParameter privKey)
throws PGPException
{
BCPGKey privPk = getPrivateBCPGKey(pubKey, privKey);
return new PGPPrivateKey(pubKey.getKeyID(), pubKey.getPublicKeyPacket(), privPk);
}
/**
* Create a PGPPublicKey from the passed in JCA one.
*
* Note: the time passed in affects the value of the key's keyID, so you probably only want
* to do this once for a JCA key, or make sure you keep track of the time you used.
*
* @param algorithm asymmetric algorithm type representing the public key.
* @param pubKey actual public key to associate.
* @param time date of creation.
* @throws PGPException on key creation problem.
*/
public PGPPublicKey getPGPPublicKey(int algorithm, PGPAlgorithmParameters algorithmParameters, AsymmetricKeyParameter pubKey, Date time)
throws PGPException
{
BCPGKey bcpgKey = getPublicBCPGKey(algorithm, algorithmParameters, pubKey, time);
return new PGPPublicKey(new PublicKeyPacket(algorithm, time, bcpgKey), new BcKeyFingerprintCalculator());
}
public AsymmetricKeyParameter getPrivateKey(PGPPrivateKey privKey)
throws PGPException
{
PublicKeyPacket pubPk = privKey.getPublicKeyPacket();
BCPGKey privPk = privKey.getPrivateKeyDataPacket();
try
{
switch (pubPk.getAlgorithm())
{
case PublicKeyAlgorithmTags.DSA:
{
DSAPublicBCPGKey dsaPub = (DSAPublicBCPGKey)pubPk.getKey();
DSASecretBCPGKey dsaPriv = (DSASecretBCPGKey)privPk;
return new DSAPrivateKeyParameters(dsaPriv.getX(),
new DSAParameters(dsaPub.getP(), dsaPub.getQ(), dsaPub.getG()));
}
case PublicKeyAlgorithmTags.ECDH:
{
ECDHPublicBCPGKey ecdhPub = (ECDHPublicBCPGKey)pubPk.getKey();
ECSecretBCPGKey ecdhK = (ECSecretBCPGKey)privPk;
if (CryptlibObjectIdentifiers.curvey25519.equals(ecdhPub.getCurveOID()))
{
// 'reverse' because the native format for X25519 private keys is little-endian
return implGetPrivateKeyPKCS8(new PrivateKeyInfo(
new AlgorithmIdentifier(EdECObjectIdentifiers.id_X25519),
new DEROctetString(Arrays.reverse(BigIntegers.asUnsignedByteArray(ecdhK.getX())))));
}
else
{
return implGetPrivateKeyEC(ecdhPub, ecdhK);
}
}
case PublicKeyAlgorithmTags.ECDSA:
return implGetPrivateKeyEC((ECDSAPublicBCPGKey)pubPk.getKey(), (ECSecretBCPGKey)privPk);
case PublicKeyAlgorithmTags.EDDSA:
{
EdSecretBCPGKey eddsaK = (EdSecretBCPGKey)privPk;
return implGetPrivateKeyPKCS8(new PrivateKeyInfo(
new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed25519),
new DEROctetString(BigIntegers.asUnsignedByteArray(eddsaK.getX()))));
}
case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT:
case PublicKeyAlgorithmTags.ELGAMAL_GENERAL:
{
ElGamalPublicBCPGKey elPub = (ElGamalPublicBCPGKey)pubPk.getKey();
ElGamalSecretBCPGKey elPriv = (ElGamalSecretBCPGKey)privPk;
return new ElGamalPrivateKeyParameters(elPriv.getX(), new ElGamalParameters(elPub.getP(), elPub.getG()));
}
case PublicKeyAlgorithmTags.RSA_ENCRYPT:
case PublicKeyAlgorithmTags.RSA_GENERAL:
case PublicKeyAlgorithmTags.RSA_SIGN:
{
RSAPublicBCPGKey rsaPub = (RSAPublicBCPGKey)pubPk.getKey();
RSASecretBCPGKey rsaPriv = (RSASecretBCPGKey)privPk;
return new RSAPrivateCrtKeyParameters(rsaPriv.getModulus(), rsaPub.getPublicExponent(),
rsaPriv.getPrivateExponent(), rsaPriv.getPrimeP(), rsaPriv.getPrimeQ(), rsaPriv.getPrimeExponentP(),
rsaPriv.getPrimeExponentQ(), rsaPriv.getCrtCoefficient());
}
default:
throw new PGPException("unknown public key algorithm encountered");
}
}
catch (PGPException e)
{
throw e;
}
catch (Exception e)
{
throw new PGPException("Exception constructing key", e);
}
}
public AsymmetricKeyParameter getPublicKey(PGPPublicKey publicKey)
throws PGPException
{
PublicKeyPacket publicPk = publicKey.getPublicKeyPacket();
try
{
switch (publicPk.getAlgorithm())
{
case PublicKeyAlgorithmTags.DSA:
{
DSAPublicBCPGKey dsaK = (DSAPublicBCPGKey)publicPk.getKey();
return new DSAPublicKeyParameters(dsaK.getY(), new DSAParameters(dsaK.getP(), dsaK.getQ(), dsaK.getG()));
}
case PublicKeyAlgorithmTags.ECDH:
{
ECDHPublicBCPGKey ecdhK = (ECDHPublicBCPGKey)publicPk.getKey();
if (ecdhK.getCurveOID().equals(CryptlibObjectIdentifiers.curvey25519))
{
byte[] pEnc = BigIntegers.asUnsignedByteArray(ecdhK.getEncodedPoint());
// skip the 0x40 header byte.
if (pEnc.length < 1 || 0x40 != pEnc[0])
{
throw new IllegalArgumentException("Invalid Curve25519 public key");
}
return implGetPublicKeyX509(new SubjectPublicKeyInfo(
new AlgorithmIdentifier(EdECObjectIdentifiers.id_X25519),
Arrays.copyOfRange(pEnc, 1, pEnc.length)));
}
else
{
return implGetPublicKeyEC(ecdhK);
}
}
case PublicKeyAlgorithmTags.ECDSA:
return implGetPublicKeyEC((ECDSAPublicBCPGKey)publicPk.getKey());
case PublicKeyAlgorithmTags.EDDSA:
{
EdDSAPublicBCPGKey eddsaK = (EdDSAPublicBCPGKey)publicPk.getKey();
byte[] pEnc = BigIntegers.asUnsignedByteArray(eddsaK.getEncodedPoint());
// skip the 0x40 header byte.
if (pEnc.length < 1 || 0x40 != pEnc[0])
{
throw new IllegalArgumentException("Invalid Ed25519 public key");
}
return implGetPublicKeyX509(new SubjectPublicKeyInfo(
new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed25519),
Arrays.copyOfRange(pEnc, 1, pEnc.length)));
}
case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT:
case PublicKeyAlgorithmTags.ELGAMAL_GENERAL:
ElGamalPublicBCPGKey elK = (ElGamalPublicBCPGKey)publicPk.getKey();
return new ElGamalPublicKeyParameters(elK.getY(), new ElGamalParameters(elK.getP(), elK.getG()));
case PublicKeyAlgorithmTags.RSA_ENCRYPT:
case PublicKeyAlgorithmTags.RSA_GENERAL:
case PublicKeyAlgorithmTags.RSA_SIGN:
{
RSAPublicBCPGKey rsaK = (RSAPublicBCPGKey)publicPk.getKey();
return new RSAKeyParameters(false, rsaK.getModulus(), rsaK.getPublicExponent());
}
default:
throw new PGPException("unknown public key algorithm encountered");
}
}
catch (PGPException e)
{
throw e;
}
catch (Exception e)
{
throw new PGPException("exception constructing public key", e);
}
}
private BCPGKey getPrivateBCPGKey(PGPPublicKey pubKey, AsymmetricKeyParameter privKey)
throws PGPException
{
switch (pubKey.getAlgorithm())
{
case PublicKeyAlgorithmTags.DSA:
{
DSAPrivateKeyParameters dsK = (DSAPrivateKeyParameters)privKey;
return new DSASecretBCPGKey(dsK.getX());
}
case PublicKeyAlgorithmTags.ECDH:
{
if (privKey instanceof ECPrivateKeyParameters)
{
ECPrivateKeyParameters ecK = (ECPrivateKeyParameters)privKey;
return new ECSecretBCPGKey(ecK.getD());
}
else
{
// 'reverse' because the native format for X25519 private keys is little-endian
X25519PrivateKeyParameters xK = (X25519PrivateKeyParameters)privKey;
return new ECSecretBCPGKey(new BigInteger(1, Arrays.reverse(xK.getEncoded())));
}
}
case PublicKeyAlgorithmTags.ECDSA:
{
ECPrivateKeyParameters ecK = (ECPrivateKeyParameters)privKey;
return new ECSecretBCPGKey(ecK.getD());
}
case PublicKeyAlgorithmTags.EDDSA:
{
Ed25519PrivateKeyParameters edK = (Ed25519PrivateKeyParameters)privKey;
return new EdSecretBCPGKey(new BigInteger(1, edK.getEncoded()));
}
case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT:
case PublicKeyAlgorithmTags.ELGAMAL_GENERAL:
{
ElGamalPrivateKeyParameters esK = (ElGamalPrivateKeyParameters)privKey;
return new ElGamalSecretBCPGKey(esK.getX());
}
case PublicKeyAlgorithmTags.RSA_ENCRYPT:
case PublicKeyAlgorithmTags.RSA_GENERAL:
case PublicKeyAlgorithmTags.RSA_SIGN:
{
RSAPrivateCrtKeyParameters rsK = (RSAPrivateCrtKeyParameters)privKey;
return new RSASecretBCPGKey(rsK.getExponent(), rsK.getP(), rsK.getQ());
}
default:
throw new PGPException("unknown key class");
}
}
private BCPGKey getPublicBCPGKey(int algorithm, PGPAlgorithmParameters algorithmParameters,
AsymmetricKeyParameter pubKey, Date time) throws PGPException
{
if (pubKey instanceof RSAKeyParameters)
{
RSAKeyParameters rK = (RSAKeyParameters)pubKey;
return new RSAPublicBCPGKey(rK.getModulus(), rK.getExponent());
}
else if (pubKey instanceof DSAPublicKeyParameters)
{
DSAPublicKeyParameters dK = (DSAPublicKeyParameters)pubKey;
DSAParameters dP = dK.getParameters();
return new DSAPublicBCPGKey(dP.getP(), dP.getQ(), dP.getG(), dK.getY());
}
else if (pubKey instanceof ElGamalPublicKeyParameters)
{
ElGamalPublicKeyParameters eK = (ElGamalPublicKeyParameters)pubKey;
ElGamalParameters eS = eK.getParameters();
return new ElGamalPublicBCPGKey(eS.getP(), eS.getG(), eK.getY());
}
else if (pubKey instanceof ECPublicKeyParameters)
{
ECPublicKeyParameters ecK = (ECPublicKeyParameters)pubKey;
// TODO Should we have a way to recognize named curves when the name is missing?
ECNamedDomainParameters parameters = (ECNamedDomainParameters)ecK.getParameters();
if (algorithm == PGPPublicKey.ECDH)
{
PGPKdfParameters kdfParams = implGetKdfParameters(algorithmParameters);
return new ECDHPublicBCPGKey(parameters.getName(), ecK.getQ(), kdfParams.getHashAlgorithm(),
kdfParams.getSymmetricWrapAlgorithm());
}
else if (algorithm == PGPPublicKey.ECDSA)
{
return new ECDSAPublicBCPGKey(parameters.getName(), ecK.getQ());
}
else
{
throw new PGPException("unknown EC algorithm");
}
}
else if (pubKey instanceof Ed25519PublicKeyParameters)
{
byte[] pointEnc = new byte[1 + Ed25519PublicKeyParameters.KEY_SIZE];
pointEnc[0] = 0x40;
((Ed25519PublicKeyParameters)pubKey).encode(pointEnc, 1);
return new EdDSAPublicBCPGKey(GNUObjectIdentifiers.Ed25519, new BigInteger(1, pointEnc));
}
else if (pubKey instanceof X25519PublicKeyParameters)
{
byte[] pointEnc = new byte[1 + X25519PublicKeyParameters.KEY_SIZE];
pointEnc[0] = 0x40;
((X25519PublicKeyParameters)pubKey).encode(pointEnc, 1);
PGPKdfParameters kdfParams = implGetKdfParameters(algorithmParameters);
return new ECDHPublicBCPGKey(CryptlibObjectIdentifiers.curvey25519, new BigInteger(1, pointEnc),
kdfParams.getHashAlgorithm(), kdfParams.getSymmetricWrapAlgorithm());
}
else
{
throw new PGPException("unknown key class");
}
}
private PGPKdfParameters implGetKdfParameters(PGPAlgorithmParameters algorithmParameters)
{
return null == algorithmParameters ? DEFAULT_KDF_PARAMETERS : (PGPKdfParameters)algorithmParameters;
}
private ECNamedDomainParameters implGetParametersEC(ECPublicBCPGKey ecPub)
{
ASN1ObjectIdentifier curveOID = ecPub.getCurveOID();
X9ECParameters x9 = BcUtil.getX9Parameters(curveOID);
return new ECNamedDomainParameters(curveOID, x9.getCurve(), x9.getG(), x9.getN(), x9.getH());
}
private AsymmetricKeyParameter implGetPrivateKeyEC(ECPublicBCPGKey ecPub, ECSecretBCPGKey ecPriv)
throws IOException, PGPException
{
ECNamedDomainParameters parameters = implGetParametersEC(ecPub);
return new ECPrivateKeyParameters(ecPriv.getX(), parameters);
}
private AsymmetricKeyParameter implGetPrivateKeyPKCS8(PrivateKeyInfo privateKeyInfo) throws IOException
{
return PrivateKeyFactory.createKey(privateKeyInfo);
}
private AsymmetricKeyParameter implGetPublicKeyEC(ECPublicBCPGKey ecPub) throws IOException, PGPException
{
ECNamedDomainParameters parameters = implGetParametersEC(ecPub);
ECPoint pubPoint = BcUtil.decodePoint(ecPub.getEncodedPoint(), parameters.getCurve());
return new ECPublicKeyParameters(pubPoint, parameters);
}
private AsymmetricKeyParameter implGetPublicKeyX509(SubjectPublicKeyInfo subjectPublicKeyInfo) throws IOException
{
return PublicKeyFactory.createKey(subjectPublicKeyInfo);
}
}