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

org.bouncycastle.cms.KeyAgreeIntRecipientInfoGenerator Maven / Gradle / Ivy

The newest version!
package org.bouncycastle.cms;

import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECParameterSpec;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

import javax.crypto.Cipher;
import javax.crypto.KeyAgreement;
import javax.crypto.SecretKey;

import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.DERObjectIdentifier;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.cms.KeyAgreeRecipientIdentifier;
import org.bouncycastle.asn1.cms.KeyAgreeRecipientInfo;
import org.bouncycastle.asn1.cms.OriginatorIdentifierOrKey;
import org.bouncycastle.asn1.cms.OriginatorPublicKey;
import org.bouncycastle.asn1.cms.RecipientEncryptedKey;
import org.bouncycastle.asn1.cms.RecipientInfo;
import org.bouncycastle.asn1.cms.ecc.MQVuserKeyingMaterial;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.jce.spec.MQVPrivateKeySpec;
import org.bouncycastle.jce.spec.MQVPublicKeySpec;

class KeyAgreeIntRecipientInfoGenerator
    implements IntRecipientInfoGenerator
{
    private DERObjectIdentifier keyAgreementOID;
    private DERObjectIdentifier keyEncryptionOID;
    private ArrayList recipientCerts;
    private KeyPair senderKeyPair;

    KeyAgreeIntRecipientInfoGenerator()
    {
    }

    void setKeyAgreementOID(DERObjectIdentifier keyAgreementOID)
    {
        this.keyAgreementOID = keyAgreementOID;
    }

    void setKeyEncryptionOID(DERObjectIdentifier keyEncryptionOID)
    {
        this.keyEncryptionOID = keyEncryptionOID;
    }

    void setRecipientCerts(Collection recipientCerts)
    {
        this.recipientCerts = new ArrayList(recipientCerts);
    }

    void setSenderKeyPair(KeyPair senderKeyPair)
    {
        this.senderKeyPair = senderKeyPair;
    }

    public RecipientInfo generate(SecretKey contentEncryptionKey, SecureRandom random,
            Provider prov) throws GeneralSecurityException
    {
        PublicKey senderPublicKey = senderKeyPair.getPublic();
        PrivateKey senderPrivateKey = senderKeyPair.getPrivate();


        OriginatorIdentifierOrKey originator;
        try
        {
            originator = new OriginatorIdentifierOrKey(
                createOriginatorPublicKey(senderPublicKey));
        }
        catch (IOException e)
        {
            throw new InvalidKeyException("cannot extract originator public key: " + e);
        }


        ASN1OctetString ukm = null;
        if (keyAgreementOID.getId().equals(CMSEnvelopedGenerator.ECMQV_SHA1KDF))
        {
            try
            {
                ECParameterSpec ecParamSpec = ((ECPublicKey)senderPublicKey).getParams();

                KeyPairGenerator ephemKPG = KeyPairGenerator.getInstance(
                    keyAgreementOID.getId(), prov);
                ephemKPG.initialize(ecParamSpec, random);

                KeyPair ephemKP = ephemKPG.generateKeyPair();

                ukm = new DEROctetString(
                    new MQVuserKeyingMaterial(
                        createOriginatorPublicKey(ephemKP.getPublic()), null));

                senderPrivateKey = new MQVPrivateKeySpec(
                    senderPrivateKey, ephemKP.getPrivate(), ephemKP.getPublic());
            }
            catch (InvalidAlgorithmParameterException e)
            {
                throw new InvalidKeyException(
                    "cannot determine MQV ephemeral key pair parameters from public key: " + e);
            }
            catch (IOException e)
            {
                throw new InvalidKeyException("cannot extract MQV ephemeral public key: " + e);
            }
        }


        ASN1EncodableVector params = new ASN1EncodableVector();
        params.add(keyEncryptionOID);
        params.add(DERNull.INSTANCE);
        AlgorithmIdentifier keyEncAlg = new AlgorithmIdentifier(keyAgreementOID,
            new DERSequence(params));


        ASN1EncodableVector recipientEncryptedKeys = new ASN1EncodableVector();
        Iterator it = recipientCerts.iterator();
        while (it.hasNext())
        {
            X509Certificate recipientCert = (X509Certificate)it.next();

            // TODO Should there be a SubjectKeyIdentifier-based alternative?
            KeyAgreeRecipientIdentifier karid = new KeyAgreeRecipientIdentifier(
                CMSUtils.getIssuerAndSerialNumber(recipientCert));

            PublicKey recipientPublicKey = recipientCert.getPublicKey();

            if (keyAgreementOID.getId().equals(CMSEnvelopedGenerator.ECMQV_SHA1KDF))
            {
                recipientPublicKey = new MQVPublicKeySpec(recipientPublicKey, recipientPublicKey);
            }

            // Use key agreement to choose a wrap key for this recipient
            KeyAgreement keyAgreement = KeyAgreement.getInstance(keyAgreementOID.getId(), prov);
            keyAgreement.init(senderPrivateKey, random);
            keyAgreement.doPhase(recipientPublicKey, true);
            SecretKey keyEncryptionKey = keyAgreement.generateSecret(keyEncryptionOID.getId());

            // Wrap the content encryption key with the agreement key
            Cipher keyEncryptionCipher = CMSEnvelopedHelper.INSTANCE.createSymmetricCipher(
                keyEncryptionOID.getId(), prov);
            keyEncryptionCipher.init(Cipher.WRAP_MODE, keyEncryptionKey, random);
            byte[] encryptedKeyBytes = keyEncryptionCipher.wrap(contentEncryptionKey);

            ASN1OctetString encryptedKey = new DEROctetString(encryptedKeyBytes);

            recipientEncryptedKeys.add(new RecipientEncryptedKey(karid, encryptedKey));
        }

        return new RecipientInfo(new KeyAgreeRecipientInfo(originator, ukm,
                keyEncAlg, new DERSequence(recipientEncryptedKeys)));
    }

    // TODO Make this a public helper?
    private static OriginatorPublicKey createOriginatorPublicKey(PublicKey publicKey)
        throws IOException
    {
        SubjectPublicKeyInfo spki = SubjectPublicKeyInfo.getInstance(
            ASN1Object.fromByteArray(publicKey.getEncoded()));
        return new OriginatorPublicKey(
            new AlgorithmIdentifier(spki.getAlgorithmId().getObjectId(), DERNull.INSTANCE),
            spki.getPublicKeyData().getBytes());
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy