title: Encryption using PKCS#7
body: <p>I am using Bouncy Castle provided library to encrypt,decrypt,sign and verify sign.
  I am doing this as<br>
   1. Encrypt data <br>
   2. Sign data<br>
   3. Write signed byte to a file<br>
   4. Read signed byte from file<br>
   5. Verify signature<br>
   6. Decrypt data <br></p>
  
  <p>I have taken reference from <em>Beginning Cryptography with Java</em></p>
  
  <p>My problem is in step 5 when i am verifying data i am getting  </p>
  
  <blockquote>
    <p>org.bouncycastle.cms.CMSException: message-digest attribute value does
    not match calculated value</p>
  </blockquote>
  
  <p>My code is below </p>
  
  <pre><code>import java.io.ByteArrayInputStream;
  import java.io.File;
  import java.io.FileInputStream;
  import java.io.FileOutputStream;
  import java.math.BigInteger;
  import java.security.KeyPair;
  import java.security.KeyPairGenerator;
  import java.security.KeyStore;
  import java.security.PrivateKey;
  import java.security.PublicKey;
  import java.security.SecureRandom;
  import java.security.cert.CertPathBuilder;
  import java.security.cert.CertStore;
  import java.security.cert.Certificate;
  import java.security.cert.CollectionCertStoreParameters;
  import java.security.cert.PKIXBuilderParameters;
  import java.security.cert.PKIXCertPathBuilderResult;
  import java.security.cert.TrustAnchor;
  import java.security.cert.X509CertSelector;
  import java.security.cert.X509Certificate;
  import java.util.Arrays;
  import java.util.Collections;
  import java.util.Date;
  import java.util.Iterator;
  
  import javax.security.auth.x500.X500Principal;
  import javax.security.auth.x500.X500PrivateCredential;
  
  import org.bouncycastle.asn1.x509.BasicConstraints;
  import org.bouncycastle.asn1.x509.KeyUsage;
  import org.bouncycastle.asn1.x509.X509Extensions;
  import org.bouncycastle.cms.CMSEnvelopedData;
  import org.bouncycastle.cms.CMSEnvelopedDataGenerator;
  import org.bouncycastle.cms.CMSEnvelopedDataParser;
  import org.bouncycastle.cms.CMSProcessable;
  import org.bouncycastle.cms.CMSProcessableByteArray;
  import org.bouncycastle.cms.CMSSignedData;
  import org.bouncycastle.cms.CMSSignedDataGenerator;
  import org.bouncycastle.cms.RecipientId;
  import org.bouncycastle.cms.RecipientInformation;
  import org.bouncycastle.cms.RecipientInformationStore;
  import org.bouncycastle.cms.SignerId;
  import org.bouncycastle.cms.SignerInformation;
  import org.bouncycastle.cms.SignerInformationStore;
  import org.bouncycastle.x509.X509V1CertificateGenerator;
  import org.bouncycastle.x509.X509V3CertificateGenerator;
  import org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure;
  import org.bouncycastle.x509.extension.SubjectKeyIdentifierStructure;
  
  public class Test {
  
  
      private static final char[] KEY_STORE_PASSWORD = "123456".toCharArray();
      private static final long VALIDITY_PERIOD = 365 * 24 * 60 * 60 * 1000;
      private static final char[] KEY_PASSWORD = "keyPassword".toCharArray();
      public static String ROOT_ALIAS = "root";
      public static String INTERMEDIATE_ALIAS = "intermediate";
      public static String END_ENTITY_ALIAS = "end";
      public static String PLAIN_TEXT = "Hello World!123";
  
      public static void main(String[] args)  {
          try{
  
          // CREATE KEY STORE
          KeyStore keyStore = createKeyStore();
  
          // STEP 1. ENCRYPT AND SIGN
          byte[] step1Data = encryptData(keyStore, PLAIN_TEXT.getBytes());
          CMSSignedData cmsSignedData = signData(keyStore,step1Data);
          new File("D:\\pkcs7\\encrypted-file.p7b");
          FileOutputStream fileOuputStream = new FileOutputStream("D:\\pkcs7\\encrypted-file.p7b"); 
          fileOuputStream.write(cmsSignedData.getEncoded());
          fileOuputStream.flush();
          fileOuputStream.close();
  
  
          // STEP 2. READ ENCRYPTED DATA AND VERIFY SIGN AND DECRYPT IT
          File file =new File("D:\\pkcs7\\encrypted-file.p7b");
          FileInputStream fileInputStream = new FileInputStream(file);
          byte[] encryptedAndSignedByte = new byte[(int)file.length()];
          fileInputStream.read(encryptedAndSignedByte );
          fileInputStream.close();
          cmsSignedData =  new CMSSignedData(encryptedAndSignedByte);
          if( verifyData(keyStore, cmsSignedData) == true ){
              decryptData(keyStore,encryptedAndSignedByte);
          }
  
          }catch (Exception e) {
              e.printStackTrace();
          }
  
  
      }
  
      /**
       * 
       * This method will encrypt data
       */
      private static byte[] encryptData(KeyStore keyStore, byte[] plainData) throws Exception {
          PrivateKey key = (PrivateKey) keyStore.getKey(END_ENTITY_ALIAS,
                  KEY_PASSWORD);
          Certificate[] chain = keyStore.getCertificateChain(END_ENTITY_ALIAS);
          X509Certificate cert = (X509Certificate) chain[0];
  
          // set up the generator
          CMSEnvelopedDataGenerator gen = new CMSEnvelopedDataGenerator();
  
          gen.addKeyTransRecipient(cert);
  
          // create the enveloped-data object
          CMSProcessable data = new CMSProcessableByteArray(plainData);
  
  
          CMSEnvelopedData enveloped = gen.generate(data,
                  CMSEnvelopedDataGenerator.AES128_CBC, "BC");
  
          return  enveloped.getEncoded();
          // recreate
  
      }
  
      private static byte[] decryptData(KeyStore keyStore,byte[] encryptedData) throws Exception{
          CMSEnvelopedDataParser envelopedDataParser = new CMSEnvelopedDataParser(new ByteArrayInputStream(encryptedData));
  
          PrivateKey key = (PrivateKey) keyStore.getKey(END_ENTITY_ALIAS,KEY_PASSWORD);
          Certificate[] chain = keyStore.getCertificateChain(END_ENTITY_ALIAS);
          X509Certificate cert = (X509Certificate) chain[0];
  
  
          CMSEnvelopedData enveloped = new CMSEnvelopedData(encryptedData);
  
          // look for our recipient identifier
          RecipientId recId = new RecipientId();
  
          recId.setSerialNumber(cert.getSerialNumber());
          recId.setIssuer(cert.getIssuerX500Principal().getEncoded());
  
          RecipientInformationStore recipients = enveloped.getRecipientInfos();
          RecipientInformation recipient = recipients.get(recId);
  
          if (recipient != null) {
              // decrypt the data
              byte[] recData = recipient.getContent(key, "BC");
              System.out.println("----------------------- RECOVERED DATA -----------------------");
              System.out.println(new String(recData));
              System.out.println("--------------------------------------------------------------");
              return recData;
  
          } else {
              System.out.println("could not find a matching recipient");
          }
          return null;
      }
  
      private static CMSSignedData signData(KeyStore keyStore,byte[] encryptedData ) throws Exception {
          // GET THE PRIVATE KEY
          PrivateKey key = (PrivateKey) keyStore.getKey(END_ENTITY_ALIAS,
                  KEY_PASSWORD);
  
          Certificate[] chain = keyStore.getCertificateChain(END_ENTITY_ALIAS);
          CertStore certsAndCRLs = CertStore.getInstance("Collection",
                  new CollectionCertStoreParameters(Arrays.asList(chain)), "BC");
          X509Certificate cert = (X509Certificate) chain[0];
  
          // set up the generator
          CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
          gen.addSigner(key, cert, CMSSignedDataGenerator.DIGEST_SHA224);
          gen.addCertificatesAndCRLs(certsAndCRLs);
  
          // create the signed-data object
          CMSProcessable data = new CMSProcessableByteArray(encryptedData);
          CMSSignedData signed = gen.generate(data, "BC");
  
          // recreate
          signed = new CMSSignedData(data, signed.getEncoded());
          // ContentInfo conInf = signed.getContentInfo();
          // CMSProcessable sigContent = signed.getSignedContent();
          return signed;
      }
  
      private static boolean verifyData(KeyStore keyStore, CMSSignedData signed)
              throws Exception {
          // verification step
          X509Certificate rootCert = (X509Certificate) keyStore.getCertificate(ROOT_ALIAS);
  
          if (isValidSignature(signed, rootCert)) {
              System.out.println("verification succeeded");
              return true;
          } else {
              System.out.println("verification failed");
          }
          return false;
      }
  
      /**
       * Take a CMS SignedData message and a trust anchor and determine if the
       * message is signed with a valid signature from a end entity entity
       * certificate recognized by the trust anchor rootCert.
       */
      private static boolean isValidSignature(CMSSignedData signedData,
              X509Certificate rootCert) throws Exception {
  
          boolean[] bArr = new boolean[2];
          bArr[0] = true;
          CertStore certsAndCRLs = signedData.getCertificatesAndCRLs(
                  "Collection", "BC");
          SignerInformationStore signers = signedData.getSignerInfos();
          Iterator it = signers.getSigners().iterator();
  
          if (it.hasNext()) {
              SignerInformation signer = (SignerInformation) it.next();
              SignerId signerConstraints = signer.getSID();
              signerConstraints.setKeyUsage(bArr);
              PKIXCertPathBuilderResult result = buildPath(rootCert,
                      signer.getSID(), certsAndCRLs);
              return signer.verify(result.getPublicKey(), "BC");
          }
  
          return false;
      }
  
      /**
       * Build a path using the given root as the trust anchor, and the passed in
       * end constraints and certificate store.
       * &lt;p&gt;
       * Note: the path is built with revocation checking turned off.
       */
      public static PKIXCertPathBuilderResult buildPath(X509Certificate rootCert,
              X509CertSelector endConstraints, CertStore certsAndCRLs)
              throws Exception {
          CertPathBuilder builder = CertPathBuilder.getInstance("PKIX", "BC");
          PKIXBuilderParameters buildParams = new PKIXBuilderParameters(
                  Collections.singleton(new TrustAnchor(rootCert, null)),
                  endConstraints);
  
          buildParams.addCertStore(certsAndCRLs);
          buildParams.setRevocationEnabled(false);
  
          return (PKIXCertPathBuilderResult) builder.build(buildParams);
      }
  
      /**
       * Create a KeyStore containing the a private credential with certificate
       * chain and a trust anchor.
       */
      public static KeyStore createKeyStore() throws Exception {
          KeyStore keyStore = KeyStore.getInstance("JKS");
          keyStore.load(null, null);
  
          keyStore.load(null, null);
  
          X500PrivateCredential rootCredential = createRootCredential();
          X500PrivateCredential interCredential = createIntermediateCredential(
                  rootCredential.getPrivateKey(), rootCredential.getCertificate());
          X500PrivateCredential endCredential = createEndEntityCredential(
                  interCredential.getPrivateKey(),
                  interCredential.getCertificate());
  
          keyStore.setCertificateEntry(rootCredential.getAlias(),
                  rootCredential.getCertificate());
          keyStore.setKeyEntry(
                  endCredential.getAlias(),
                  endCredential.getPrivateKey(),
                  KEY_PASSWORD,
                  new Certificate[] { endCredential.getCertificate(),
                          interCredential.getCertificate(),
                          rootCredential.getCertificate() });
  
          keyStore.store(new FileOutputStream("d:\\pkcs7\\KeyStore.jks"),
                  KEY_STORE_PASSWORD);
          return keyStore;
      }
  
      /**
       * Create a random 1024 bit RSA key pair
       */
      public static KeyPair generateRSAKeyPair() throws Exception {
          KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC");
          kpGen.initialize(1024, new SecureRandom());
          return kpGen.generateKeyPair();
      }
  
      /**
       * Generate a sample V1 certificate to use as a CA root certificate
       */
      public static X509Certificate generateCertificate(KeyPair pair)
              throws Exception {
          X509V1CertificateGenerator certGen = new X509V1CertificateGenerator();
          certGen.setSerialNumber(BigInteger.valueOf(1));
          certGen.setIssuerDN(new X500Principal("CN=Test CA Certificate"));
          certGen.setNotBefore(new Date(System.currentTimeMillis()
                  - VALIDITY_PERIOD));
          certGen.setNotAfter(new Date(System.currentTimeMillis()
                  + VALIDITY_PERIOD));
          certGen.setSubjectDN(new X500Principal("CN=Test CA Certificate"));
          certGen.setPublicKey(pair.getPublic());
          certGen.setSignatureAlgorithm("SHA1WithRSAEncryption");
          return certGen.generateX509Certificate(pair.getPrivate(), "BC");
      }
  
      /**
       * Generate a sample V1 certificate to use as a CA root certificate
       */
      public static X509Certificate generateRootCert(KeyPair pair)
              throws Exception {
          X509V1CertificateGenerator certGen = new X509V1CertificateGenerator();
  
          certGen.setSerialNumber(BigInteger.valueOf(1));
          certGen.setIssuerDN(new X500Principal("CN=Test CA Certificate"));
          certGen.setNotBefore(new Date(System.currentTimeMillis()
                  - VALIDITY_PERIOD));
          certGen.setNotAfter(new Date(System.currentTimeMillis()
                  + VALIDITY_PERIOD));
          certGen.setSubjectDN(new X500Principal("CN=Test CA Certificate"));
          certGen.setPublicKey(pair.getPublic());
          certGen.setSignatureAlgorithm("SHA1WithRSAEncryption");
  
          return certGen.generateX509Certificate(pair.getPrivate(), "BC");
      }
  
      /**
       * Generate a sample V3 certificate to use as an end entity certificate
       */
      public static X509Certificate generateEndEntityCert(PublicKey entityKey,
              PrivateKey caKey, X509Certificate caCert) throws Exception {
          X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
  
          certGen.setSerialNumber(BigInteger.valueOf(1));
          certGen.setIssuerDN(caCert.getSubjectX500Principal());
          certGen.setNotBefore(new Date(System.currentTimeMillis()
                  - VALIDITY_PERIOD));
          certGen.setNotAfter(new Date(System.currentTimeMillis()
                  + VALIDITY_PERIOD));
          certGen.setSubjectDN(new X500Principal("CN=Test End Certificate"));
          certGen.setPublicKey(entityKey);
          certGen.setSignatureAlgorithm("SHA1WithRSAEncryption");
  
          certGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false,
                  new AuthorityKeyIdentifierStructure(caCert));
          certGen.addExtension(X509Extensions.SubjectKeyIdentifier, false,
                  new SubjectKeyIdentifierStructure(entityKey));
          certGen.addExtension(X509Extensions.BasicConstraints, true,
                  new BasicConstraints(false));
          certGen.addExtension(X509Extensions.KeyUsage, true, new KeyUsage(
                  KeyUsage.digitalSignature | KeyUsage.keyEncipherment));
  
          return certGen.generateX509Certificate(caKey, "BC");
      }
  
      /**
       * Generate a X500PrivateCredential for the root entity.
       */
      public static X500PrivateCredential createRootCredential() throws Exception {
          KeyPair rootPair = generateRSAKeyPair();
          X509Certificate rootCert = generateRootCert(rootPair);
  
          return new X500PrivateCredential(rootCert, rootPair.getPrivate(),
                  ROOT_ALIAS);
      }
  
      /**
       * Generate a X500PrivateCredential for the intermediate entity.
       */
      public static X500PrivateCredential createIntermediateCredential(
              PrivateKey caKey, X509Certificate caCert) throws Exception {
          KeyPair interPair = generateRSAKeyPair();
          X509Certificate interCert = generateIntermediateCert(
                  interPair.getPublic(), caKey, caCert);
  
          return new X500PrivateCredential(interCert, interPair.getPrivate(),
                  INTERMEDIATE_ALIAS);
      }
  
      /**
       * Generate a X500PrivateCredential for the end entity.
       */
      public static X500PrivateCredential createEndEntityCredential(
              PrivateKey caKey, X509Certificate caCert) throws Exception {
          KeyPair endPair = generateRSAKeyPair();
          X509Certificate endCert = generateEndEntityCert(endPair.getPublic(),
                  caKey, caCert);
  
          return new X500PrivateCredential(endCert, endPair.getPrivate(),
                  END_ENTITY_ALIAS);
      }
  
      /**
       * Generate a sample V3 certificate to use as an intermediate CA certificate
       */
      public static X509Certificate generateIntermediateCert(PublicKey intKey,
              PrivateKey caKey, X509Certificate caCert) throws Exception {
          X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
  
          certGen.setSerialNumber(BigInteger.valueOf(1));
          certGen.setIssuerDN(caCert.getSubjectX500Principal());
          certGen.setNotBefore(new Date(System.currentTimeMillis()));
          certGen.setNotAfter(new Date(System.currentTimeMillis()
                  + VALIDITY_PERIOD));
          certGen.setSubjectDN(new X500Principal(
                  "CN=Test Intermediate Certificate"));
          certGen.setPublicKey(intKey);
          certGen.setSignatureAlgorithm("SHA1WithRSAEncryption");
  
          certGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false,
                  new AuthorityKeyIdentifierStructure(caCert));
          certGen.addExtension(X509Extensions.SubjectKeyIdentifier, false,
                  new SubjectKeyIdentifierStructure(intKey));
          certGen.addExtension(X509Extensions.BasicConstraints, true,
                  new BasicConstraints(0));
          certGen.addExtension(X509Extensions.KeyUsage, true, new KeyUsage(
                  KeyUsage.digitalSignature | KeyUsage.keyCertSign
                          | KeyUsage.cRLSign));
  
          return certGen.generateX509Certificate(caKey, "BC");
      }
  
  
  }
  </code></pre>