All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyConverter Maven / Gradle / Ivy

Go to download

The Bouncy Castle Java API for handling the OpenPGP protocol. This jar contains the OpenPGP API for JDK 1.4. The APIs can be used in conjunction with a JCE/JCA provider such as the one provided with the Bouncy Castle Cryptography APIs.

The newest version!
package org.bouncycastle.openpgp.operator.jcajce;

import java.io.IOException;
import java.math.BigInteger;
import java.security.AlgorithmParameters;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.interfaces.DSAParams;
import java.security.interfaces.DSAPrivateKey;
import java.security.interfaces.DSAPublicKey;
import org.bouncycastle.jce.interfaces.ECPrivateKey;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.DSAPrivateKeySpec;
import java.security.spec.DSAPublicKeySpec;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.jce.spec.ECPrivateKeySpec;
import org.bouncycastle.jce.spec.ECPublicKeySpec;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPrivateCrtKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Date;
import java.util.Enumeration;

import javax.crypto.interfaces.DHPrivateKey;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DHParameterSpec;
import javax.crypto.spec.DHPrivateKeySpec;
import javax.crypto.spec.DHPublicKeySpec;

import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1OctetString;
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.ECNamedCurveTable;
import org.bouncycastle.asn1.x9.X962Parameters;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.asn1.x9.X9ECParametersHolder;
import org.bouncycastle.asn1.x9.X9ECPoint;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
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.Ed25519PublicBCPGKey;
import org.bouncycastle.bcpg.Ed25519SecretBCPGKey;
import org.bouncycastle.bcpg.Ed448PublicBCPGKey;
import org.bouncycastle.bcpg.Ed448SecretBCPGKey;
import org.bouncycastle.bcpg.EdDSAPublicBCPGKey;
import org.bouncycastle.bcpg.EdSecretBCPGKey;
import org.bouncycastle.bcpg.ElGamalPublicBCPGKey;
import org.bouncycastle.bcpg.ElGamalSecretBCPGKey;
import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyPacket;
import org.bouncycastle.bcpg.RSAPublicBCPGKey;
import org.bouncycastle.bcpg.RSASecretBCPGKey;
import org.bouncycastle.bcpg.X25519PublicBCPGKey;
import org.bouncycastle.bcpg.X25519SecretBCPGKey;
import org.bouncycastle.bcpg.X448PublicBCPGKey;
import org.bouncycastle.bcpg.X448SecretBCPGKey;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
import org.bouncycastle.jcajce.util.DefaultJcaJceHelper;
import org.bouncycastle.jcajce.util.NamedJcaJceHelper;
import org.bouncycastle.jcajce.util.ProviderJcaJceHelper;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.math.ec.rfc7748.X25519;
import org.bouncycastle.math.ec.rfc7748.X448;
import org.bouncycastle.math.ec.rfc8032.Ed25519;
import org.bouncycastle.math.ec.rfc8032.Ed448;
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.openpgp.operator.KeyFingerPrintCalculator;
import org.bouncycastle.openpgp.operator.PGPKeyConverter;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.BigIntegers;

