be.e_contract.mycarenet.etee.Sealer.java Source code

Java tutorial

Introduction

Here is the source code for be.e_contract.mycarenet.etee.Sealer.java

Source

/*
 * Java MyCareNet Project.
 * Copyright (C) 2013 e-Contract.be BVBA.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License version
 * 3.0 as published by the Free Software Foundation.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, see 
 * http://www.gnu.org/licenses/.
 */

package be.e_contract.mycarenet.etee;

import java.io.IOException;
import java.security.PrivateKey;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.List;

import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cms.CMSAlgorithm;
import org.bouncycastle.cms.CMSEnvelopedData;
import org.bouncycastle.cms.CMSEnvelopedDataGenerator;
import org.bouncycastle.cms.CMSException;
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.cms.jcajce.JceCMSContentEncryptorBuilder;
import org.bouncycastle.cms.jcajce.JceKeyTransRecipientInfoGenerator;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.util.PrivateKeyFactory;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.bc.BcRSAContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;

/**
 * eHealth end-to-end encryption sealer implementation.
 * 
 * @author Frank Cornelis
 * 
 */
public class Sealer {

    private final PrivateKey authenticationPrivateKey;
    private final X509Certificate authenticationCertificate;
    private final List<X509Certificate> destinationCertificates;

    public Sealer(PrivateKey authenticationPrivateKey, X509Certificate authenticationCertificate,
            X509Certificate destinationCertificate) {
        this.authenticationCertificate = authenticationCertificate;
        this.authenticationPrivateKey = authenticationPrivateKey;
        this.destinationCertificates = Collections.singletonList(destinationCertificate);
    }

    /**
     * Main constructor.
     * 
     * @param authenticationPrivateKey
     *            the eHealth authentication private key of the sender.
     * @param authenticationCertificate
     *            the eHealth authentication certificate of the sender.
     * @param destinationCertificates
     *            the eHealth encryption certificates of the recipients.
     */
    public Sealer(PrivateKey authenticationPrivateKey, X509Certificate authenticationCertificate,
            List<X509Certificate> destinationCertificates) {
        this.authenticationCertificate = authenticationCertificate;
        this.authenticationPrivateKey = authenticationPrivateKey;
        this.destinationCertificates = destinationCertificates;
    }

    /**
     * Seals the given data.
     * 
     * @param data
     * @return
     * @throws OperatorCreationException
     * @throws CertificateEncodingException
     * @throws CMSException
     * @throws IOException
     */
    public byte[] seal(byte[] data)
            throws OperatorCreationException, CertificateEncodingException, CMSException, IOException {
        byte[] innerSignedData = sign(data, false);
        byte[] encryptedData = encrypt(innerSignedData);
        byte[] outerSignedData = sign(encryptedData, true);
        return outerSignedData;
    }

    private byte[] encrypt(byte[] data) throws CertificateEncodingException, CMSException, IOException {
        CMSEnvelopedDataGenerator cmsEnvelopedDataGenerator = new CMSEnvelopedDataGenerator();
        for (X509Certificate destinationCertificate : this.destinationCertificates) {
            cmsEnvelopedDataGenerator
                    .addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(destinationCertificate)
                            .setProvider(BouncyCastleProvider.PROVIDER_NAME));
        }
        CMSTypedData cmsTypedData = new CMSProcessableByteArray(data);
        CMSEnvelopedData cmsEnvelopedData = cmsEnvelopedDataGenerator.generate(cmsTypedData,
                new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC)
                        .setProvider(BouncyCastleProvider.PROVIDER_NAME).build());
        return cmsEnvelopedData.getEncoded();
    }

    private byte[] sign(byte[] data, boolean includeCertificate)
            throws OperatorCreationException, CertificateEncodingException, CMSException, IOException {
        CMSSignedDataGenerator cmsSignedDataGenerator = new CMSSignedDataGenerator();
        AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA1withRSA");
        AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
        AsymmetricKeyParameter privKeyParams = PrivateKeyFactory
                .createKey(this.authenticationPrivateKey.getEncoded());
        ContentSigner contentSigner = new BcRSAContentSignerBuilder(sigAlgId, digAlgId).build(privKeyParams);
        cmsSignedDataGenerator.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(
                new JcaDigestCalculatorProviderBuilder().setProvider(BouncyCastleProvider.PROVIDER_NAME).build())
                        .build(contentSigner, this.authenticationCertificate));
        if (includeCertificate) {
            cmsSignedDataGenerator
                    .addCertificate(new X509CertificateHolder(this.authenticationCertificate.getEncoded()));
        }
        CMSTypedData cmsTypedData = new CMSProcessableByteArray(data);
        CMSSignedData cmsSignedData = cmsSignedDataGenerator.generate(cmsTypedData, true);
        return cmsSignedData.getEncoded();
    }
}