com.jaspersoft.jasperserver.api.metadata.common.service.impl.Cipherer.java Source code

Java tutorial

Introduction

Here is the source code for com.jaspersoft.jasperserver.api.metadata.common.service.impl.Cipherer.java

Source

/*
 * Copyright (C) 2005 - 2014 TIBCO Software Inc. All rights reserved.
 * http://www.jaspersoft.com.
 *
 * Unless you have purchased  a commercial license agreement from Jaspersoft,
 * the following license terms  apply:
 *
 * 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.
 *
 * 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 com.jaspersoft.jasperserver.api.metadata.common.service.impl;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.spec.AlgorithmParameterSpec;

/**
 * This class provides the utilities of a cryptographic cipher for encryption and decryption.
 *
 */
public class Cipherer implements InitializingBean {

    private static Log log = LogFactory.getLog(Cipherer.class);

    private static final byte[] DEFAULT_KEY_BYTES = { (byte) 0xC8, (byte) 0x43, (byte) 0x29, (byte) 0x49,
            (byte) 0xAE, (byte) 0x25, (byte) 0x2F, (byte) 0xA1, (byte) 0xC1, (byte) 0xF2, (byte) 0xC8, (byte) 0xD9,
            (byte) 0x31, (byte) 0x01, (byte) 0x2C, (byte) 0x52, (byte) 0x54, (byte) 0x0B, (byte) 0x5E, (byte) 0xEA,
            (byte) 0x9E, (byte) 0x37, (byte) 0xA8, (byte) 0x61 };

    //Create an 8-byte initialization vector
    //TODO Static IV is bad
    private static final byte[] INIT_VECTOR_8 = { (byte) 0x8E, (byte) 0x12, (byte) 0x39, (byte) 0x9C, (byte) 0x07,
            (byte) 0x72, (byte) 0x6F, (byte) 0x5A };
    //   private static final Random NONCE_GEN = new SecureRandom(SecureRandom.getSeed(16));

    //Create an 16-byte initialization vector
    private static final byte[] INIT_VECTOR_16 = { (byte) 0x8b, (byte) 0x48, (byte) 0x10, (byte) 0x03, (byte) 0x5d,
            (byte) 0xdf, (byte) 0xf9, (byte) 0xac, (byte) 0x17, (byte) 0xf2, (byte) 0xbd, (byte) 0x64, (byte) 0xb7,
            (byte) 0x51, (byte) 0xc0, (byte) 0x29 };

    private Cipher E_CIPHER = null;
    private Cipher D_CIPHER = null;

    private static final String DEFAULT_CIPHER_TRANSFORMATION = "DESede/CBC/PKCS5Padding";
    private static final String DEFAULT_KEY_ALGORITHM = "DESede";

    private byte[] keyBytes;
    private String cipherTransformation;
    private String keyAlgorithm;

    /**
     * 
     */
    public Cipherer() {
        keyBytes = DEFAULT_KEY_BYTES;
        cipherTransformation = DEFAULT_CIPHER_TRANSFORMATION;
        keyAlgorithm = DEFAULT_KEY_ALGORITHM;
    }

    /**
     * Initializes the encoder and decoder with the given parameters
    *
     * @param isPlainText
     */
    public void init(String inCipherTransformation, String inKeyAlgorithm, String inKeyBytes, boolean isPlainText) {
        cipherTransformation = inCipherTransformation;
        keyAlgorithm = inKeyAlgorithm;
        setKeyBytes(inKeyBytes, isPlainText);
        init();
    }

    /**
    * Initializes the encoder and decoder. 
    * Note: The vaues of CIPHER_TRANSFORMATION, KEY_BYTES, KEY_ALGORITHM should be set before calling this method,
    *       otherwise it will use the default values.
    */
    public void init() {
        try {
            /*
                     byte[] nonce = new byte[16];
                     NONCE_GEN.nextBytes(nonce);
                     AlgorithmParameterSpec paramSpec = new IvParameterSpec(nonce);
            */
            AlgorithmParameterSpec paramSpec = cipherTransformation.toUpperCase().startsWith("AES")
                    ? new IvParameterSpec(INIT_VECTOR_16)
                    : new IvParameterSpec(INIT_VECTOR_8);

            E_CIPHER = Cipher.getInstance(cipherTransformation);
            D_CIPHER = Cipher.getInstance(cipherTransformation);

            SecretKeySpec spec = new SecretKeySpec(keyBytes, keyAlgorithm);

            // CBC requires an initialization vector
            E_CIPHER.init(Cipher.ENCRYPT_MODE, spec, paramSpec);
            D_CIPHER.init(Cipher.DECRYPT_MODE, spec, paramSpec);
        } catch (Exception e) {
            log.error("Cipher init failed", e);
            throw new RuntimeException(e);
        }
    }

