Manière correcte de signer et de vérifier la signature en utilisant bouncycastle

J’utilise bcmail-jdk16-1.46.jar et bcprov-jdk16-1.46.jar (bibliothèques Bouncycastle) pour signer une ssortingng puis vérifier la signature .

Ceci est mon code pour signer une ssortingng :

 package my.package; import java.io.FileInputStream; import java.security.Key; import java.security.KeyStore; import java.security.PrivateKey; import java.security.Security; import java.security.Signature; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.List; import org.bouncycastle.cert.jcajce.JcaCertStore; import org.bouncycastle.cms.CMSProcessableByteArray; import org.bouncycastle.cms.CMSSignedData; import org.bouncycastle.cms.CMSSignedDataGenerator; import org.bouncycastle.cms.CMSTypedData; import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.operator.ContentSigner; import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder; import org.bouncycastle.util.Store; import sun.misc.BASE64Encoder; public class SignMessage { static final Ssortingng KEYSTORE_FILE = "keys/certificatees.p12"; static final Ssortingng KEYSTORE_INSTANCE = "PKCS12"; static final Ssortingng KEYSTORE_PWD = "test"; static final Ssortingng KEYSTORE_ALIAS = "Key1"; public static void main(Ssortingng[] args) throws Exception { Ssortingng text = "This is a message"; Security.addProvider(new BouncyCastleProvider()); KeyStore ks = KeyStore.getInstance(KEYSTORE_INSTANCE); ks.load(new FileInputStream(KEYSTORE_FILE), KEYSTORE_PWD.toCharArray()); Key key = ks.getKey(KEYSTORE_ALIAS, KEYSTORE_PWD.toCharArray()); //Sign PrivateKey privKey = (PrivateKey) key; Signature signature = Signature.getInstance("SHA1WithRSA", "BC"); signature.initSign(privKey); signature.update(text.getBytes()); //Build CMS X509Certificate cert = (X509Certificate) ks.getCertificate(KEYSTORE_ALIAS); List certList = new ArrayList(); CMSTypedData msg = new CMSProcessableByteArray(signature.sign()); certList.add(cert); Store certs = new JcaCertStore(certList); CMSSignedDataGenerator gen = new CMSSignedDataGenerator(); ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider("BC").build(privKey); gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider("BC").build()).build(sha1Signer, cert)); gen.addCertificates(certs); CMSSignedData sigData = gen.generate(msg, false); BASE64Encoder encoder = new BASE64Encoder(); Ssortingng signedContent = encoder.encode((byte[]) sigData.getSignedContent().getContent()); System.out.println("Signed content: " + signedContent + "\n"); Ssortingng envelopedData = encoder.encode(sigData.getEncoded()); System.out.println("Enveloped data: " + envelopedData); } } 

Maintenant, la sortie EnvelopedData sera utilisée dans le processus pour verify la signature de la manière suivante:

 package my.package; import java.security.Security; import java.security.cert.X509Certificate; import java.util.Collection; import java.util.Iterator; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; import org.bouncycastle.cms.CMSSignedData; import org.bouncycastle.cms.SignerInformation; import org.bouncycastle.cms.SignerInformationStore; import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.util.Store; import org.bouncycastle.util.encoders.Base64; public class VerifySignature { public static void main(Ssortingng[] args) throws Exception { Ssortingng envelopedData = "MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIAwggLQMIIC" + "OQIEQ479uzANBgkqhkiG9w0BAQUFADCBrjEmMCQGCSqGSIb3DQEJARYXcm9zZXR0YW5ldEBtZW5k" + "ZWxzb24uZGUxCzAJBgNVBAYTAkRFMQ8wDQYDVQQIEwZCZXJsaW4xDzANBgNVBAcTBkJlcmxpbjEi" + "MCAGA1UEChMZbWVuZGVsc29uLWUtY29tbWVyY2UgR21iSDEiMCAGA1UECxMZbWVuZGVsc29uLWUt" + "Y29tbWVyY2UgR21iSDENMAsGA1UEAxMEbWVuZDAeFw0wNTEyMDExMzQyMTlaFw0xOTA4MTAxMzQy" + "MTlaMIGuMSYwJAYJKoZIhvcNAQkBFhdyb3NldHRhbmV0QG1lbmRlbHNvbi5kZTELMAkGA1UEBhMC" + "REUxDzANBgNVBAgTBkJlcmxpbjEPMA0GA1UEBxMGQmVybGluMSIwIAYDVQQKExltZW5kZWxzb24t" + "ZS1jb21tZXJjZSBHbWJIMSIwIAYDVQQLExltZW5kZWxzb24tZS1jb21tZXJjZSBHbWJIMQ0wCwYD" + "VQQDEwRtZW5kMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+X1g6JvbdwJI6mQMNT41GcycH" + "UbwCFWKJ4qHDaHffz3n4h+uQJJoQvc8yLTCfnl109GB0yL2Y5YQtTohOS9IwyyMWBhh77WJtCN8r" + "dOfD2DW17877te+NlpugRvg6eOH6np9Vn3RZODVxxTyyJ8pI8VMnn13YeyMMw7VVaEO5hQIDAQAB" + "MA0GCSqGSIb3DQEBBQUAA4GBALwOIc/rWMAANdEh/GgO/DSkVMwxM5UBr3TkYbLU/5jg0Lwj3Y++" + "KhumYSrxnYewSLqK+JXA4Os9NJ+b3eZRZnnYQ9eKeUZgdE/QP9XE04y8WL6ZHLB4sDnmsgVaTU+p" + "0lFyH0Te9NyPBG0J88109CXKdXCTSN5gq0S1CfYn0staAAAxggG9MIIBuQIBATCBtzCBrjEmMCQG" + "CSqGSIb3DQEJARYXcm9zZXR0YW5ldEBtZW5kZWxzb24uZGUxCzAJBgNVBAYTAkRFMQ8wDQYDVQQI" + "EwZCZXJsaW4xDzANBgNVBAcTBkJlcmxpbjEiMCAGA1UEChMZbWVuZGVsc29uLWUtY29tbWVyY2Ug" + "R21iSDEiMCAGA1UECxMZbWVuZGVsc29uLWUtY29tbWVyY2UgR21iSDENMAsGA1UEAxMEbWVuZAIE" + "Q479uzAJBgUrDgMCGgUAoF0wGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUx" + "DxcNMTMwNTIxMDE1MDUzWjAjBgkqhkiG9w0BCQQxFgQU8mE6gw6iudxLUc9379lWK0lUSWcwDQYJ" + "KoZIhvcNAQEBBQAEgYB5mVhqJu1iX9nUqfqk7hTYJb1lR/hQiCaxruEuInkuVTglYuyzivZjAR54" + "zx7Cfm5lkcRyyxQ35ztqoq/V5JzBa+dYkisKcHGptJX3CbmmDIa1s65mEye4eLS4MTBvXCNCUTb9" + "STYSWvr4VPenN80mbpqSS6JpVxjM0gF3QTAhHwAAAAAAAA=="; Security.addProvider(new BouncyCastleProvider()); CMSSignedData cms = new CMSSignedData(Base64.decode(envelopedData.getBytes())); Store store = cms.getCertificates(); SignerInformationStore signers = cms.getSignerInfos(); Collection c = signers.getSigners(); Iterator it = c.iterator(); while (it.hasNext()) { SignerInformation signer = (SignerInformation) it.next(); Collection certCollection = store.getMatches(signer.getSID()); Iterator certIt = certCollection.iterator(); X509CertificateHolder certHolder = (X509CertificateHolder) certIt.next(); X509Certificate cert = new JcaX509CertificateConverter().setProvider("BC").getCertificate(certHolder); if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(cert))) { System.out.println("verified"); } } } } 

