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 APIs for the OpenPGP Protocol. The APIs are designed primarily to be used in conjunction with the BC FIPS provider. The APIs may also be used with other providers although if being used in a FIPS context it is the responsibility of the user to ensure that any other providers used are FIPS certified and used appropriately.

There is a newer version: 2.0.9
Show 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 java.security.interfaces.ECPrivateKey;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.DSAPrivateKeySpec;
import java.security.spec.DSAPublicKeySpec;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPrivateKeySpec;
import java.security.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.crypto.asymmetric.ECDomainParametersIndex;
import org.bouncycastle.crypto.asymmetric.NamedECDomainParameters;
import org.bouncycastle.jcajce.spec.ECDomainParameterSpec;
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. */ @Deprecated 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. */ @Deprecated 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(); } PublicKeyPacket pubPk = privKey.getPublicKeyPacket(); 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", () -> 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", () -> 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", () -> getPrivateKeyInfo(EdECObjectIdentifiers.id_X25519, X25519SecretBCPGKey.LENGTH, privPk.getEncoded())); } // Modern X448 (1.3.101.111) case PublicKeyAlgorithmTags.X448: { return implGeneratePrivate("XDH", () -> 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", () -> 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", () -> 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", () -> getPrivateKeyInfo(EdECObjectIdentifiers.id_Ed25519, Ed25519SecretBCPGKey.LENGTH, privPk.getEncoded())); } // Modern Ed448 (1.3.101.113) case PublicKeyAlgorithmTags.Ed448: { return implGeneratePrivate("EdDSA", () -> 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 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.getS()); } else { // 'reverse' because the native format for X25519,X448 private keys is little-endian return getPrivateBCPGKey(privKey, (pInfoEncoded) -> new ECSecretBCPGKey(new BigInteger(1, Arrays.reverse(pInfoEncoded)))); } } // Modern X25519 (1.3.6.1.4.1.3029.1.5.1 & 1.3.101.110) case PublicKeyAlgorithmTags.X25519: { return getPrivateBCPGKey(privKey, (pInfoEncoded) -> new X25519SecretBCPGKey(pInfoEncoded)); } // Modern X448 (1.3.101.111) case PublicKeyAlgorithmTags.X448: { return getPrivateBCPGKey(privKey, (pInfoEncoded) -> new X448SecretBCPGKey(pInfoEncoded)); } case PublicKeyAlgorithmTags.ECDSA: { return new ECSecretBCPGKey(((ECPrivateKey)privKey).getS()); } // Legacy EdDSA (legacy Ed448, legacy Ed25519) case PublicKeyAlgorithmTags.EDDSA_LEGACY: { return getPrivateBCPGKey(privKey, (pInfoEncoded) -> new EdSecretBCPGKey(new BigInteger(1, pInfoEncoded))); } // Modern Ed25519 (1.3.6.1.4.1.11591.15.1 & 1.3.101.112) case PublicKeyAlgorithmTags.Ed25519: { return getPrivateBCPGKey(privKey, Ed25519SecretBCPGKey::new); } // Modern Ed448 (1.3.101.113) case PublicKeyAlgorithmTags.Ed448: { return getPrivateBCPGKey(privKey, Ed448SecretBCPGKey::new); } 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()); } } NamedECDomainParameters params = ECDomainParametersIndex.lookupDomainParameters(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, Ed25519PublicBCPGKey::new); } // Modern Ed448 (1.3.101.113) case PublicKeyAlgorithmTags.Ed448: { return getPublicBCPGKey(pubKey, Ed448PublicBCPGKey.LENGTH, Ed448PublicBCPGKey::new); } // Modern X25519 (1.3.6.1.4.1.3029.1.5.1 & 1.3.101.110) case PublicKeyAlgorithmTags.X25519: { return getPublicBCPGKey(pubKey, X25519PublicBCPGKey.LENGTH, X25519PublicBCPGKey::new); } // Modern X448 (1.3.101.111) case PublicKeyAlgorithmTags.X448: { return getPublicBCPGKey(pubKey, X448PublicBCPGKey.LENGTH, X448PublicBCPGKey::new); } 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; } @FunctionalInterface 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; } @FunctionalInterface private interface Operation { PrivateKeyInfo getPrivateKeyInfo() throws IOException; } private PrivateKey implGeneratePrivate(String keyAlgorithm, Operation operation) throws GeneralSecurityException, PGPException, IOException { PKCS8EncodedKeySpec pkcs8Spec = new PKCS8EncodedKeySpec(operation.getPrivateKeyInfo().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(); NamedECDomainParameters x9Params = JcaJcePGPUtil.getX9Parameters(curveOID); ECPoint ecPubPoint = JcaJcePGPUtil.decodePoint(ecPub.getEncodedPoint(), x9Params.getCurve()); ECPublicKeySpec ecPubSpec = new ECPublicKeySpec( new java.security.spec.ECPoint( ecPubPoint.getAffineXCoord().toBigInteger(), ecPubPoint.getAffineYCoord().toBigInteger()), new ECDomainParameterSpec(x9Params)); 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