title: Correct way to sign and verify signature using bouncycastle
body: <p>I am using <code>bcmail-jdk16-1.46.jar</code> and <code>bcprov-jdk16-1.46.jar</code> <strong>(Bouncycastle libraries)</strong> to sign a <code>string</code> and then verify the <code>signature</code>.</p>
  
  <p><strong>This is my <code>code</code> to sign a <code>string</code>:</strong></p>
  
  <pre><code>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 String KEYSTORE_FILE = "keys/certificates.p12";
      static final String KEYSTORE_INSTANCE = "PKCS12";
      static final String KEYSTORE_PWD = "test";
      static final String KEYSTORE_ALIAS = "Key1";
  
      public static void main(String[] args) throws Exception {
  
          String 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();
  
          String signedContent = encoder.encode((byte[]) sigData.getSignedContent().getContent());
          System.out.println("Signed content: " + signedContent + "\n");
  
          String envelopedData = encoder.encode(sigData.getEncoded());
          System.out.println("Enveloped data: " + envelopedData);
      }
  }
  </code></pre>
  
  <p><strong>Now, the <code>EnvelopedData</code> output will be used in the process to <code>verify</code> the <code>signature</code>:</strong></p>
  
  <pre><code>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(String[] args) throws Exception {
  
          String 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");
              }
          }
  
      }
  
  }
  </code></pre>
  
  <p><strong>Everything works fine until <code>signer.verify(..)</code> due to the following <code>Exception</code>:</strong></p>
  
  <pre><code>Exception in thread "main" org.bouncycastle.cms.CMSSignerDigestMismatchException: message-digest attribute 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)
  </code></pre>
  
  <p>Can someone please give me a hint of what could be happening?</p>
  
  <hr>
  
  <p><strong><em>PS</strong>. If someone wants to test above <code>code</code> you will need the test <code>certificate</code> file that I am using to replicate this, just <code>download</code> it from here:</em> </p>
  
  <p><a href="https://www.dropbox.com/s/zs4jo1a86v8qamw/certificates.p12?dl=0" rel="noreferrer">https://www.dropbox.com/s/zs4jo1a86v8qamw/certificates.p12?dl=0</a></p>