public class JcaPGPKeyConverter
    extends PGPKeyConverter
{
    private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper());
    private KeyFingerPrintCalculator fingerPrintCalculator = new JcaKeyFingerprintCalculator();

    public JcaPGPKeyConverter setProvider(Provider provider)
    {
        this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider));

        return this;
    }

    public JcaPGPKeyConverter setProvider(String providerName)
    {
        this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName));

        return this;
    }

    /**
     * Convert a PrivateKey into a PGPPrivateKey.
     *
     * @param pub     the corresponding PGPPublicKey to privKey.
     * @param privKey the private key for the key in pub.
     * @return a PGPPrivateKey
     * @throws PGPException
     */
    public PGPPrivateKey getPGPPrivateKey(PGPPublicKey pub, PrivateKey privKey)
        throws PGPException
    {
        BCPGKey privPk = getPrivateBCPGKey(pub, privKey);

        return new PGPPrivateKey(pub.getKeyID(), pub.getPublicKeyPacket(), privPk);
    }

    /**
     * Create a version 4 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 algorithmParameters additional parameters to be stored against the public key. * @param pubKey actual public key to associate. * @param time date of creation. * @throws PGPException on key creation problem. * @deprecated use versioned {@link #getPGPPublicKey(int, int, PGPAlgorithmParameters, PublicKey, Date)} instead. */ public PGPPublicKey getPGPPublicKey(int algorithm, PGPAlgorithmParameters algorithmParameters, PublicKey pubKey, Date time) throws PGPException { return getPGPPublicKey(PublicKeyPacket.VERSION_4, algorithm, algorithmParameters, pubKey, time); } /** * 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 version key version. * @param algorithm asymmetric algorithm type representing the public key. * @param algorithmParameters additional parameters to be stored against 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 version, int algorithm, PGPAlgorithmParameters algorithmParameters, PublicKey pubKey, Date time) throws PGPException { BCPGKey bcpgKey = getPublicBCPGKey(algorithm, algorithmParameters, pubKey); return new PGPPublicKey(new PublicKeyPacket(version, algorithm, time, bcpgKey), fingerPrintCalculator); } /** * Create a version 4 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. * @deprecated use versioned {@link #getPGPPublicKey(int, int, PublicKey, Date)} instead. */ public PGPPublicKey getPGPPublicKey(int algorithm, PublicKey pubKey, Date time) throws PGPException { return getPGPPublicKey(algorithm, null, pubKey, time); } /** * 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 version key version. * @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 version, int algorithm, PublicKey pubKey, Date time) throws PGPException { return getPGPPublicKey(version, algorithm, null, pubKey, time); } public PrivateKey getPrivateKey(PGPPrivateKey privKey) throws PGPException { if (privKey instanceof JcaPGPPrivateKey) { return ((JcaPGPPrivateKey)privKey).getPrivateKey(); } final PublicKeyPacket pubPk = privKey.getPublicKeyPacket(); final BCPGKey privPk = privKey.getPrivateKeyDataPacket(); try { switch (pubPk.getAlgorithm()) { case PublicKeyAlgorithmTags.DSA: { DSAPublicBCPGKey dsaPub = (DSAPublicBCPGKey)pubPk.getKey(); DSASecretBCPGKey dsaPriv = (DSASecretBCPGKey)privPk; DSAPrivateKeySpec dsaPrivSpec = new DSAPrivateKeySpec(dsaPriv.getX(), dsaPub.getP(), dsaPub.getQ(), dsaPub.getG()); return implGeneratePrivate("DSA", dsaPrivSpec); } case PublicKeyAlgorithmTags.ECDH: { ECDHPublicBCPGKey ecdhPub = (ECDHPublicBCPGKey)pubPk.getKey(); ECSecretBCPGKey ecdhK = (ECSecretBCPGKey)privPk; // Legacy XDH on Curve25519 (legacy X25519) // 1.3.6.1.4.1.3029.1.5.1 & 1.3.101.110 if (JcaJcePGPUtil.isX25519(ecdhPub.getCurveOID())) { // 'reverse' because the native format for X25519 private keys is little-endian return implGeneratePrivate("XDH", new Operation() { public PrivateKeyInfo getPrivateKeyInfos() throws IOException { return getPrivateKeyInfo(EdECObjectIdentifiers.id_X25519, Arrays.reverseInPlace(BigIntegers.asUnsignedByteArray(((ECSecretBCPGKey)privPk).getX()))); } }); } // Legacy X448 (1.3.101.111) else if (EdECObjectIdentifiers.id_X448.equals(ecdhPub.getCurveOID())) { // 'reverse' because the native format for X448 private keys is little-endian (?) return implGeneratePrivate("XDH", new Operation() { public PrivateKeyInfo getPrivateKeyInfos() throws IOException { return getPrivateKeyInfo(EdECObjectIdentifiers.id_X448, Arrays.reverseInPlace(BigIntegers.asUnsignedByteArray(((ECSecretBCPGKey)privPk).getX()))); } }); } // Brainpool, NIST etc. else { return implGetPrivateKeyEC("ECDH", ecdhPub, ecdhK); } } // Modern X25519 (1.3.6.1.4.1.3029.1.5.1 & 1.3.101.110) case PublicKeyAlgorithmTags.X25519: { return implGeneratePrivate("XDH", new Operation() { public PrivateKeyInfo getPrivateKeyInfos() throws IOException { return getPrivateKeyInfo(EdECObjectIdentifiers.id_X25519, X25519SecretBCPGKey.LENGTH, privPk.getEncoded()); } }); } // Modern X448 (1.3.101.111) case PublicKeyAlgorithmTags.X448: { return implGeneratePrivate("XDH", new Operation() { public PrivateKeyInfo getPrivateKeyInfos() throws IOException { return getPrivateKeyInfo(EdECObjectIdentifiers.id_X448, X448SecretBCPGKey.LENGTH, privPk.getEncoded()); } }); } case PublicKeyAlgorithmTags.ECDSA: { return implGetPrivateKeyEC("EC", (ECDSAPublicBCPGKey)pubPk.getKey(), (ECSecretBCPGKey)privPk); } // Legacy EdDSA (legacy Ed448, legacy Ed25519) case PublicKeyAlgorithmTags.EDDSA_LEGACY: { EdDSAPublicBCPGKey eddsaPub = (EdDSAPublicBCPGKey) pubPk.getKey(); // Legacy Ed448 (1.3.101.113) if (EdECObjectIdentifiers.id_Ed448.equals(eddsaPub.getCurveOID())) { return implGeneratePrivate("EdDSA", new Operation() { public PrivateKeyInfo getPrivateKeyInfos() throws IOException { return getPrivateKeyInfo(EdECObjectIdentifiers.id_Ed448, BigIntegers.asUnsignedByteArray(Ed448.SECRET_KEY_SIZE, ((EdSecretBCPGKey)privPk).getX())); } }); } // Legacy Ed25519 // 1.3.6.1.4.1.11591.15.1 & 1.3.101.112 return implGeneratePrivate("EdDSA", new Operation() { public PrivateKeyInfo getPrivateKeyInfos() throws IOException { return getPrivateKeyInfo(EdECObjectIdentifiers.id_Ed25519, BigIntegers.asUnsignedByteArray(Ed25519.SECRET_KEY_SIZE, ((EdSecretBCPGKey)privPk).getX())); } }); } // Modern Ed25519 (1.3.6.1.4.1.11591.15.1 & 1.3.101.112) case PublicKeyAlgorithmTags.Ed25519: { return implGeneratePrivate("EdDSA", new Operation() { public PrivateKeyInfo getPrivateKeyInfos() throws IOException { return getPrivateKeyInfo(EdECObjectIdentifiers.id_Ed25519, Ed25519SecretBCPGKey.LENGTH, privPk.getEncoded()); } }); } // Modern Ed448 (1.3.101.113) case PublicKeyAlgorithmTags.Ed448: { return implGeneratePrivate("EdDSA", new Operation() { public PrivateKeyInfo getPrivateKeyInfos() throws IOException { return getPrivateKeyInfo(EdECObjectIdentifiers.id_Ed448, Ed448SecretBCPGKey.LENGTH, privPk.getEncoded()); } }); } case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT: case PublicKeyAlgorithmTags.ELGAMAL_GENERAL: { ElGamalPublicBCPGKey elPub = (ElGamalPublicBCPGKey)pubPk.getKey(); ElGamalSecretBCPGKey elPriv = (ElGamalSecretBCPGKey)privPk; DHPrivateKeySpec elSpec = new DHPrivateKeySpec(elPriv.getX(), elPub.getP(), elPub.getG()); return implGeneratePrivate("ElGamal", elSpec); } case PublicKeyAlgorithmTags.RSA_ENCRYPT: case PublicKeyAlgorithmTags.RSA_GENERAL: case PublicKeyAlgorithmTags.RSA_SIGN: { RSAPublicBCPGKey rsaPub = (RSAPublicBCPGKey)pubPk.getKey(); RSASecretBCPGKey rsaPriv = (RSASecretBCPGKey)privPk; RSAPrivateCrtKeySpec rsaPrivSpec = new RSAPrivateCrtKeySpec(rsaPriv.getModulus(), rsaPub.getPublicExponent(), rsaPriv.getPrivateExponent(), rsaPriv.getPrimeP(), rsaPriv.getPrimeQ(), rsaPriv.getPrimeExponentP(), rsaPriv.getPrimeExponentQ(), rsaPriv.getCrtCoefficient()); return implGeneratePrivate("RSA", rsaPrivSpec); } default: throw new PGPException("unknown public key algorithm encountered: " + pubPk.getAlgorithm()); } } catch (PGPException e) { throw e; } catch (Exception e) { throw new PGPException("Exception constructing key", e); } } public PublicKey getPublicKey(PGPPublicKey publicKey) throws PGPException { PublicKeyPacket publicPk = publicKey.getPublicKeyPacket(); try { switch (publicPk.getAlgorithm()) { case PublicKeyAlgorithmTags.DSA: { DSAPublicBCPGKey dsaK = (DSAPublicBCPGKey)publicPk.getKey(); DSAPublicKeySpec dsaSpec = new DSAPublicKeySpec(dsaK.getY(), dsaK.getP(), dsaK.getQ(), dsaK.getG()); return implGeneratePublic("DSA", dsaSpec); } case PublicKeyAlgorithmTags.ECDH: { ECDHPublicBCPGKey ecdhK = (ECDHPublicBCPGKey)publicPk.getKey(); // Legacy XDH on Curve25519 (legacy X25519) // 1.3.6.1.4.1.3029.1.5.1 & 1.3.101.110 if (JcaJcePGPUtil.isX25519(ecdhK.getCurveOID())) { return get25519PublicKey(ecdhK.getEncodedPoint(), EdECObjectIdentifiers.id_X25519, "XDH", "Curve"); } // Legacy X448 (1.3.101.111) else if (ecdhK.getCurveOID().equals(EdECObjectIdentifiers.id_X448)) { return get448PublicKey(ecdhK.getEncodedPoint(), EdECObjectIdentifiers.id_X448, "XDH", "Curve"); } // Brainpool, NIST etc. else { return implGetPublicKeyEC("ECDH", ecdhK); } } // Modern X25519 (1.3.6.1.4.1.3029.1.5.1 & 1.3.101.110) case PublicKeyAlgorithmTags.X25519: { return implGetPublicKeyX509(publicPk.getKey().getEncoded(), 0, EdECObjectIdentifiers.id_X25519, "XDH"); } // Modern X448 (1.3.101.111) case PublicKeyAlgorithmTags.X448: { return implGetPublicKeyX509(publicPk.getKey().getEncoded(), 0, EdECObjectIdentifiers.id_X448, "XDH"); } case PublicKeyAlgorithmTags.ECDSA: { return implGetPublicKeyEC("EC", (ECDSAPublicBCPGKey) publicPk.getKey()); } // Legacy EdDSA (legacy Ed448, legacy Ed25519) case PublicKeyAlgorithmTags.EDDSA_LEGACY: { EdDSAPublicBCPGKey eddsaKey = (EdDSAPublicBCPGKey) publicPk.getKey(); // Legacy Ed448 (1.3.101.113) if (EdECObjectIdentifiers.id_Ed448.equals(eddsaKey.getCurveOID())) { return get448PublicKey(eddsaKey.getEncodedPoint(), EdECObjectIdentifiers.id_Ed448, "EdDSA", "Ed"); } // Legacy Ed25519 // 1.3.6.1.4.1.11591.15.1 & 1.3.101.112 else { return get25519PublicKey(eddsaKey.getEncodedPoint(), EdECObjectIdentifiers.id_Ed25519, "EdDSA", "Ed"); } } // Modern Ed25519 (1.3.6.1.4.1.11591.15.1 & 1.3.101.112) case PublicKeyAlgorithmTags.Ed25519: { return implGetPublicKeyX509(publicPk.getKey().getEncoded(), 0, EdECObjectIdentifiers.id_Ed25519, "EdDSA"); } // Modern Ed448 (1.3.101.113) case PublicKeyAlgorithmTags.Ed448: { return implGetPublicKeyX509(publicPk.getKey().getEncoded(), 0, EdECObjectIdentifiers.id_Ed448, "EdDSA"); } case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT: case PublicKeyAlgorithmTags.ELGAMAL_GENERAL: { ElGamalPublicBCPGKey elK = (ElGamalPublicBCPGKey)publicPk.getKey(); DHPublicKeySpec elSpec = new DHPublicKeySpec(elK.getY(), elK.getP(), elK.getG()); return implGeneratePublic("ElGamal", elSpec); } case PublicKeyAlgorithmTags.RSA_ENCRYPT: case PublicKeyAlgorithmTags.RSA_GENERAL: case PublicKeyAlgorithmTags.RSA_SIGN: { RSAPublicBCPGKey rsaK = (RSAPublicBCPGKey)publicPk.getKey(); RSAPublicKeySpec rsaSpec = new RSAPublicKeySpec(rsaK.getModulus(), rsaK.getPublicExponent()); return implGeneratePublic("RSA", rsaSpec); } default: throw new PGPException("unknown public key algorithm encountered: " + publicPk.getAlgorithm()); } } catch (PGPException e) { throw e; } catch (Exception e) { throw new PGPException("exception constructing public key", e); } } private ECParameterSpec getECParameterSpec(ASN1ObjectIdentifier curveOid) throws IOException, GeneralSecurityException { AlgorithmParameters params = helper.createAlgorithmParameters("EC"); params.init(new X962Parameters(curveOid).getEncoded()); return (org.bouncycastle.jce.spec.ECParameterSpec)params.getParameterSpec(ECParameterSpec.class); } private BCPGKey getPrivateBCPGKey(PrivateKey privKey, BCPGKeyOperation operation) throws PGPException { PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(privKey.getEncoded()); try { return operation.getBCPGKey(ASN1OctetString.getInstance(pInfo.parsePrivateKey()).getOctets()); } catch (IOException e) { throw new PGPException(e.getMessage(), e); } } private BCPGKey getPrivateBCPGKey(PGPPublicKey pub, PrivateKey privKey) throws PGPException { switch (pub.getAlgorithm()) { case PublicKeyAlgorithmTags.DSA: { DSAPrivateKey dsK = (DSAPrivateKey)privKey; return new DSASecretBCPGKey(dsK.getX()); } case PublicKeyAlgorithmTags.ECDH: { if (privKey instanceof ECPrivateKey) { ECPrivateKey ecK = (ECPrivateKey)privKey; return new ECSecretBCPGKey(ecK.getD()); } else { // 'reverse' because the native format for X25519,X448 private keys is little-endian return getPrivateBCPGKey(privKey, new BCPGKeyOperation() { public BCPGKey getBCPGKey(byte[] key) { return new ECSecretBCPGKey(new BigInteger(1, Arrays.reverse(key))); } }); } } // Modern X25519 (1.3.6.1.4.1.3029.1.5.1 & 1.3.101.110) case PublicKeyAlgorithmTags.X25519: { return getPrivateBCPGKey(privKey, new BCPGKeyOperation() { public BCPGKey getBCPGKey(byte[] key) { return new X25519SecretBCPGKey(key); } }); } // Modern X448 (1.3.101.111) case PublicKeyAlgorithmTags.X448: { return getPrivateBCPGKey(privKey, new BCPGKeyOperation() { public BCPGKey getBCPGKey(byte[] key) { return new X448SecretBCPGKey(key); } }); } case PublicKeyAlgorithmTags.ECDSA: { return new ECSecretBCPGKey(((ECPrivateKey)privKey).getD()); } // Legacy EdDSA (legacy Ed448, legacy Ed25519) case PublicKeyAlgorithmTags.EDDSA_LEGACY: { return getPrivateBCPGKey(privKey, new BCPGKeyOperation() { public BCPGKey getBCPGKey(byte[] key) { return new EdSecretBCPGKey(new BigInteger(1, key)); } }); } // Modern Ed25519 (1.3.6.1.4.1.11591.15.1 & 1.3.101.112) case PublicKeyAlgorithmTags.Ed25519: { return getPrivateBCPGKey(privKey, new BCPGKeyOperation() { public BCPGKey getBCPGKey(byte[] key) { return new Ed25519SecretBCPGKey(key); } }); } // Modern Ed448 (1.3.101.113) case PublicKeyAlgorithmTags.Ed448: { return getPrivateBCPGKey(privKey, new BCPGKeyOperation() { public BCPGKey getBCPGKey(byte[] key) { return new Ed448SecretBCPGKey(key); } }); } case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT: case PublicKeyAlgorithmTags.ELGAMAL_GENERAL: { DHPrivateKey esK = (DHPrivateKey)privKey; return new ElGamalSecretBCPGKey(esK.getX()); } case PublicKeyAlgorithmTags.RSA_ENCRYPT: case PublicKeyAlgorithmTags.RSA_GENERAL: case PublicKeyAlgorithmTags.RSA_SIGN: { RSAPrivateCrtKey rsK = (RSAPrivateCrtKey)privKey; return new RSASecretBCPGKey(rsK.getPrivateExponent(), rsK.getPrimeP(), rsK.getPrimeQ()); } default: throw new PGPException("unknown public key algorithm encountered: " + pub.getAlgorithm()); } } private BCPGKey getPublicBCPGKey(int algorithm, PGPAlgorithmParameters algorithmParameters, PublicKey pubKey) throws PGPException { switch (algorithm) { case PublicKeyAlgorithmTags.RSA_GENERAL: case PublicKeyAlgorithmTags.RSA_ENCRYPT: case PublicKeyAlgorithmTags.RSA_SIGN: { RSAPublicKey rK = (RSAPublicKey) pubKey; return new RSAPublicBCPGKey(rK.getModulus(), rK.getPublicExponent()); } case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT: case PublicKeyAlgorithmTags.ELGAMAL_GENERAL: { DHPublicKey egK = (DHPublicKey) pubKey; return new ElGamalPublicBCPGKey(egK.getParams().getP(), egK.getParams().getG(), egK.getY()); } case PublicKeyAlgorithmTags.DSA: { DSAPublicKey dK = (DSAPublicKey) pubKey; DSAParams dP = dK.getParams(); return new DSAPublicBCPGKey(dP.getP(), dP.getQ(), dP.getG(), dK.getY()); } case PublicKeyAlgorithmTags.DIFFIE_HELLMAN: { DHPublicKey eK = (DHPublicKey) pubKey; DHParameterSpec eS = eK.getParams(); return new ElGamalPublicBCPGKey(eS.getP(), eS.getG(), eK.getY()); } case PublicKeyAlgorithmTags.ECDH: case PublicKeyAlgorithmTags.ECDSA: { SubjectPublicKeyInfo keyInfo = SubjectPublicKeyInfo.getInstance(pubKey.getEncoded()); // TODO: should probably match curve by comparison as well ASN1Encodable enc = keyInfo.getAlgorithm().getAlgorithm(); ASN1ObjectIdentifier curveOid; curveOid = ASN1ObjectIdentifier.getInstance(enc); // BCECPublicKey uses explicit parameter encoding, so we need to find the named curve manually if (X9ObjectIdentifiers.id_ecPublicKey.equals(curveOid)) { enc = getNamedCurveOID(X962Parameters.getInstance(keyInfo.getAlgorithm().getParameters())); ASN1ObjectIdentifier nCurveOid = ASN1ObjectIdentifier.getInstance(enc); if (nCurveOid != null) { curveOid = nCurveOid; } } // Legacy XDH on Curve25519 (legacy X25519) // 1.3.6.1.4.1.3029.1.5.1 & 1.3.101.110 if (pubKey.getAlgorithm().regionMatches(true, 0, "X2", 0, 2)) { PGPKdfParameters kdfParams = implGetKdfParameters(CryptlibObjectIdentifiers.curvey25519, algorithmParameters); return new ECDHPublicBCPGKey(CryptlibObjectIdentifiers.curvey25519, new BigInteger(1, getPointEncUncompressed(pubKey, X25519.SCALAR_SIZE)), kdfParams.getHashAlgorithm(), kdfParams.getSymmetricWrapAlgorithm()); } // Legacy X448 (1.3.101.111) if (pubKey.getAlgorithm().regionMatches(true, 0, "X4", 0, 2)) { PGPKdfParameters kdfParams = implGetKdfParameters(EdECObjectIdentifiers.id_X448, algorithmParameters); return new ECDHPublicBCPGKey(EdECObjectIdentifiers.id_X448, new BigInteger(1, getPointEncUncompressed(pubKey, X448.SCALAR_SIZE)), kdfParams.getHashAlgorithm(), kdfParams.getSymmetricWrapAlgorithm()); } // sun.security.ec.XDHPublicKeyImpl returns "XDH" for getAlgorithm() // In this case we need to determine the curve by looking at the length of the encoding :/ else if (pubKey.getAlgorithm().regionMatches(true, 0, "XDH", 0, 3)) { // Legacy X25519 (1.3.6.1.4.1.3029.1.5.1 & 1.3.101.110) if (X25519.SCALAR_SIZE + 12 == pubKey.getEncoded().length) // + 12 for some reason { PGPKdfParameters kdfParams = implGetKdfParameters(CryptlibObjectIdentifiers.curvey25519, algorithmParameters); return new ECDHPublicBCPGKey(CryptlibObjectIdentifiers.curvey25519, new BigInteger(1, getPointEncUncompressed(pubKey, X25519.SCALAR_SIZE)), kdfParams.getHashAlgorithm(), kdfParams.getSymmetricWrapAlgorithm()); } // Legacy X448 (1.3.101.111) else { PGPKdfParameters kdfParams = implGetKdfParameters(EdECObjectIdentifiers.id_X448, algorithmParameters); return new ECDHPublicBCPGKey(EdECObjectIdentifiers.id_X448, new BigInteger(1, getPointEncUncompressed(pubKey, X448.SCALAR_SIZE)), kdfParams.getHashAlgorithm(), kdfParams.getSymmetricWrapAlgorithm()); } } X9ECParametersHolder params = ECNamedCurveTable.getByOIDLazy(curveOid); ASN1OctetString key = new DEROctetString(keyInfo.getPublicKeyData().getBytes()); X9ECPoint derQ = new X9ECPoint(params.getCurve(), key); if (algorithm == PGPPublicKey.ECDH) { PGPKdfParameters kdfParams = implGetKdfParameters(curveOid, algorithmParameters); return new ECDHPublicBCPGKey(curveOid, derQ.getPoint(), kdfParams.getHashAlgorithm(), kdfParams.getSymmetricWrapAlgorithm()); } else { return new ECDSAPublicBCPGKey(curveOid, derQ.getPoint()); } } case PublicKeyAlgorithmTags.EDDSA_LEGACY: { // Legacy Ed25519 (1.3.6.1.4.1.11591.15.1 & 1.3.101.112) if (pubKey.getAlgorithm().regionMatches(true, 0, "ED2", 0, 3)) { return new EdDSAPublicBCPGKey(GNUObjectIdentifiers.Ed25519, new BigInteger(1, getPointEncUncompressed(pubKey, Ed25519.PUBLIC_KEY_SIZE))); } // Legacy Ed448 (1.3.101.113) if (pubKey.getAlgorithm().regionMatches(true, 0, "ED4", 0, 3)) { return new EdDSAPublicBCPGKey(EdECObjectIdentifiers.id_Ed448, new BigInteger(1, getPointEncUncompressed(pubKey, Ed448.PUBLIC_KEY_SIZE))); } // Manual matching on curve encoding length else { // sun.security.ec.ed.EdDSAPublicKeyImpl returns "EdDSA" for getAlgorithm() // if algorithm is just EdDSA, we need to detect the curve based on encoding length :/ if (pubKey.getEncoded().length == 12 + Ed25519.PUBLIC_KEY_SIZE) // +12 for some reason { // Legacy Ed25519 (1.3.6.1.4.1.11591.15.1 & 1.3.101.112) return new EdDSAPublicBCPGKey(GNUObjectIdentifiers.Ed25519, new BigInteger(1, getPointEncUncompressed(pubKey, Ed25519.PUBLIC_KEY_SIZE))); } else { // Legacy Ed448 (1.3.101.113) return new EdDSAPublicBCPGKey(EdECObjectIdentifiers.id_Ed448, new BigInteger(1, getPointEncUncompressed(pubKey, Ed448.PUBLIC_KEY_SIZE))); } } } // Modern Ed25519 (1.3.6.1.4.1.11591.15.1 & 1.3.101.112) case PublicKeyAlgorithmTags.Ed25519: { return getPublicBCPGKey(pubKey, Ed25519PublicBCPGKey.LENGTH, new BCPGKeyOperation() { public BCPGKey getBCPGKey(byte[] key) { return new Ed25519PublicBCPGKey(key); } }); } // Modern Ed448 (1.3.101.113) case PublicKeyAlgorithmTags.Ed448: { return getPublicBCPGKey(pubKey, Ed448PublicBCPGKey.LENGTH, new BCPGKeyOperation() { public BCPGKey getBCPGKey(byte[] key) { return new Ed448PublicBCPGKey(key); } }); } // Modern X25519 (1.3.6.1.4.1.3029.1.5.1 & 1.3.101.110) case PublicKeyAlgorithmTags.X25519: { return getPublicBCPGKey(pubKey, X25519PublicBCPGKey.LENGTH, new BCPGKeyOperation() { public BCPGKey getBCPGKey(byte[] key) { return new X25519PublicBCPGKey(key); } }); } // Modern X448 (1.3.101.111) case PublicKeyAlgorithmTags.X448: { return getPublicBCPGKey(pubKey, X448PublicBCPGKey.LENGTH, new BCPGKeyOperation() { public BCPGKey getBCPGKey(byte[] key) { return new X448PublicBCPGKey(key); } }); } default: throw new PGPException("unknown public key algorithm encountered: " + algorithm); } } private ASN1Encodable getNamedCurveOID(X962Parameters ecParams) { ECCurve curve = null; if (ecParams.isNamedCurve()) { return ASN1ObjectIdentifier.getInstance(ecParams.getParameters()); } else if (ecParams.isImplicitlyCA()) { curve = ((X9ECParameters)CryptoServicesRegistrar.getProperty(CryptoServicesRegistrar.Property.EC_IMPLICITLY_CA)).getCurve(); } else { curve = X9ECParameters.getInstance(ecParams.getParameters()).getCurve(); } // Iterate through all registered curves to find applicable OID Enumeration names = ECNamedCurveTable.getNames(); while (names.hasMoreElements()) { String name = (String)names.nextElement(); X9ECParameters parms = ECNamedCurveTable.getByName(name); if (curve.equals(parms.getCurve())) { return ECNamedCurveTable.getOID(name); } } return null; } private interface BCPGKeyOperation { BCPGKey getBCPGKey(byte[] key); } private BCPGKey getPublicBCPGKey(PublicKey pubKey, int keySize, BCPGKeyOperation operation) { byte[] pubInfo = SubjectPublicKeyInfo.getInstance(pubKey.getEncoded()).getPublicKeyData().getBytes(); byte[] pointEnc = new byte[keySize]; // refer to getPointEncUncompressed System.arraycopy(pubInfo, 0, pointEnc, pointEnc.length - pubInfo.length , pubInfo.length); return operation.getBCPGKey(pointEnc); } private byte[] getPointEncUncompressed(PublicKey pubKey, int publicKeySize) { byte[] pubInfo = SubjectPublicKeyInfo.getInstance(pubKey.getEncoded()).getPublicKeyData().getBytes(); byte[] pointEnc = new byte[1 + publicKeySize]; pointEnc[0] = 0x40; //offset with pointEnc.length - pubInfo.length to avoid leading zero issue System.arraycopy(pubInfo, 0, pointEnc, pointEnc.length - pubInfo.length , pubInfo.length); return pointEnc; } private interface Operation { PrivateKeyInfo getPrivateKeyInfos() throws IOException; } private PrivateKey implGeneratePrivate(String keyAlgorithm, Operation operation) throws GeneralSecurityException, PGPException, IOException { PKCS8EncodedKeySpec pkcs8Spec = new PKCS8EncodedKeySpec(operation.getPrivateKeyInfos().getEncoded()); KeyFactory keyFactory = helper.createKeyFactory(keyAlgorithm); return keyFactory.generatePrivate(pkcs8Spec); } private PrivateKey implGeneratePrivate(String keyAlgorithm, KeySpec keySpec) throws GeneralSecurityException, PGPException { KeyFactory keyFactory = helper.createKeyFactory(keyAlgorithm); return keyFactory.generatePrivate(keySpec); } private PublicKey implGeneratePublic(String keyAlgorithm, KeySpec keySpec) throws GeneralSecurityException, PGPException { KeyFactory keyFactory = helper.createKeyFactory(keyAlgorithm); return keyFactory.generatePublic(keySpec); } private PublicKey implGetPublicKeyX509(byte[] pEnc, int pEncOff, ASN1ObjectIdentifier algorithm, String keyAlgorithm) throws IOException, PGPException, GeneralSecurityException { return implGeneratePublic(keyAlgorithm, new X509EncodedKeySpec(new SubjectPublicKeyInfo( new AlgorithmIdentifier(algorithm), Arrays.copyOfRange(pEnc, pEncOff, pEnc.length)).getEncoded())); } private PrivateKey implGetPrivateKeyEC(String keyAlgorithm, ECPublicBCPGKey ecPub, ECSecretBCPGKey ecPriv) throws GeneralSecurityException, PGPException, IOException { ASN1ObjectIdentifier curveOid = ecPub.getCurveOID(); ECPrivateKeySpec ecPrivSpec = new ECPrivateKeySpec(ecPriv.getX(), getECParameterSpec(curveOid)); return implGeneratePrivate(keyAlgorithm, ecPrivSpec); } private PublicKey implGetPublicKeyEC(String keyAlgorithm, ECPublicBCPGKey ecPub) throws GeneralSecurityException, IOException, PGPException { ASN1ObjectIdentifier curveOID = ecPub.getCurveOID(); X9ECParameters x9Params = JcaJcePGPUtil.getX9Parameters(curveOID); ECPoint ecPubPoint = JcaJcePGPUtil.decodePoint(ecPub.getEncodedPoint(), x9Params.getCurve()); ECPublicKeySpec ecPubSpec = new ECPublicKeySpec( x9Params.getCurve().createPoint( ecPubPoint.getAffineXCoord().toBigInteger(), ecPubPoint.getAffineYCoord().toBigInteger()), getECParameterSpec(curveOID)); return implGeneratePublic(keyAlgorithm, ecPubSpec); } private PublicKey get25519PublicKey(BigInteger x, ASN1ObjectIdentifier algorithm, String keyAlgorithm, String name) throws PGPException, GeneralSecurityException, IOException { byte[] pEnc = BigIntegers.asUnsignedByteArray(x); // skip the 0x40 header byte. if (pEnc.length < 1 || 0x40 != pEnc[0]) { throw new IllegalArgumentException("Invalid " + name + "25519 public key"); } return implGetPublicKeyX509(pEnc, 1, algorithm, keyAlgorithm); } private PublicKey get448PublicKey(BigInteger x, ASN1ObjectIdentifier algorithm, String keyAlgorithm, String name) throws PGPException, GeneralSecurityException, IOException { byte[] pEnc = BigIntegers.asUnsignedByteArray(x); // skip the 0x40 header byte. if (pEnc.length < 1 || 0x40 != pEnc[0]) { throw new IllegalArgumentException("Invalid " + name + "448 public key"); } return implGetPublicKeyX509(pEnc, 1, algorithm, keyAlgorithm); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy