org.xdi.util.security.StringEncrypter.java Source code

Java tutorial

Introduction

Here is the source code for org.xdi.util.security.StringEncrypter.java

Source

/*
 * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text.
 *
 * Copyright (c) 2014, Gluu
 */

package org.xdi.util.security;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.KeySpec;
import java.util.concurrent.locks.ReentrantLock;

import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.DESedeKeySpec;

import org.apache.commons.codec.binary.Base64;
import org.apache.log4j.Logger;
import org.xdi.util.Util;

/**
 * Encryption algorithms
 * 
 * @author ssudala
 */
public class StringEncrypter {

    private static final Logger log = Logger.getLogger(StringEncrypter.class);
    private final ReentrantLock lock = new ReentrantLock();

    // lazy init via static holder
    private static class Holder {
        static final StringEncrypter instance = createInstance();

        private static StringEncrypter createInstance() {
            try {
                return new StringEncrypter(StringEncrypter.DESEDE_ENCRYPTION_SCHEME);
            } catch (EncryptionException e) {
                log.error("Failed to create default StringEncrypter instance", e);
                return null;
            }
        }
    }

    public static StringEncrypter defaultInstance() throws EncryptionException {
        return Holder.instance;
    }

    public static StringEncrypter instance(String encryptionKey) throws EncryptionException {
        return new StringEncrypter(StringEncrypter.DESEDE_ENCRYPTION_SCHEME, encryptionKey);
    }

    /**
     * Exception thrown from encryption failures
     * 
     * @author ssudala
     */
    public static class EncryptionException extends Exception {
        /**
         * Serial UID
         */
        private static final long serialVersionUID = -7220454928814292801L;

        /**
         * Default constructor
         * 
         * @param t
         *            Wrapped exception
         */
        public EncryptionException(final Throwable t) {
            super(t);
        }
    }

    /**
     * Default encryption key
     */
    public static final String DEFAULT_ENCRYPTION_KEY = "This is a fairly long phrase used to encrypt";

    /**
     * DES encryption scheme
     */
    public static final String DES_ENCRYPTION_SCHEME = "DES";

    /**
     * Desede encryption scheme
     */
    public static final String DESEDE_ENCRYPTION_SCHEME = "DESede";

    /**
     * Unicode format
     */
    private static final String UNICODE_FORMAT = "UTF8";

    /**
     * Convert a byte stream to a string
     * 
     * @param bytes
     *            Byte stream
     * @return String representation
     */
    private static String bytes2String(final byte[] bytes) {
        final StringBuffer stringBuffer = new StringBuffer();
        for (final byte element : bytes) {
            stringBuffer.append((char) element);
        }
        return stringBuffer.toString();
    }

    /**
     * Cipher being used
     */
    private Cipher cipher;

    /**
     * Key factory being used
     */
    private SecretKeyFactory keyFactory;

    /**
     * Key spec being used
     */
    private KeySpec keySpec;

    private Base64 base64 = new Base64();

    /**
     * Constructor specifying scheme and key
     * 
     * @param encryptionScheme
     *            Encryption scheme to use
     * @param encryptionKey
     *            Encryption key to use
     * @throws EncryptionException
     */
    public StringEncrypter(final String encryptionScheme) throws EncryptionException {
        try {
            keyFactory = SecretKeyFactory.getInstance(encryptionScheme);
            cipher = Cipher.getInstance(encryptionScheme);
        } catch (final NoSuchAlgorithmException e) {
            throw new EncryptionException(e);
        } catch (final NoSuchPaddingException e) {
            throw new EncryptionException(e);
        }
    }

    /**
     * Constructor specifying scheme and key
     * 
     * @param encryptionScheme
     *            Encryption scheme to use
     * @param encryptionKey
     *            Encryption key to use
     * @throws EncryptionException
     */
    public StringEncrypter(final String encryptionScheme, final String encryptionKey) throws EncryptionException {
        if (encryptionKey == null) {
            throw new IllegalArgumentException("encryption key was null");
        }
        if (encryptionKey.trim().length() < 24) {
            throw new IllegalArgumentException("encryption key was less than 24 characters");
        }

        try {
            final byte[] keyAsBytes = encryptionKey.getBytes(StringEncrypter.UNICODE_FORMAT);

            if (encryptionScheme.equalsIgnoreCase(StringEncrypter.DESEDE_ENCRYPTION_SCHEME)) {
                keySpec = new DESedeKeySpec(keyAsBytes);
            } else if (encryptionScheme.equalsIgnoreCase(StringEncrypter.DES_ENCRYPTION_SCHEME)) {
                keySpec = new DESKeySpec(keyAsBytes);
            } else {
                throw new IllegalArgumentException("Encryption scheme not supported: " + encryptionScheme);
            }

            keyFactory = SecretKeyFactory.getInstance(encryptionScheme);
            cipher = Cipher.getInstance(encryptionScheme);
        } catch (final InvalidKeyException e) {
            throw new EncryptionException(e);
        } catch (final UnsupportedEncodingException e) {
            throw new EncryptionException(e);
        } catch (final NoSuchAlgorithmException e) {
            throw new EncryptionException(e);
        } catch (final NoSuchPaddingException e) {
            throw new EncryptionException(e);
        }
    }

