Шифрование с использованием PKCS # 7

Я использую библиотеку Bouncy Castle для шифрования, дешифрования, подписи и проверки подписи. Я делаю это как
 1. Шифровать данные
 2. Подписать данные
 3. Записать подписанный байт в файл
 4. Чтение подписанного байта из файла.
 5. Проверьте подпись
 6. Расшифровать данные

Я взял ссылку изBeginning Cryptography with Java

Моя проблема в шаге 5, когда я проверяю данные, которые я получаю

org.bouncycastle.cms.CMSException: message-digest attribute value does not match calculated value

Мой код ниже

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


}
 iammyr20 июл. 2016 г., 13:36
просто примечание о порядке между шифрованием и подписью. Пожалуйста, не забудьте сначала подписать, а затем зашифровать (в отличие от того, что вы написали в своем посте). В противном случае вы столкнетесь со многими проблемами. Например, личность эмитента утечка, а также кто-то может удалить подпись и добавить свою собственную.
 James K Polk17 июн. 2012 г., 15:28
Ваш вопрос кажется сосредоточенным на.p7b файлы. Но расширения файлов - это просто соглашения. Было бы лучше, если бы вы сосредоточились на проблеме программирования, которую вы пытаетесь решить, и где вы застряли в этом стремлении. Таким образом, мы могли бы лучше помочь вам. Тем не менее, я предложу ответ на ваши вопросы, но я сомневаюсь, что это приблизит вас к решению вашей проблемы.
 CodesInChaos17 июн. 2012 г., 15:10
связанные сearlier question тем же пользователем

Ответы на вопрос(2)

Решение Вопроса

В типичном использовании.p7b Файл содержит только сертификаты открытого ключа и никогда не закрытый ключ. Он часто используется для хранения всей цепочки сертификатов, а не одного сертификата. 'P7b' имя происходит из формата, который является вырожденной формой структуры PKCS # 7 SignedData. Как правило, закрытые ключи хранятся в PKCS # 12 (часто это файл, который имеет.p12 или.pfx расширение), но другие форматы также распространены.

Чтобы прочитать сертификаты из файла p7b, вы можете использоватьCertificateFactory учебный класс. Файл PKCS # 12 можно напрямую использовать в качестве хранилища ключей.

Вы часто упоминаете PKCS # 7. PKCS # 7 - это старый стандарт, чрезвычайно большой и открытый. В наши дни более распространенным стандартом является расширенное подмножество PKCS # 7, называемое CMS. Это стандарт IETF, документированный вRFC 5652,Bouncycastle PKIX / CMS библиотека имеет обширную поддержку спецификации CMS.

 04 мая 2016 г., 09:26
Правда ли, что все форматы p7 (с любым расширением, например .p7b или .p7s и т. Д.) Зашифрованы? Можно ли конвертировать сообщение без шифрования в файлы p7? Я имею в виду, обязательно ли шифрование в p7 или это необязательно?
  try {
    File file = new File("d:\\TESTS\\VG.p7b");
    FileInputStream fis = new FileInputStream(file);
    CertificateFactory cf = CertificateFactory.getInstance("X.509");
    Collection c = cf.generateCertificates(fis);
    Iterator i = c.iterator();
    while (i.hasNext()) {
      X509Certificate cert509 = (X509Certificate) i.next();
      System.out.println(cert509);
    }
  }
  catch (Throwable th) {
    th.printStackTrace();
  }
 27 авг. 2012 г., 13:23
Добро пожаловать в переполнение стека! Не могли бы вы добавить описательную часть, чтобы объяснить, почему этот код работает, и что делает его ответом на вопрос?

Ваш ответ на вопрос