Tout fonctionne bien jusqu’à signer.verify(..) raison de l’ Exception suivante:

 Exception in thread "main" org.bouncycastle.cms.CMSSignerDigestMismatchException: message-digest atsortingbute value does not match calculated value at org.bouncycastle.cms.SignerInformation.doVerify(Unknown Source) at org.bouncycastle.cms.SignerInformation.verify(Unknown Source) at my.package.VerifySignature.main(VerifySignature.java:64) 

Et je ne sais vraiment pas ce que je fais mal. Quelqu’un peut-il me donner s’il vous plaît un indice de ce qui se passe?


PS Si quelqu’un veut tester le code ci-dessus, vous aurez besoin du fichier de certificatee test que j’utilise pour reproduire tout cela, il suffit de le download/save ici:

https://dl.dropboxusercontent.com/u/15208254/keys/certificatees.p12

    le

     gen.generate(msg, false) 

    signifie que les données signées ne sont pas encapsulées dans la signature. C’est bien si vous voulez créer une signature détachée, mais cela signifie que lorsque vous allez vérifier le SignedData, vous devez utiliser le constructeur CMSSignedData qui prend également une copie des données – dans ce cas, le code utilise l’unique Le constructeur d’argument qui doit supposer que les données signées ont été encapsulées (donc ce cas sera vide), avec pour résultat que la tentative de vérification échouera.

    Il existe deux types d’object CMSSignedData générés à l’aide de CMSSignedDataGenerator. Ils sont générés de la manière suivante:

    Celui ci-dessous génère un object CMSSignedData portant une signature détachée du CMS

     gen.generate(cmsdata); 

    Le code ci-dessous crée une CMSSignedData portant une signature CMS séparée, avec les données encapsulées.

     gen.generate(cmsdata, true); 

    Donc, les vérifier nécessite 2 approches

    Approche n ° 1 pour vérifier la signature détachée avec des données encapsulées

     //sig is the Signature object CMSSignedData signedData = new CMSSignedData(Base64.decode(sig.getBytes())); 

    Approche n ° 2 pour vérifier la signature détachée sans données encapsulées, uniquement la signature détachée

     //Create a CMSProcessable object, specify any encoding, I have used mine CMSProcessable signedContent = new CMSProcessableByteArray(content.getBytes("ISO-8859-1")); //Create a InputStream object InputStream is = new ByteArrayInputStream(Base64.decode(sig.getBytes())); //Pass them both to CMSSignedData constructor CMSSignedData signedData = new CMSSignedData(signedContent, is); 

    Le rest du code pour la vérification rest le même

     Store store = signedData.getCertificates(); SignerInformationStore signers = signedData.getSignerInfos(); Collection c = signers.getSigners(); Iterator it = c.iterator(); while (it.hasNext()) { SignerInformation signer = (SignerInformation)it.next(); Collection certCollection = store.getMatches(signer.getSID()); Iterator certIt = certCollection.iterator(); X509CertificateHolder certHolder = (X509CertificateHolder)certIt.next(); X509Certificate cert = new JcaX509CertificateConverter().setProvider("BC").getCertificate(certHolder); if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(cert))) { ret = true; } } 

    Si nous utilisons signature.sign () comme dans la réponse du PO, nous ne pourrons pas récupérer le message original, car il ne s’agit que de la signature.

    Vous devez simplement saisir les octets du texte original plutôt que le contenu signé. En gros, ignorez cette partie:

     //Sign PrivateKey privKey = (PrivateKey) key; Signature signature = Signature.getInstance("SHA1WithRSA", "BC"); signature.initSign(privKey); signature.update(text.getBytes()); 

    et entrez simplement comme:

     CMSTypedData msg = new CMSProcessableByteArray(text.getBytes()); 

    Vous pouvez trouver une réponse sur ce lien ici. Vous devez simplement append des en-têtes au message ou simplement append une ligne vierge avant le message, puis signer le message pour que tout fonctionne correctement.

    Je travaille pour une signature détachée: D

     package signature; import java.security.Provider; import java.security.Security; import java.security.cert.X509Certificate; import java.util.Collection; import java.util.Iterator; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; import org.bouncycastle.cms.CMSProcessable; import org.bouncycastle.cms.CMSProcessableByteArray; import org.bouncycastle.cms.CMSSignedData; import org.bouncycastle.cms.SignerInformation; import org.bouncycastle.cms.SignerInformationStore; import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.util.Store; import org.bouncycastle.util.encoders.Base64; public class VerifySignature { static final Ssortingng DIGEST_SHA1 = "SHA1withRSA"; static final Ssortingng BC_PROVIDER = "BC"; public static void main(Ssortingng[] args) throws Exception { Ssortingng envelopedData = "MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIAwggLQMIIC" + "OQIEQ479uzANBgkqhkiG9w0BAQUFADCBrjEmMCQGCSqGSIb3DQEJARYXcm9zZXR0YW5ldEBtZW5k" + "ZWxzb24uZGUxCzAJBgNVBAYTAkRFMQ8wDQYDVQQIEwZCZXJsaW4xDzANBgNVBAcTBkJlcmxpbjEi" + "MCAGA1UEChMZbWVuZGVsc29uLWUtY29tbWVyY2UgR21iSDEiMCAGA1UECxMZbWVuZGVsc29uLWUt" + "Y29tbWVyY2UgR21iSDENMAsGA1UEAxMEbWVuZDAeFw0wNTEyMDExMzQyMTlaFw0xOTA4MTAxMzQy" + "MTlaMIGuMSYwJAYJKoZIhvcNAQkBFhdyb3NldHRhbmV0QG1lbmRlbHNvbi5kZTELMAkGA1UEBhMC" + "REUxDzANBgNVBAgTBkJlcmxpbjEPMA0GA1UEBxMGQmVybGluMSIwIAYDVQQKExltZW5kZWxzb24t" + "ZS1jb21tZXJjZSBHbWJIMSIwIAYDVQQLExltZW5kZWxzb24tZS1jb21tZXJjZSBHbWJIMQ0wCwYD" + "VQQDEwRtZW5kMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+X1g6JvbdwJI6mQMNT41GcycH" + "UbwCFWKJ4qHDaHffz3n4h+uQJJoQvc8yLTCfnl109GB0yL2Y5YQtTohOS9IwyyMWBhh77WJtCN8r" + "dOfD2DW17877te+NlpugRvg6eOH6np9Vn3RZODVxxTyyJ8pI8VMnn13YeyMMw7VVaEO5hQIDAQAB" + "MA0GCSqGSIb3DQEBBQUAA4GBALwOIc/rWMAANdEh/GgO/DSkVMwxM5UBr3TkYbLU/5jg0Lwj3Y++" + "KhumYSrxnYewSLqK+JXA4Os9NJ+b3eZRZnnYQ9eKeUZgdE/QP9XE04y8WL6ZHLB4sDnmsgVaTU+p" + "0lFyH0Te9NyPBG0J88109CXKdXCTSN5gq0S1CfYn0staAAAxggG9MIIBuQIBATCBtzCBrjEmMCQG" + "CSqGSIb3DQEJARYXcm9zZXR0YW5ldEBtZW5kZWxzb24uZGUxCzAJBgNVBAYTAkRFMQ8wDQYDVQQI" + "EwZCZXJsaW4xDzANBgNVBAcTBkJlcmxpbjEiMCAGA1UEChMZbWVuZGVsc29uLWUtY29tbWVyY2Ug" + "R21iSDEiMCAGA1UECxMZbWVuZGVsc29uLWUtY29tbWVyY2UgR21iSDENMAsGA1UEAxMEbWVuZAIE" + "Q479uzAJBgUrDgMCGgUAoF0wGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUx" + "DxcNMTMwNTIxMDE1MDUzWjAjBgkqhkiG9w0BCQQxFgQU8mE6gw6iudxLUc9379lWK0lUSWcwDQYJ" + "KoZIhvcNAQEBBQAEgYB5mVhqJu1iX9nUqfqk7hTYJb1lR/hQiCaxruEuInkuVTglYuyzivZjAR54" + "zx7Cfm5lkcRyyxQ35ztqoq/V5JzBa+dYkisKcHGptJX3CbmmDIa1s65mEye4eLS4MTBvXCNCUTb9" + "STYSWvr4VPenN80mbpqSS6JpVxjM0gF3QTAhHwAAAAAAAA=="; Ssortingng Sig_Bytes ="YduK22AlMLSXV3ajX5r/pX5OQ0xjj58uhGT9I9MvOrz912xNHo+9OiOKeMOD+Ys2/LUW3XaN6T+/"+ "tuRM5bi4RK7yjaqaJCZWtr/O4I968BQGgt0cyNvK8u0Jagbr9MYk6G7nnejbRXYHyAOaunqD05lW"+ "U/+g92i18dl0OMc50m4="; Provider provider = new BouncyCastleProvider(); Security.addProvider(provider); CMSSignedData signedData = new CMSSignedData(Base64.decode(envelopedData.getBytes())); CMSProcessable cmsProcesableContent = new CMSProcessableByteArray(Base64.decode(Sig_Bytes.getBytes())); signedData = new CMSSignedData(cmsProcesableContent, Base64.decode(envelopedData.getBytes())); // Verify signature Store store = signedData.getCertificates(); SignerInformationStore signers = signedData.getSignerInfos(); Collection c = signers.getSigners(); Iterator it = c.iterator(); while (it.hasNext()) { SignerInformation signer = (SignerInformation) it.next(); Collection certCollection = store.getMatches(signer.getSID()); Iterator certIt = certCollection.iterator(); X509CertificateHolder certHolder = (X509CertificateHolder) certIt.next(); X509Certificate certFromSignedData = new JcaX509CertificateConverter().setProvider(BC_PROVIDER).getCertificate(certHolder); if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC_PROVIDER).build(certFromSignedData))) { System.out.println("Signature verified"); } else { System.out.println("Signature verification failed"); } } } }