org.jamwiki.utils.Encryption.java Source code

Java tutorial

Introduction

Here is the source code for org.jamwiki.utils.Encryption.java

Source

/**
 * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE, version 2.1, dated February 1999.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the latest version of the GNU Lesser General
 * Public License as published by the Free Software Foundation;
 *
 * 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program (LICENSE.txt); if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package org.jamwiki.utils;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Properties;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import org.jamwiki.Environment;

/**
 * Provide capability for encrypting and decrypting values. Inspired by an
 * example from http://www.devx.com/assets/sourcecode/10387.zip.
 */
public class Encryption {

    private static final WikiLogger logger = WikiLogger.getLogger(Encryption.class.getName());
    public static final String DES_ALGORITHM = "DES";
    public static final String ENCRYPTION_KEY = "JAMWiki Key 12345";

    /**
     * Hide the constructor by making it private.
     */
    private Encryption() {
    }

    /**
     * Encrypt a String value using the DES encryption algorithm.
     * 
     * @param unencryptedBytes
     *          The unencrypted String value that is to be encrypted.
     * @return An encrypted version of the String that was passed to this method.
     */
    private static String encrypt64(byte[] unencryptedBytes)
            throws GeneralSecurityException, UnsupportedEncodingException {
        if (unencryptedBytes == null || unencryptedBytes.length == 0) {
            throw new IllegalArgumentException("Cannot encrypt a null or empty byte array");
        }
        SecretKey key = createKey();
        Cipher cipher = Cipher.getInstance(key.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, key);
        byte[] encryptedBytes = Base64.encodeBase64(cipher.doFinal(unencryptedBytes));
        return bytes2String(encryptedBytes);
    }

    /**
      *
      */
    public static String encrypt(String unencryptedString) {
        if (StringUtils.isBlank(unencryptedString)) {
            throw new IllegalArgumentException("Cannot encrypt a null or empty string");
        }
        MessageDigest md = null;
        String encryptionAlgorithm = Environment.getValue(Environment.PROP_ENCRYPTION_ALGORITHM);
        try {
            md = MessageDigest.getInstance(encryptionAlgorithm);
        } catch (NoSuchAlgorithmException e) {
            logger.warning("JDK does not support the " + encryptionAlgorithm
                    + " encryption algorithm.  Weaker encryption will be attempted.");
        }
        if (md == null) {
            // fallback to weaker encryption algorithm if nothing better is available
            try {
                md = MessageDigest.getInstance("SHA-1");
            } catch (NoSuchAlgorithmException e) {
                throw new UnsupportedOperationException(
                        "JDK does not support the SHA-1 or SHA-512 encryption algorithms");
            }
            // save the algorithm so that if the user upgrades the JDK they can
            // still use passwords encrypted with the weaker algorithm
            Environment.setValue(Environment.PROP_ENCRYPTION_ALGORITHM, "SHA-1");
            // trY {
            // ENVIRONMENT.SAVEPROPERTIES();
            // } CATCH (IOEXCEPTION E) {
            // LOGGER.INFO("FAILURE WHILE SAVING ENCRYPTION ALGORITHM PROPERTY", E);
            // }
        }
        try {
            md.update(unencryptedString.getBytes("UTF-8"));
            byte raw[] = md.digest();
            return encrypt64(raw);
        } catch (GeneralSecurityException e) {
            logger.severe("Encryption failure", e);
            throw new IllegalStateException("Failure while encrypting value");
        } catch (UnsupportedEncodingException e) {
            // this should never happen
            throw new IllegalStateException("Unsupporting encoding UTF-8");
        }
    }

    /**
     * Unencrypt a String value using the DES encryption algorithm.
     * 
     * @param encryptedString
     *          The encrypted String value that is to be unencrypted.
     * @return An unencrypted version of the String that was passed to this
     *         method.
     */
    private static String decrypt64(String encryptedString)
            throws GeneralSecurityException, UnsupportedEncodingException {
        if (StringUtils.isBlank(encryptedString)) {
            return encryptedString;
        }
        SecretKey key = createKey();
        Cipher cipher = Cipher.getInstance(key.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, key);
        byte[] encryptedBytes = encryptedString.getBytes("UTF8");
        byte[] unencryptedBytes = cipher.doFinal(Base64.decodeBase64(encryptedBytes));
        return bytes2String(unencryptedBytes);
    }

    /**
     * Convert a byte array to a String value.
     * 
     * @param bytes
     *          The byte array that is to be converted.
     * @return A String value created from the byte array that was passed to this
     *         method.
     */
    private static String bytes2String(byte[] bytes) {
        StringBuilder buffer = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            buffer.append((char) bytes[i]);
        }
        return buffer.toString();
    }

    /**
     * Create the encryption key value.
     * 
     * @return An encryption key value implementing the DES encryption algorithm.
     */
    private static SecretKey createKey() throws GeneralSecurityException, UnsupportedEncodingException {
        byte[] bytes = ENCRYPTION_KEY.getBytes("UTF8");
        DESKeySpec spec = new DESKeySpec(bytes);
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES_ALGORITHM);
        return keyFactory.generateSecret(spec);
    }

    /**
     * If a property value is encrypted, return the unencrypted value. Note that
     * if this method finds an un-encrypted value it will automatically encrypt it
     * and re-save it to the property file.
     * 
     * @param name
     *          The name of the encrypted property being retrieved.
     * @return The unencrypted value of the property.
     */
    public static String getEncryptedProperty(String name, Properties props) {
        try {
            if (props != null) {
                return Encryption.decrypt64(props.getProperty(name));
            }
            return Encryption.decrypt64(Environment.getValue(name));
        } catch (GeneralSecurityException e) {
            String value = Environment.getValue(name);
            if (props != null || StringUtils.isBlank(value)) {
                logger.severe("Encryption failure or no value available for property: " + name, e);
                throw new IllegalStateException("Failure while retrieving encrypted property: " + name);
            }
            // the property might have been unencrypted in the property file, so
            // encrypt, save, and return the value
            logger.warning("Found unencrypted property file value: " + name
                    + ".  Assuming that this value manually un-encrypted in the property file so re-encrypting and re-saving.");
            Encryption.setEncryptedProperty(name, value, null);
            // try {
            // Environment.saveProperties();
            // } catch (IOException ex) {
            // logger.severe("Failure while saving properties", ex);
            // throw new IllegalStateException("Failure while saving properties");
            // }
            return value;
        } catch (UnsupportedEncodingException e) {
            throw new IllegalStateException("Unsupporting encoding UTF-8");
        }
    }

    /**
     * Encrypt and set a property value.
     * 
     * @param name
     *          The name of the encrypted property being retrieved.
     * @param value
     *          The unenencrypted value of the property.
     * @param props
     *          The property object in which the property is being set.
     */
    public static void setEncryptedProperty(String name, String value, Properties props) {
        String encrypted = "";
        if (!StringUtils.isBlank(value)) {
            byte[] unencryptedBytes = null;
            try {
                unencryptedBytes = value.getBytes("UTF8");
                encrypted = Encryption.encrypt64(unencryptedBytes);
            } catch (GeneralSecurityException e) {
                logger.severe("Encryption failure", e);
                throw new IllegalStateException("Failure while encrypting value");
            } catch (UnsupportedEncodingException e) {
                // this should never happen
                throw new IllegalStateException("Unsupporting encoding UTF-8");
            }
        }
        if (props == null) {
            Environment.setValue(name, encrypted);
        } else {
            props.setProperty(name, encrypted);
        }
    }
}