Wednesday, April 1, 2015

Create CMS Signature using Bouncy Castle

P
This post today will show you guys how to generate Cryptographic Message Syntax (CMS) signature. CMS is the IETF's standard for cryptographically protected messages. It can be used to digitally sign, digest, authenticate or encrypt any form of digital data. CMS is based on the syntax of PKCS#7 standard.
In this tutorial, I will use Bouncy Castle (BC) library. BC is a strong cryptographic library in Java, it has enough API to do this. The version of BC I am going to use is 1.47, you can download and use this version or higher at bouncycastle.org.

Keystore is used in this post is in PKCS#12 format

String passwordP12 = "p12KeystorePass";
String pathToP12 = "/path/to/your.p12";

OK, there is complete sample

package com.it4shared.pkcs7;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;

import javax.xml.bind.DatatypeConverter;

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 {

    public PKCS7Signer() {
    }

    public KeyStore loadKeyStore(String path, String password) throws Exception {

        KeyStore keystore = KeyStore.getInstance("PKCS12");
        InputStream is = new FileInputStream(path);
        keystore.load(is, password.toCharArray());
        return keystore;
    }

    public CMSSignedDataGenerator setUpProvider(final KeyStore keystore, String pkcs12Password, String algorithm) throws Exception {
     
     Enumeration e = keystore.aliases();
     String aliasName="";
        while(e.hasMoreElements())
        {
         aliasName = e.nextElement().toString();
        }
     
     Security.addProvider(new BouncyCastleProvider());

        Certificate[] certchain = (Certificate[]) keystore.getCertificateChain(aliasName);
        
        final List certlist = new ArrayList();

        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(aliasName);
        
        ContentSigner signer = new JcaContentSignerBuilder(algorithm).setProvider("BC").
                build((PrivateKey)(keystore.getKey(aliasName, pkcs12Password.toCharArray())));
        CMSSignedDataGenerator generator = new CMSSignedDataGenerator();

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

        generator.addCertificates(certstore);

        return generator;
    }

    public String SignData(final byte[] content, final CMSSignedDataGenerator generator) throws Exception {

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

    public static void main(String[] args) throws Exception {
        String passwordP12 = "p12KeystorePass";
        String pathToP12 = "/path/to/your.p12";
        String algorithm = "SHA1withRSA";
        
        PKCS7Signer signer = new PKCS7Signer();
        KeyStore keyStore = signer.loadKeyStore(pathToP12, passwordP12);
        
        CMSSignedDataGenerator signatureGenerator = signer.setUpProvider(keyStore, passwordP12, algorithm);
        String content = "signdata";
        String signedData = signer.SignData(content.getBytes("UTF-8"), signatureGenerator);
        System.out.println(signedData);
    }
To create detached signature
CMSSignedData signeddata = generator.generate(cmsdata, false);
Output:
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

No comments:

Post a Comment