001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2013-2016 ForgeRock AS.
015 */
016
017package org.forgerock.json.jose.jwe.handlers.encryption;
018
019import java.security.GeneralSecurityException;
020import java.security.InvalidAlgorithmParameterException;
021import java.security.InvalidKeyException;
022import java.security.Key;
023import java.security.NoSuchAlgorithmException;
024import java.util.logging.Level;
025import java.util.logging.Logger;
026
027import javax.crypto.BadPaddingException;
028import javax.crypto.Cipher;
029import javax.crypto.IllegalBlockSizeException;
030import javax.crypto.NoSuchPaddingException;
031import javax.crypto.spec.IvParameterSpec;
032import javax.crypto.spec.SecretKeySpec;
033
034import org.forgerock.json.jose.exceptions.JweDecryptionException;
035import org.forgerock.json.jose.exceptions.JweEncryptionException;
036
037/**
038 * A base implementation of an EncryptionHandler that provides common encryption and decryption methods for all
039 * concrete EncryptionHandler implementations.
040 *
041 * @since 2.0.0
042 * @deprecated Use {@link ContentEncryptionHandler} instead.
043 */
044@Deprecated
045public abstract class AbstractEncryptionHandler implements EncryptionHandler {
046    private static final Logger LOGGER = Logger.getLogger(AbstractEncryptionHandler.class.getName());
047
048    /**
049     * Encrypts the given plaintext using the specified key with the specified encryption algorithm.
050     *
051     * @param algorithm The Java Cryptographic encryption algorithm.
052     * @param key The encryption key.
053     * @param data The data to encrypt.
054     * @return An array of bytes representing the encrypted data.
055     */
056    protected byte[] encrypt(String algorithm, Key key, byte[] data) {
057        try {
058            Cipher cipher = Cipher.getInstance(algorithm);
059            cipher.init(Cipher.ENCRYPT_MODE, key);
060            return cipher.doFinal(data);
061        } catch (NoSuchAlgorithmException e) {
062            throw new JweEncryptionException("Unsupported Encryption Algorithm, " + algorithm, e);
063        } catch (IllegalBlockSizeException | InvalidKeyException | NoSuchPaddingException | BadPaddingException e) {
064            throw new JweEncryptionException(e);
065        }
066    }
067
068    /**
069     * Encrypts the given plaintext using the specified key and initialisation vector with the specified encryption
070     * algorithm.
071     *
072     * @param algorithm The Java Cryptographic encryption algorithm.
073     * @param key The encryption key.
074     * @param initialisationVector The initialisation vector.
075     * @param data The data to encrypt.
076     * @return An array of bytes representing the encrypted data.
077     */
078    protected byte[] encrypt(String algorithm, Key key, byte[] initialisationVector, byte[] data) {
079
080        try {
081            Cipher cipher = Cipher.getInstance(algorithm);
082            SecretKeySpec secretKeySpec = new SecretKeySpec(key.getEncoded(), key.getAlgorithm());
083            IvParameterSpec ivParameterSpec = new IvParameterSpec(initialisationVector);
084            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
085            return cipher.doFinal(data);
086        } catch (NoSuchAlgorithmException e) {
087            throw new JweEncryptionException("Unsupported Encryption Algorithm, " + algorithm, e);
088        } catch (IllegalBlockSizeException | InvalidKeyException | NoSuchPaddingException | BadPaddingException
089                | InvalidAlgorithmParameterException e) {
090            throw new JweEncryptionException(e);
091        }
092    }
093
094    /**
095     * Decrypts the given ciphertext using the private key and with the same encryption algorithm that was used in the
096     * encryption.
097     *
098     * @param algorithm The Java Cryptographic encryption algorithm.
099     * @param privateKey The private key pair to the public key used in the encryption.
100     * @param data The ciphertext to decrypt.
101     * @return An array of bytes representing the decrypted data.
102     */
103    public byte[] decrypt(String algorithm, Key privateKey, byte[] data) {
104
105        try {
106            Cipher cipher = Cipher.getInstance(algorithm);
107            cipher.init(Cipher.DECRYPT_MODE, privateKey);
108            return cipher.doFinal(data);
109        } catch (GeneralSecurityException e) {
110            logDecryptionFailure(e);
111            throw new JweDecryptionException();
112        }
113    }
114
115    /**
116     * Decrypts the given ciphertext using the private key and initialisation vector with the same encryption algorithm
117     * that was used in the encryption.
118     *
119     * @param algorithm The Java Cryptographic encryption algorithm.
120     * @param key The private key pair to the public key used in the encryption.
121     * @param initialisationVector The same initialisation vector that was used in the encryption.
122     * @param data The ciphertext to decrypt.
123     * @return An array of bytes representing the decrypted data.
124     */
125    protected byte[] decrypt(String algorithm, Key key, byte[] initialisationVector, byte[] data) {
126
127        try {
128            Cipher cipher = Cipher.getInstance(algorithm);
129            SecretKeySpec secretKeySpec = new SecretKeySpec(key.getEncoded(), key.getAlgorithm());
130            IvParameterSpec ivParameterSpec = new IvParameterSpec(initialisationVector);
131            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
132            return cipher.doFinal(data);
133        } catch (GeneralSecurityException e) {
134            logDecryptionFailure(e);
135            throw new JweDecryptionException();
136        }
137    }
138
139    /**
140     * Log the root cause of any decryption error before throwing a generic exception.
141     */
142    private void logDecryptionFailure(Throwable cause) {
143        if (LOGGER.isLoggable(Level.FINE)) {
144            LOGGER.log(Level.FINE, "Decryption failed: " + cause, cause);
145        }
146    }
147}