org.silverpeas.util.crypto.CMSCipher.java Source code

Java tutorial

Introduction

Here is the source code for org.silverpeas.util.crypto.CMSCipher.java

Source

/**
 * Copyright (C) 2000 - 2013 Silverpeas
 *
 * This program is free software: you can redistribute it and/or modify it under the terms of the
 * GNU Affero General Public License as published by the Free Software Foundation, either version 3
 * of the License, or (at your option) any later version.
 *
 * As a special exception to the terms and conditions of version 3.0 of the GPL, you may
 * redistribute this Program in connection with Free/Libre Open Source Software ("FLOSS")
 * applications as described in Silverpeas's FLOSS exception. You should have received a copy of the
 * text describing the FLOSS exception, and it is also available here:
 * "http://www.silverpeas.org/docs/core/legal/floss_exception.html"
 *
 * This program 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
 * Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License along with this program.
 * If not, see <http://www.gnu.org/licenses/>.
 */
package org.silverpeas.util.crypto;

import org.bouncycastle.cms.CMSAlgorithm;
import org.bouncycastle.cms.CMSEnvelopedData;
import org.bouncycastle.cms.CMSEnvelopedDataGenerator;
import org.bouncycastle.cms.CMSProcessableByteArray;
import org.bouncycastle.cms.KeyTransRecipientInformation;
import org.bouncycastle.cms.RecipientInfoGenerator;
import org.bouncycastle.cms.jcajce.JceCMSContentEncryptorBuilder;
import org.bouncycastle.cms.jcajce.JceKeyTransEnvelopedRecipient;
import org.bouncycastle.cms.jcajce.JceKeyTransRecipientInfoGenerator;
import org.bouncycastle.operator.OutputEncryptor;
import org.silverpeas.util.Charsets;

import java.io.FileNotFoundException;
import java.util.Collection;

/**
 * The Cryptographic Message Syntax (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. It is based on the syntax of PKCS#7, which in turn is based on the Privacy-Enhanced Mail
 * standard. The newest version of CMS (as of 2009) is specified in RFC 5652 (but see also RFC 5911
 * for updated ASN.1 modules conforming to ASN.1 2002).
 * <p/>
 * The architecture of CMS is built around certificate-based key management, such as the profile
 * defined by the PKIX working group.
 * <p/>
 * CMS is used as the key cryptographic component of many other cryptographic standards, such as
 * S/MIME, PKCS#12 and the RFC 3161 Digital timestamping protocol.
 * <p/>
 * This implementation wraps the all the mechanism required to encrypt and to decrypt messages
 * within a PKS/CMS infrastructure. For doing it uses the public key, the secret key and the X509
 * certificate provided by a PKS#12 key store (an instance of the PKS12KeyStore class).
 * <p/>
 * Instances of this class is for signing and encrypting, and checking and decrypting data
 * exchanged
 * between two interlocutors.
 */
public class CMSCipher implements Cipher {

    protected CMSCipher() {
    }

    /**
     * Gets the name of the algorithm of the cipher.
     * @return the algorithm name.
     */
    @Override
    public CryptographicAlgorithmName getAlgorithmName() {
        return CryptographicAlgorithmName.CMS;
    }

    /**
     * Encrypts the specified data by using the specified cryptographic key.
     * <p/>
     * The String objects handled by the encryption is done according the UTF-8 charset.
     * @param data the data to encode.
     * @param keyFilePath the file in which is stored the public key to use in the encryption.
     * @return the encrypted data in bytes.
     */
    @Override
    public byte[] encrypt(String data, CipherKey keyFilePath) throws CryptoException {
        try {
            // Chargement de la chaine  crypter
            byte[] buffer = stringToByteArray(data);

            // Chiffrement du document
            CMSEnvelopedDataGenerator gen = new CMSEnvelopedDataGenerator();
            // La variable cert correspond au certificat du destinataire
            // La cl publique de ce certificat servira  chiffrer la cl
            // symtrique
            if (!keyFilePath.isInFile()) {
                throw new FileNotFoundException("The PKS#12 file '" + keyFilePath + "' doesn't exist!");
            }
            PKS12KeyStoreWallet wallet = PKS12KeyStoreWallet.getInstance();
            PKS12KeyStore keyStore = wallet.getKeyStore(keyFilePath.getKeyFilePath());
            RecipientInfoGenerator generator = new JceKeyTransRecipientInfoGenerator(keyStore.getCertificate())
                    .setProvider("BC");
            gen.addRecipientInfoGenerator(generator);

            // Choix de l'algorithme  cl symtrique pour chiffrer le document.
            // AES est un standard. Vous pouvez donc l'utiliser sans crainte.
            // Il faut savoir qu'en france la taille maximum autorise est de 128
            // bits pour les cls symtriques (ou cls secrtes)    
            OutputEncryptor encryptor = new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider("BC")
                    .build();
            CMSEnvelopedData envData = gen.generate(new CMSProcessableByteArray(buffer), encryptor);
            return envData.getEncoded();
        } catch (CryptoException e) {
            throw e;
        } catch (Exception e) {
            throw new CryptoException(CryptoException.ENCRYPTION_FAILURE, e);
        }
    }

    /**
     * Decrypt the specified code or cipher by using the specified cryptographic key.
     * <p/>
     * The String objects handled by the encryption is done according the UTF-8 charset.
     * @param encryptedData the data in bytes that was encrypted by this cipher.
     * @param keyFilePath the file in which is stored the secret key to use in the decryption.
     * @return the decrypted data.
     */
    @Override
    public String decrypt(byte[] encryptedData, CipherKey keyFilePath) throws CryptoException {
        try {
            // Dchiffrement de la chaine
            CMSEnvelopedData ced = new CMSEnvelopedData(encryptedData);
            @SuppressWarnings("unchecked")
            Collection<KeyTransRecipientInformation> recip = ced.getRecipientInfos().getRecipients();

            KeyTransRecipientInformation rinfo = recip.iterator().next();
            // privatekey est la cl prive permettant de dchiffrer la cl
            // secrte (symtrique)
            if (!keyFilePath.isInFile()) {
                throw new FileNotFoundException("The PKS#12 file '" + keyFilePath + "' doesn't exist!");
            }
            PKS12KeyStoreWallet wallet = PKS12KeyStoreWallet.getInstance();
            PKS12KeyStore keyStore = wallet.getKeyStore(keyFilePath.getKeyFilePath());
            byte[] contents = rinfo.getContent(new JceKeyTransEnvelopedRecipient(keyStore.getPrivatekey()));
            return byteArrayToString(contents);
        } catch (CryptoException e) {
            throw e;
        } catch (Exception e) {
            throw new CryptoException(CryptoException.DECRYPTION_FAILURE, e);
        }
    }

    private String byteArrayToString(byte[] bArray) {
        // A n'utiliser qu'avec des Strings dcrypts!!!
        return new String(bArray, Charsets.UTF_8);
    }

    private byte[] stringToByteArray(String theString) {
        return theString.getBytes(Charsets.UTF_8);
    }

    /**
     * This operation isn't yet supported by this cipher.
     * @return nothing, throws an UnsupportedOperationException exception.
     */
    @Override
    public CipherKey generateCipherKey() throws CryptoException {
        throw new UnsupportedOperationException("Not supported yet.");
    }
}