001    /**
002     * Copyright (c) 2000-2013 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                    if (key == null) {
129                            if (_log.isWarnEnabled()) {
130                                    _log.warn("Skip encrypting based on a null key");
131                            }
132    
133                            return plainText;
134                    }
135    
136                    byte[] encryptedBytes = encryptUnencoded(key, plainText);
137    
138                    return Base64.encode(encryptedBytes);
139            }
140    
141            public static byte[] encryptUnencoded(Key key, byte[] plainBytes)
142                    throws EncryptorException {
143    
144                    String algorithm = key.getAlgorithm();
145    
146                    String cacheKey = algorithm.concat(StringPool.POUND).concat(
147                            key.toString());
148    
149                    Cipher cipher = _encryptCipherMap.get(cacheKey);
150    
151                    try {
152                            if (cipher == null) {
153                                    Security.addProvider(getProvider());
154    
155                                    cipher = Cipher.getInstance(algorithm);
156    
157                                    cipher.init(Cipher.ENCRYPT_MODE, key);
158    
159                                    _encryptCipherMap.put(cacheKey, cipher);
160                            }
161    
162                            synchronized (cipher) {
163                                    return cipher.doFinal(plainBytes);
164                            }
165                    }
166                    catch (Exception e) {
167                            throw new EncryptorException(e);
168                    }
169            }
170    
171            public static byte[] encryptUnencoded(Key key, String plainText)
172                    throws EncryptorException {
173    
174                    try {
175                            byte[] decryptedBytes = plainText.getBytes(ENCODING);
176    
177                            return encryptUnencoded(key, decryptedBytes);
178                    }
179                    catch (Exception e) {
180                            throw new EncryptorException(e);
181                    }
182            }
183    
184            public static Key generateKey() throws EncryptorException {
185                    return generateKey(KEY_ALGORITHM);
186            }
187    
188            public static Key generateKey(String algorithm) throws EncryptorException {
189                    try {
190                            Security.addProvider(getProvider());
191    
192                            KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm);
193    
194                            keyGenerator.init(KEY_SIZE, new SecureRandom());
195    
196                            Key key = keyGenerator.generateKey();
197    
198                            return key;
199                    }
200                    catch (Exception e) {
201                            throw new EncryptorException(e);
202                    }
203            }
204    
205            public static Provider getProvider()
206                    throws ClassNotFoundException, IllegalAccessException,
207                               InstantiationException {
208    
209                    Class<?> providerClass = null;
210    
211                    try {
212                            providerClass = Class.forName(PROVIDER_CLASS);
213                    }
214                    catch (ClassNotFoundException cnfe) {
215                            if (ServerDetector.isWebSphere() &&
216                                    PROVIDER_CLASS.equals(SUN_PROVIDER_CLASS)) {
217    
218                                    if (_log.isWarnEnabled()) {
219                                            _log.warn(
220                                                    "WebSphere does not have " + SUN_PROVIDER_CLASS +
221                                                            ", using " + IBM_PROVIDER_CLASS + " instead");
222                                    }
223    
224                                    providerClass = Class.forName(IBM_PROVIDER_CLASS);
225                            }
226                            else if (System.getProperty("java.vm.vendor").equals(
227                                                    "IBM Corporation")) {
228    
229                                    if (_log.isWarnEnabled()) {
230                                            _log.warn(
231                                                    "IBM JVM does not have " + SUN_PROVIDER_CLASS +
232                                                            ", using " + IBM_PROVIDER_CLASS + " instead");
233                                    }
234    
235                                    providerClass = Class.forName(IBM_PROVIDER_CLASS);
236                            }
237                            else {
238                                    throw cnfe;
239                            }
240                    }
241    
242                    return (Provider)providerClass.newInstance();
243            }
244    
245            private static Log _log = LogFactoryUtil.getLog(Encryptor.class);
246    
247            private static Map<String, Cipher> _decryptCipherMap =
248                    new ConcurrentHashMap<String, Cipher>(1, 1f, 1);
249            private static Map<String, Cipher> _encryptCipherMap =
250                    new ConcurrentHashMap<String, Cipher>(1, 1f, 1);
251    
252    }