    private String decrypt(final String encryptedString, KeySpec keySpec) throws EncryptionException {
        if (keySpec == null) {
            throw new IllegalArgumentException("keySpec was null or empty");
        }

        if ((encryptedString == null) || (encryptedString.trim().length() <= 0)) {
            throw new IllegalArgumentException("encrypted string was null or empty");
        }

        try {
            final SecretKey key = keyFactory.generateSecret(keySpec);
            cipher.init(Cipher.DECRYPT_MODE, key);

            final byte[] cleartext = base64.decode(encryptedString.getBytes(Util.UTF8));
            final byte[] ciphertext = cipher.doFinal(cleartext);

            return StringEncrypter.bytes2String(ciphertext);
        } catch (final Exception e) {
            throw new EncryptionException(e);
        }
    }

    /**
     * Decrypt a string encrypted with this encrypter
     * 
     * @param encryptedString
     *            Encrypted string
     * @return Decrypted string
     * @throws EncryptionException
     */
    public String decrypt(final String encryptedString) throws EncryptionException {
        lock.lock();
        try {
            return decrypt(encryptedString, keySpec);
        } finally {
            lock.unlock();
        }
    }

    /**
     * Decrypt a string encrypted with this encrypter
     * 
     * @param encryptedString
     *            Encrypted string
     * @return Decrypted string
     * @throws EncryptionException
     */
    public String decrypt(final String encryptedString, String encryptionKey) throws EncryptionException {
        lock.lock();
        try {
            final byte[] keyAsBytes = encryptionKey.getBytes(StringEncrypter.UNICODE_FORMAT);
            String encryptionScheme = StringEncrypter.DESEDE_ENCRYPTION_SCHEME;
            KeySpec keySpec;
            if (encryptionScheme.equalsIgnoreCase(StringEncrypter.DESEDE_ENCRYPTION_SCHEME)) {
                keySpec = new DESedeKeySpec(keyAsBytes);
            } else if (encryptionScheme.equalsIgnoreCase(StringEncrypter.DES_ENCRYPTION_SCHEME)) {
                keySpec = new DESKeySpec(keyAsBytes);
            } else {
                throw new IllegalArgumentException("Encryption scheme not supported: " + encryptionScheme);
            }
            return decrypt(encryptedString, keySpec);
        } catch (final Exception e) {
            throw new EncryptionException(e);
        } finally {
            lock.unlock();
        }
    }

    private String encrypt(final String unencryptedString, KeySpec keySpec) throws EncryptionException {
        if (keySpec == null) {
            throw new IllegalArgumentException("keySpec was null or empty");
        }

        if ((unencryptedString == null) || (unencryptedString.trim().length() == 0)) {
            throw new IllegalArgumentException("unencrypted string was null or empty");
        }

        try {
            final SecretKey key = keyFactory.generateSecret(keySpec);
            cipher.init(Cipher.ENCRYPT_MODE, key);
            final byte[] cleartext = unencryptedString.getBytes(StringEncrypter.UNICODE_FORMAT);
            final byte[] ciphertext = cipher.doFinal(cleartext);

            return new String(base64.encode(ciphertext), Util.UTF8);
        } catch (final Exception e) {
            throw new EncryptionException(e);
        }
    }

    /**
     * Encrypt a string
     * 
     * @param unencryptedString
     *            String to encrypt
     * @return Encrypted string (using scheme and key specified at construction)
     * @throws EncryptionException
     */
    public String encrypt(final String unencryptedString) throws EncryptionException {
        lock.lock();
        try {
            return encrypt(unencryptedString, keySpec);
        } finally {
            lock.unlock();
        }
    }

    /**
     * Encrypt a string
     * 
     * @param unencryptedString
     *            String to encrypt
     * @return Encrypted string (using scheme and key specified at construction)
     * @throws EncryptionException
     */
    public String encrypt(final String unencryptedString, String encryptionKey) throws EncryptionException {
        lock.lock();
        try {
            final byte[] keyAsBytes = encryptionKey.getBytes(StringEncrypter.UNICODE_FORMAT);
            String encryptionScheme = StringEncrypter.DESEDE_ENCRYPTION_SCHEME;
            KeySpec keySpec;
            if (encryptionScheme.equalsIgnoreCase(StringEncrypter.DESEDE_ENCRYPTION_SCHEME)) {
                keySpec = new DESedeKeySpec(keyAsBytes);
            } else if (encryptionScheme.equalsIgnoreCase(StringEncrypter.DES_ENCRYPTION_SCHEME)) {
                keySpec = new DESKeySpec(keyAsBytes);
            } else {
                throw new IllegalArgumentException("Encryption scheme not supported: " + encryptionScheme);
            }

            return encrypt(unencryptedString, keySpec);
        } catch (final Exception e) {
            throw new EncryptionException(e);
        } finally {
            lock.unlock();
        }
    }

    /*
     * private String decrypt2(final String password){ final String
     * encryptionKey = "123456789012345678901234567890"; final String
     * encryptionScheme = StringEncrypter.DESEDE_ENCRYPTION_SCHEME;
     * 
     * try { final StringEncrypter encrypter = new StringEncrypter(
     * encryptionScheme, encryptionKey ); return encrypter.decrypt(password); }
     * catch (final EncryptionException e) { e.printStackTrace(); } return
     * "invalidpass"; }
     */
}