2012-06-17 2 views
0

J'utilise la bibliothèque fournie par Bouncy Castle pour crypter, décrypter, signer et vérifier les signes. que je fais ce que
1. Chiffrer les données
2. Données de signe
3. Ecrire octet signé dans un fichier
4. Lire octet signé à partir du fichier
5. Vérifiez la signature
6. données Décrypter
Cryptage utilisant PKCS # 7

J'ai pris référence à partir à partir Cryptographie avec Java

Mon problème est à l'étape 5 quand je suis la vérification des données que je reçois

org.bouncycastle.cms.CMSException: message-digest valeur d'attribut ne pas correspondre à la valeur calculée

Mon code est ci-dessous

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


} 
+0

connexes [question précédente] (http://stackoverflow.com/questions/11044888/using-pkcs-7-cryptography) par le même utilisateur – CodesInChaos

+1

Votre question semble se concentrer sur les fichiers '.p7b'. Mais les extensions de fichiers sont simplement des conventions. Ce serait mieux si vous pouviez vous concentrer sur le problème de programmation que vous essayez de résoudre et où vous êtes coincé dans cette quête. De cette façon, nous pourrions mieux vous aider. Cela dit, je vais vous offrir une réponse, mais je doute que cela vous aidera à résoudre votre problème. –

+0

juste une note sur la commande entre le cryptage et la signature. S'il vous plaît, assurez-vous de la première signature, puis crypter (contrairement à ce que vous avez écrit dans votre message). Sinon, vous rencontrez de nombreux problèmes. Par exemple, l'identité de l'émetteur est divulguée et il est également possible que quelqu'un supprime la signature et ajoute la sienne. – iammyr

Répondre

6

Dans l'utilisation typique d'un fichier .p7b ne contient que certificats de clé publique et jamais une clé privée. Il est souvent utilisé pour stocker une chaîne entière de certificats plutôt qu'un seul certificat. Le nom 'p7b' vient du format qui est la forme dégénérée de la structure SignedData de PKCS # 7. Généralement, les clés privées sont stockées dans un fichier PKCS # 12 (souvent un fichier contenant une extension .p12 ou une extension .pfx), mais d'autres formats sont également courants.

Pour lire les certificats d'un fichier p7b, vous pouvez utiliser la classe CertificateFactory. Un fichier PKCS # 12 est directement utilisable en tant que magasin de clés.

Vous mentionnez fréquemment PKCS # 7. PKCS # 7 est une ancienne norme extrêmement grande et ouverte. De nos jours, la norme la plus communément implémentée est un sous-ensemble étendu de PKCS # 7 appelé CMS. C'est une norme IETF documentée dans RFC 5652. Le Bouncycastle PKIX/CMS library prend en charge la spécification CMS.

+0

Est-il vrai que tous les formats p7 (avec une extension telle que .p7b ou .p7s etc.) sont cryptés? Est-il possible de convertir le message sans cryptage en fichiers p7? Je veux dire que le cryptage est-il obligatoire en p7 ou est-il optionnel? –

2
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(); 
    } 
+4

Bienvenue sur Stack Overflow! Envisageriez-vous d'ajouter un récit pour expliquer pourquoi ce code fonctionne, et qu'est-ce qui en fait une réponse à la question? –

Questions connexes