12

I want to sign a text file (may be a .exe file or something else in the future) using PKCS#7 and verify the signature using Java.

  1. What do I need to know?
  2. Where will I find an API (.jar and documentation)?
  3. What are the steps I need to follow in order to sign data and verify the data?

Please provide me code snippet if possible.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
user1269042
  • 121
  • 1
  • 2
  • 8
  • 2
    Dear user, please revisit [this older question](http://stackoverflow.com/questions/9805385/delete-query-is-not-working-form-java-application). I've voted to close the other question. [Please](http://stackoverflow.com/questions/2377402/how-to-encode-a-value-in-pkcs7-with-java) [do](http://stackoverflow.com/questions/3166159/verifying-pkcs7-certificates-in-java) your homework before asking questions. – Maarten Bodewes May 22 '12 at 19:40
  • Do you want the signed exe file to be recognized by Windows as signed. – Emmanuel Bourg May 22 '12 at 21:27

2 Answers2

15

I reckon you need the following 2 Bouncy Castle jars to generate the PKCS7 digital signature:

  • bcprov-jdk15on-147.jar (for JDK 1.5 - JDK 1.7)

  • bcmail-jdk15on-147.jar (for JDK 1.5 - JDK 1.7)

You can download the Bouncy Castle jars from here.

You need to setup your keystore with the public & private key pair. You need only the private key to generate the digital signature & the public key to verify it.

Here's how you'd pkcs7 sign content (Exception handling omitted for brevity) :

import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;
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 org.bouncycastle.util.encoders.Base64;

public final class PKCS7Signer {

    private static final String PATH_TO_KEYSTORE = "/path/to/keyStore";
    private static final String KEY_ALIAS_IN_KEYSTORE = "My_Private_Key";
    private static final String KEYSTORE_PASSWORD = "MyPassword";
    private static final String SIGNATUREALGO = "SHA1withRSA";

    public PKCS7Signer() {
    }

    KeyStore loadKeyStore() throws Exception {

        KeyStore keystore = KeyStore.getInstance("JKS");
        InputStream is = new FileInputStream(PATH_TO_KEYSTORE);
        keystore.load(is, KEYSTORE_PASSWORD.toCharArray());
        return keystore;
    }

    CMSSignedDataGenerator setUpProvider(final KeyStore keystore) throws Exception {

        Security.addProvider(new BouncyCastleProvider());

        Certificate[] certchain = (Certificate[]) keystore.getCertificateChain(KEY_ALIAS_IN_KEYSTORE);

        final List<Certificate> certlist = new ArrayList<Certificate>();

        for (int i = 0, length = certchain == null ? 0 : certchain.length; i < length; i++) {
            certlist.add(certchain[i]);
        }

        Store certstore = new JcaCertStore(certlist);

        Certificate cert = keystore.getCertificate(KEY_ALIAS_IN_KEYSTORE);

        ContentSigner signer = new JcaContentSignerBuilder(SIGNATUREALGO).setProvider("BC").
                build((PrivateKey) (keystore.getKey(KEY_ALIAS_IN_KEYSTORE, KEYSTORE_PASSWORD.toCharArray())));

        CMSSignedDataGenerator generator = new CMSSignedDataGenerator();

        generator.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider("BC").
                build()).build(signer, (X509Certificate) cert));

        generator.addCertificates(certstore);

        return generator;
    }

    byte[] signPkcs7(final byte[] content, final CMSSignedDataGenerator generator) throws Exception {

        CMSTypedData cmsdata = new CMSProcessableByteArray(content);
        CMSSignedData signeddata = generator.generate(cmsdata, true);
        return signeddata.getEncoded();
    }

    public static void main(String[] args) throws Exception {

        PKCS7Signer signer = new PKCS7Signer();
        KeyStore keyStore = signer.loadKeyStore();
        CMSSignedDataGenerator signatureGenerator = signer.setUpProvider(keyStore);
        String content = "some bytes to be signed";
        byte[] signedBytes = signer.signPkcs7(content.getBytes("UTF-8"), signatureGenerator);
        System.out.println("Signed Encoded Bytes: " + new String(Base64.encode(signedBytes)));
    }
}
Zaki
  • 6,997
  • 6
  • 37
  • 53
  • How do i generate public and private key . what all algorithm can i use to sign. we have not mentioned bit length. can you please provide any study material reference, so that i can understand a2z – user1269042 Jun 12 '12 at 13:41
  • @user1269042, See [Public key Cryptography](http://en.wikipedia.org/wiki/Public-key_cryptography) for a start. Google around to find more. Although a bit dated, [Beginning Cryptography with Java](http://www.amazon.com/Beginning-Cryptography-Java-David-Hook/dp/0764596330) is an excellent reference. – Zaki Jun 12 '12 at 14:03
  • You forgot to mention the need for bcpkix-jdk15on-147.jar (now 148) for org.bouncycastle.cms imports. – Cyril N. Apr 22 '13 at 08:56
  • you mean that we do not need `bcpkix-jdk15on` ? – Hosein Aqajani May 21 '16 at 09:45
4

PKCS#7 is known as CMS now (Cryptographic Message Syntax), and you will need the Bouncy Castle PKIX libraries to create one. It has ample documentation and a well established mailing list.

I won't supply code snippet, it is against house rules. Try yourself first.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263