001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.util;
016    
017    import com.liferay.portal.kernel.log.Log;
018    import com.liferay.portal.kernel.log.LogFactoryUtil;
019    import com.liferay.portal.kernel.util.Base64;
020    import com.liferay.portal.kernel.util.Digester;
021    import com.liferay.portal.kernel.util.DigesterUtil;
022    import com.liferay.portal.kernel.util.GetterUtil;
023    import com.liferay.portal.kernel.util.PropsKeys;
024    import com.liferay.portal.kernel.util.PropsUtil;
025    import com.liferay.portal.kernel.util.ServerDetector;
026    import com.liferay.portal.kernel.util.StringPool;
027    import com.liferay.portal.kernel.util.SystemProperties;
028    
029    import java.security.Key;
030    import java.security.Provider;
031    import java.security.SecureRandom;
032    import java.security.Security;
033    
034    import java.util.Map;
035    import java.util.concurrent.ConcurrentHashMap;
036    
037    import javax.crypto.Cipher;
038    import javax.crypto.KeyGenerator;
039    
040    /**
041     * @author Brian Wing Shun Chan
042     * @author Shuyang Zhou
043     */
044    public class Encryptor {
045    
046            public static final String ENCODING = Digester.ENCODING;
047    
048            public static final String IBM_PROVIDER_CLASS =
049                    "com.ibm.crypto.provider.IBMJCE";
050    
051            public static final String KEY_ALGORITHM = GetterUtil.getString(
052                    PropsUtil.get(PropsKeys.COMPANY_ENCRYPTION_ALGORITHM)).toUpperCase();
053    
054            public static final int KEY_SIZE = GetterUtil.getInteger(
055                    PropsUtil.get(PropsKeys.COMPANY_ENCRYPTION_KEY_SIZE));
056    
057            public static final String PROVIDER_CLASS = GetterUtil.getString(
058                    SystemProperties.get(Encryptor.class.getName() + ".provider.class"),
059                    Encryptor.SUN_PROVIDER_CLASS);
060    
061            public static final String SUN_PROVIDER_CLASS =
062                    "com.sun.crypto.provider.SunJCE";
063    
064            public static String decrypt(Key key, String encryptedString)
065                    throws EncryptorException {
066    
067                    byte[] encryptedBytes = Base64.decode(encryptedString);
068    
069                    return decryptUnencodedAsString(key, encryptedBytes);
070            }
071    
072            public static byte[] decryptUnencodedAsBytes(Key key, byte[] encryptedBytes)
073                    throws EncryptorException {
074    
075                    String algorithm = key.getAlgorithm();
076    
077                    String cacheKey = algorithm.concat(StringPool.POUND).concat(
078                            key.toString());
079    
080                    Cipher cipher = _decryptCipherMap.get(cacheKey);
081    
082                    try {
083                            if (cipher == null) {
084                                    Security.addProvider(getProvider());
085    
086                                    cipher = Cipher.getInstance(algorithm);
087    
088                                    cipher.init(Cipher.DECRYPT_MODE, key);
089    
090                                    _decryptCipherMap.put(cacheKey, cipher);
091                            }
092    
093                            synchronized (cipher) {
094                                    return cipher.doFinal(encryptedBytes);
095                            }
096                    }
097                    catch (Exception e) {
098                            throw new EncryptorException(e);
099                    }
100            }
101    
102            public static String decryptUnencodedAsString(
103                            Key key, byte[] encryptedBytes)
104                    throws EncryptorException {
105    
106                    try {
107                            byte[] decryptedBytes = decryptUnencodedAsBytes(
108                                    key, encryptedBytes);
109    
110                            return new String(decryptedBytes, ENCODING);
111                    }
112                    catch (Exception e) {
113                            throw new EncryptorException(e);
114                    }
115            }
116    
117            public static String digest(String text) {
118                    return DigesterUtil.digest(text);
119            }
120    
121            public static String digest(String algorithm, String text) {
122                    return DigesterUtil.digest(algorithm, text);
123            }
124    
125            public static String encrypt(Key key, String plainText)
126                    throws EncryptorException {
127    
128                    byte[] encryptedBytes = encryptUnencoded(key, plainText);
129    
130                    return Base64.encode(encryptedBytes);
131            }
132    
133            public static byte[] encryptUnencoded(Key key, byte[] plainBytes)
134                    throws EncryptorException {
135    
136                    String algorithm = key.getAlgorithm();
137    
138                    String cacheKey = algorithm.concat(StringPool.POUND).concat(
139                            key.toString());
140    
141                    Cipher cipher = _encryptCipherMap.get(cacheKey);
142    
143                    try {
144                            if (cipher == null) {
145                                    Security.addProvider(getProvider());
146    
147                                    cipher = Cipher.getInstance(algorithm);
148    
149                                    cipher.init(Cipher.ENCRYPT_MODE, key);
150    
151                                    _encryptCipherMap.put(cacheKey, cipher);
152                            }
153    
154                            synchronized (cipher) {
155                                    return cipher.doFinal(plainBytes);
156                            }
157                    }
158                    catch (Exception e) {
159                            throw new EncryptorException(e);
160                    }
161            }
162    
163            public static byte[] encryptUnencoded(Key key, String plainText)
164                    throws EncryptorException {
165    
166                    try {
167                            byte[] decryptedBytes = plainText.getBytes(ENCODING);
168    
169                            return encryptUnencoded(key, decryptedBytes);
170                    }
171                    catch (Exception e) {
172                            throw new EncryptorException(e);
173                    }
174            }
175    
176            public static Key generateKey() throws EncryptorException {
177                    return generateKey(KEY_ALGORITHM);
178            }
179    
180            public static Key generateKey(String algorithm) throws EncryptorException {
181                    try {
182                            Security.addProvider(getProvider());
183    
184                            KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm);
185    
186                            keyGenerator.init(KEY_SIZE, new SecureRandom());
187    
188                            Key key = keyGenerator.generateKey();
189    
190                            return key;
191                    }
192                    catch (Exception e) {
193                            throw new EncryptorException(e);
194                    }
195            }
196    
197            public static Provider getProvider()
198                    throws ClassNotFoundException, IllegalAccessException,
199                               InstantiationException {
200    
201                    Class<?> providerClass = null;
202    
203                    try {
204                            providerClass = Class.forName(PROVIDER_CLASS);
205                    }
206                    catch (ClassNotFoundException cnfe) {
207                            if ((ServerDetector.isWebSphere()) &&
208                                    (PROVIDER_CLASS.equals(SUN_PROVIDER_CLASS))) {
209    
210                                    if (_log.isWarnEnabled()) {
211                                            _log.warn(
212                                                    "WebSphere does not have " + SUN_PROVIDER_CLASS +
213                                                            ", using " + IBM_PROVIDER_CLASS + " instead");
214                                    }
215    
216                                    providerClass = Class.forName(IBM_PROVIDER_CLASS);
217                            }
218                            else if (System.getProperty("java.vm.vendor").equals(
219                                                    "IBM Corporation")) {
220    
221                                    if (_log.isWarnEnabled()) {
222                                            _log.warn(
223                                                    "IBM JVM does not have " + SUN_PROVIDER_CLASS +
224                                                            ", using " + IBM_PROVIDER_CLASS + " instead");
225                                    }
226    
227                                    providerClass = Class.forName(IBM_PROVIDER_CLASS);
228                            }
229                            else {
230                                    throw cnfe;
231                            }
232                    }
233    
234                    return (Provider)providerClass.newInstance();
235            }
236    
237            private static Log _log = LogFactoryUtil.getLog(Encryptor.class);
238    
239            private static Map<String, Cipher> _decryptCipherMap =
240                    new ConcurrentHashMap<String, Cipher>(1, 1f, 1);
241            private static Map<String, Cipher> _encryptCipherMap =
242                    new ConcurrentHashMap<String, Cipher>(1, 1f, 1);
243    
244    }