Cifrado utilizando PKCS # 7

Estoy utilizando la biblioteca provista por Bouncy Castle para cifrar, descifrar, firmar y verificar firmar. Estoy haciendo esto como
1. Cifrar datos
2. firmar los datos
3. Escribir byte firmado en un archivo.
4. Leer el byte firmado del archivo.
5. Verificar firma
6. Descifrar datos

He tomado referencia deCriptografía inicial con Java

Mi problema está en el paso 5 cuando estoy verificando los datos que estoy obteniendo

org.bouncycastle.cms.CMSException: el valor del atributo message-digest no coincide con el valor calculado

Mi codigo esta abajo

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.
     * <p>
     * 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");
    }


}

Respuestas a la pregunta(2)

Su respuesta a la pregunta