Package org.jscep.message

Source Code of org.jscep.message.PkcsPkiEnvelopeDecoder

package org.jscep.message;

import static org.slf4j.LoggerFactory.getLogger;

import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.spec.IvParameterSpec;

import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.cms.EnvelopedData;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.cms.CMSEnvelopedData;
import org.bouncycastle.cms.CMSException;
import org.bouncycastle.cms.RecipientInformation;
import org.bouncycastle.cms.RecipientInformationStore;
import org.bouncycastle.cms.RecipientOperator;
import org.bouncycastle.cms.jcajce.JceKeyTransEnvelopedRecipient;
import org.bouncycastle.cms.jcajce.JceKeyTransRecipientId;
import org.bouncycastle.operator.InputDecryptor;
import org.slf4j.Logger;

/**
* This class is used to decrypt the <tt>pkcsPkiEnvelope</tt> of a SCEP secure
* message object and extract the <tt>messageData</tt> from within.
*
* @see PkcsPkiEnvelopeEncoder
*/
public final class PkcsPkiEnvelopeDecoder {
  private static final Logger LOGGER = getLogger(PkcsPkiEnvelopeDecoder.class);
  private final X509Certificate recipient;
  private final PrivateKey priKey;

  /**
   * Creates a <tt>PkcsPkiEnveloperDecoder</tt> for the provided certificate
   * and key.
   * <p>
   * The provided certificate is used to identify the envelope recipient info,
   * which is then used with the key unwrapped using the provided key.
   *
   * @param recipient
   *            the entity for whom the message was enveloped.
   * @param priKey
   *            the key to unwrap the symmetric encrypting key.
   */
  public PkcsPkiEnvelopeDecoder(X509Certificate recipient, PrivateKey priKey) {
    this.recipient = recipient;
    this.priKey = priKey;
  }

  /**
   * Decrypts the provided <tt>pkcsPkiEnvelope</tt>, and extracts the content.
   *
   * @param pkcsPkiEnvelope
   *            the envelope to decrypt and open.
   * @return the content of the <tt>pkcsPkiEnvelope</tt>, the SCEP
   *         <tt>messageData</tt>.
   * @throws MessageDecodingException
   *             if the envelope cannot be decoded.
   */
  public byte[] decode(CMSEnvelopedData pkcsPkiEnvelope)
      throws MessageDecodingException {
    LOGGER.debug("Decoding pkcsPkiEnvelope");
    validate(pkcsPkiEnvelope);

    LOGGER.debug(
        "Decrypting pkcsPkiEnvelope using key belonging to [issuer={}; serial={}]",
        recipient.getIssuerDN(), recipient.getSerialNumber());
    final RecipientInformationStore recipientInfos = pkcsPkiEnvelope
        .getRecipientInfos();
    RecipientInformation info = recipientInfos
        .get(new JceKeyTransRecipientId(recipient));

    if (info == null) {
      throw new MessageDecodingException(
          "Missing expected key transfer recipient");
    }

    LOGGER.debug("pkcsPkiEnvelope encryption algorithm: {}", info
        .getKeyEncryptionAlgorithm().getAlgorithm());

    try {
      byte[] messageData = info.getContent(getKeyTransRecipient());
      LOGGER.debug("Finished decoding pkcsPkiEnvelope");
      return messageData;
    } catch (CMSException e) {
      throw new MessageDecodingException(e);
    }
  }

  private JceKeyTransEnvelopedRecipient getKeyTransRecipient() {
    return new JceKeyTransEnvelopedRecipient(priKey) {
      public RecipientOperator getRecipientOperator(
          AlgorithmIdentifier keyEncryptionAlgorithm,
          final AlgorithmIdentifier contentEncryptionAlgorithm,
          byte[] encryptedContentEncryptionKey) throws CMSException {
        if ("1.3.14.3.2.7".equals(contentEncryptionAlgorithm
            .getAlgorithm().getId())) {
          final Cipher dataCipher;
          try {
            Cipher unwrapper = Cipher.getInstance("RSA");
            unwrapper.init(Cipher.UNWRAP_MODE, priKey);
            Key encKey = unwrapper.unwrap(encryptedContentEncryptionKey, "DES", Cipher.SECRET_KEY);
            ASN1Encodable sParams = contentEncryptionAlgorithm.getParameters();
           
            dataCipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
            dataCipher.init(Cipher.DECRYPT_MODE, encKey, new IvParameterSpec(
                                ASN1OctetString.getInstance(sParams).getOctets()));
          } catch (GeneralSecurityException e) {
            throw new CMSException("Could not create DES cipher", e);
          }

          return new RecipientOperator(new InputDecryptor() {
            public AlgorithmIdentifier getAlgorithmIdentifier() {
              return contentEncryptionAlgorithm;
            }

            public InputStream getInputStream(InputStream dataIn) {
              return new CipherInputStream(dataIn, dataCipher);
            }
          });
        }
        return super.getRecipientOperator(keyEncryptionAlgorithm,
            contentEncryptionAlgorithm,
            encryptedContentEncryptionKey);
      }
    };
  }

  private void validate(CMSEnvelopedData pkcsPkiEnvelope) {
    EnvelopedData ed = EnvelopedData.getInstance(pkcsPkiEnvelope
        .toASN1Structure().getContent());
    LOGGER.debug("pkcsPkiEnvelope version: {}", ed.getVersion());
    LOGGER.debug("pkcsPkiEnvelope encryptedContentInfo contentType: {}", ed
        .getEncryptedContentInfo().getContentType());
  }
}
TOP

Related Classes of org.jscep.message.PkcsPkiEnvelopeDecoder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.