    /** Encodes and hexifies the given content */
    public String encode(String content) {
        try {
            if (content == null)
                content = "";
            return hexify(encode(content.getBytes("UTF-8")));
        } catch (Exception ex) {
            log.warn("Unsuccessfull password encryption", ex);
            return hexify(encode(content.getBytes()));
        }
    }

    /** Encodes the given content*/
    public byte[] encode(byte[] content) {
        try {
            return E_CIPHER.doFinal(content);
        } catch (Exception ex) {
            log.warn("Unsuccessfull password decryption", ex);
            return content;
        }
    }

    /** Dehexifies and decodes the given content
     * * @param content string to be decoded
     * @return the decoded content.
     */
    public String decode(String content) {
        try {
            if (content == null)
                return null;
            return new String(decode(dehexify(content)), "UTF-8");
        } catch (Exception ex) {
            log.warn("Password decrypted unsuccesfully.", ex);
            return new String(decode(dehexify(content)));
        }
    }

    /** Decodes the given content*/
    public byte[] decode(byte[] content) {
        try {
            return D_CIPHER.doFinal(content);
        } catch (Exception ex) {
            log.warn("Unsuccessfull password decryption", ex);
            return content;
        }
    }

    /**
     * Decodes the given content if the booleanValue is "true" (case insensitive). 
     * (Utility Function) 
     * @param content string to be decoded
     * @param booleanValue specifies whether content needs to be decoded
     * @return the decoded content if the booleanValue is "true" (case insensitive). Otherwise it just returns content.
     */
    public String decode(String content, Object booleanValue) {
        if ((booleanValue == null) || !(booleanValue instanceof String) || (content == null))
            return content;
        boolean isEncrypted = new Boolean((String) booleanValue).booleanValue();
        if (isEncrypted)
            return decode(content);
        return content;
    }

    //
    // used in hexifying
    //
    private static final char[] hexChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D',
            'E', 'F' };

    /**
     * Convert a byte array response to a hex string
     */
    public static String hexify(byte[] data) {
        StringBuffer hex = new StringBuffer();

        for (int i = 0; i < data.length; i++) {
            int highBits = ((int) data[i] & 0x000000F0) >> 4;
            int lowBits = ((int) data[i] & 0x0000000F);
            hex.append(hexChars[highBits]).append(hexChars[lowBits]);
        }

        return (hex.toString());
    }

    /**
     * Convert a hex string response to a byte array
     */
    public static byte[] dehexify(String data) {
        byte[] bytes = new byte[data.length() / 2];

        for (int i = 0; i < bytes.length; i++) {
            bytes[i] = (byte) Integer.parseInt(data.substring(2 * i, (2 * i) + 2), 16);
        }

        return bytes;
    }

    /**
     * @param inKeyBytes The KEY_BYTES to set.
     * @param isPlainText Whether key_bytes is plain text or a represantation of byte sequence
     */
    public void setKeyBytes(String inKeyBytes, boolean isPlainText) {
        if (isPlainText) {
            keyBytes = inKeyBytes.getBytes();
        } else {
            setKeyBytes(inKeyBytes);
        }

    }

    public void setKeyBytes(String inKeyBytes) {
        String[] keyStringArr = inKeyBytes.split("\\s+");
        keyBytes = new byte[keyStringArr.length];
        for (int i = 0; i < keyStringArr.length; i++) {
            keyBytes[i] = Integer.decode(keyStringArr[i]).byteValue();
        }
    }

    /**
     * @param cipherTransformation The cipherTransformation to set.
     */
    public void setCipherTransformation(String cipherTransformation) {
        this.cipherTransformation = cipherTransformation;
    }

    /**
     * @param keyAlgorithm The keyAlgorithm to set.
     */
    public void setKeyAlgorithm(String keyAlgorithm) {
        this.keyAlgorithm = keyAlgorithm;
    }

    /**
     * Invoked by a BeanFactory after it has set all bean properties supplied
     * (and satisfied BeanFactoryAware and ApplicationContextAware).
     * <p>This method allows the bean instance to perform initialization only
     * possible when all bean properties have been set and to throw an
     * exception in the event of misconfiguration.
     *
     * @throws Exception in the event of misconfiguration (such
     *                   as failure to set an essential property) or if initialization fails.
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        Assert.notNull(this.keyBytes, "keyBytes has not been set in " + Cipherer.class);
        Assert.notNull(this.keyAlgorithm, "keyAlgorithm has not been set in " + Cipherer.class);
        Assert.notNull(this.cipherTransformation, "cipherTransformation has not been set in " + Cipherer.class);
        init();
    }
}