org.projectforge.common.Crypt.java Source code

Java tutorial

Introduction

Here is the source code for org.projectforge.common.Crypt.java

Source

/////////////////////////////////////////////////////////////////////////////
//
// Project ProjectForge Community Edition
//         www.projectforge.org
//
// Copyright (C) 2001-2013 Kai Reinhard (k.reinhard@micromata.de)
//
// ProjectForge is dual-licensed.
//
// This community edition is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation; version 3 of the License.
//
// This community edition 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 General
// Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, see http://www.gnu.org/licenses/.
//
/////////////////////////////////////////////////////////////////////////////

package org.projectforge.common;

import java.io.UnsupportedEncodingException;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Security;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;
import org.apache.log4j.Logger;

/**
 * 
 * @author Wolfgang Jung (W.Jung@micromata.de)
 * @author Kai Reinhard (k.reinhard@micromata.de)
 * 
 */
public class Crypt {
    private final static Logger log = Logger.getLogger(Crypt.class);

    private static final String CRYPTO_ALGORITHM = "AES/ECB/PKCS5Padding";

    private static boolean initialized;

    /**
     * Encrypts the given str with AES. The password is first converted using SHA-256.
     * @param password
     * @param str
     * @return The base64 encoded result (url safe).
     */
    public static String encrypt(final String password, final String data) {
        initialize();
        try {
            // AES is sometimes not part of Java, therefore use bouncy castle provider:
            final Cipher cipher = Cipher.getInstance(CRYPTO_ALGORITHM);
            final byte[] keyValue = getPassword(password);
            final Key key = new SecretKeySpec(keyValue, "AES");
            cipher.init(Cipher.ENCRYPT_MODE, key);
            final byte[] encVal = cipher.doFinal(data.getBytes("UTF-8"));
            final String encryptedValue = Base64.encodeBase64URLSafeString(encVal);
            return encryptedValue;
        } catch (final Exception ex) {
            log.error("Exception encountered while trying to encrypt with Algorithm 'AES' and the given password: "
                    + ex.getMessage(), ex);
            return null;
        }
    }

    /**
     * @param password
     * @param encryptedString
     * @return
     */
    public static String decrypt(final String password, final String encryptedString) {
        initialize();
        try {
            final Cipher cipher = Cipher.getInstance(CRYPTO_ALGORITHM);
            final byte[] keyValue = getPassword(password);
            final Key key = new SecretKeySpec(keyValue, "AES");
            cipher.init(Cipher.DECRYPT_MODE, key);
            final byte[] decordedValue = Base64.decodeBase64(encryptedString);
            final byte[] decValue = cipher.doFinal(decordedValue);
            final String decryptedValue = new String(decValue, "UTF-8");
            return decryptedValue;
        } catch (final Exception ex) {
            log.error("Exception encountered while trying to encrypt with Algorithm 'AES' and the given password: "
                    + ex.getMessage(), ex);
            return null;
        }
    }

    private static byte[] getPassword(final String password) {
        try {
            final MessageDigest digester = MessageDigest.getInstance("MD5"); // 128 bit. 256 bit (SHA-256) doesn't work on Java versions without required security policy.
            digester.update(password.getBytes("UTF-8"));
            final byte[] key = digester.digest();
            return key;
        } catch (final NoSuchAlgorithmException ex) {
            log.error("Exception encountered while trying to create a MD5 password: " + ex.getMessage(), ex);
            return null;
        } catch (final UnsupportedEncodingException ex) {
            log.error("Exception encountered while trying to get bytes in UTF-8: " + ex.getMessage(), ex);
            return null;
        }
    }

    private static void initialize() {
        synchronized (log) {
            if (initialized == false) {
                Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
                initialized = true;
            }
        }
    }

    /**
     * Encrypts the given String via SHA crypt algorithm.
     * @param s
     * @return
     */
    public static String digest(final String s) {
        return encode(s, "SHA");
    }

    public static String digest(final String s, final String alg) {
        return encode(s, alg);
    }

    public static boolean check(final String pass, final String encoded) {
        final String alg = encoded.substring(0, encoded.indexOf('{'));
        return encoded.equals(encode(pass, alg));
    }

    private static String encode(final String s, final String alg) {
        try {
            final MessageDigest md = MessageDigest.getInstance(alg);
            md.reset();
            md.update(s.getBytes());
            final byte[] d = md.digest();

            String ret = "";

            for (int val : d) {
                final char[] hex = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C',
                        'D', 'E', 'F' };
                if (val < 0) {
                    val = 256 + val;
                }
                final char hi = hex[val / 16];
                final char lo = hex[val % 16];
                ret = hi + "" + lo + ret;
            }
            return md.getAlgorithm() + '{' + ret + '}';
        } catch (final NoSuchAlgorithmException ex) {
            log.fatal(ex);
            return "NONE{" + s + "}";
        }
    }
}