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.StringUtil;
028    import com.liferay.portal.kernel.util.SystemProperties;
029    
030    import java.security.Key;
031    import java.security.Provider;
032    import java.security.SecureRandom;
033    import java.security.Security;
034    
035    import java.util.Map;
036    import java.util.concurrent.ConcurrentHashMap;
037    
038    import javax.crypto.Cipher;
039    import javax.crypto.KeyGenerator;
040    
041    /**
042     * @author Brian Wing Shun Chan
043     * @author Shuyang Zhou
044     */
045    public class Encryptor {
046    
047            public static final String ENCODING = Digester.ENCODING;
048    
049            public static final String IBM_PROVIDER_CLASS =
050                    "com.ibm.crypto.provider.IBMJCE";
051    
052            public static final String KEY_ALGORITHM = StringUtil.toUpperCase(
053                    GetterUtil.getString(
054                            PropsUtil.get(PropsKeys.COMPANY_ENCRYPTION_ALGORITHM)));
055    
056            public static final int KEY_SIZE = GetterUtil.getInteger(
057                    PropsUtil.get(PropsKeys.COMPANY_ENCRYPTION_KEY_SIZE));
058    
059            public static final String PROVIDER_CLASS = GetterUtil.getString(
060                    SystemProperties.get(Encryptor.class.getName() + ".provider.class"),
061                    Encryptor.SUN_PROVIDER_CLASS);
062    
063            public static final String SUN_PROVIDER_CLASS =
064                    "com.sun.crypto.provider.SunJCE";
065    
066            public static String decrypt(Key key, String encryptedString)
067                    throws EncryptorException {
068    
069                    byte[] encryptedBytes = Base64.decode(encryptedString);
070    
071                    return decryptUnencodedAsString(key, encryptedBytes);
072            }
073    
074            public static byte[] decryptUnencodedAsBytes(Key key, byte[] encryptedBytes)
075                    throws EncryptorException {
076    
077                    String algorithm = key.getAlgorithm();
078    
079                    String cacheKey = algorithm.concat(StringPool.POUND).concat(
080                            key.toString());
081    
082                    Cipher cipher = _decryptCipherMap.get(cacheKey);
083    
084                    try {
085                            if (cipher == null) {
086                                    Security.addProvider(getProvider());
087    
088                                    cipher = Cipher.getInstance(algorithm);
089    
090                                    cipher.init(Cipher.DECRYPT_MODE, key);
091    
092                                    _decryptCipherMap.put(cacheKey, cipher);
093                            }
094    
095                            synchronized (cipher) {
096                                    return cipher.doFinal(encryptedBytes);
097                            }
098                    }
099                    catch (Exception e) {
100                            throw new EncryptorException(e);
101                    }
102            }
103    
104            public static String decryptUnencodedAsString(
105                            Key key, byte[] encryptedBytes)
106                    throws EncryptorException {
107    
108                    try {
109                            byte[] decryptedBytes = decryptUnencodedAsBytes(
110                                    key, encryptedBytes);
111    
112                            return new String(decryptedBytes, ENCODING);
113                    }
114                    catch (Exception e) {
115                            throw new EncryptorException(e);
116                    }
117            }
118    
119            public static String digest(String text) {
120                    return DigesterUtil.digest(text);
121            }
122    
123            public static String digest(String algorithm, String text) {
124                    return DigesterUtil.digest(algorithm, text);
125            }
126    
127            public static String encrypt(Key key, String plainText)
128                    throws EncryptorException {
129    
130                    if (key == null) {
131                            if (_log.isWarnEnabled()) {
132                                    _log.warn("Skip encrypting based on a null key");
133                            }
134    
135                            return plainText;
136                    }
137    
138                    byte[] encryptedBytes = encryptUnencoded(key, plainText);
139    
140                    return Base64.encode(encryptedBytes);
141            }
142    
143            public static byte[] encryptUnencoded(Key key, byte[] plainBytes)
144                    throws EncryptorException {
145    
146                    String algorithm = key.getAlgorithm();
147    
148                    String cacheKey = algorithm.concat(StringPool.POUND).concat(
149                            key.toString());
150    
151                    Cipher cipher = _encryptCipherMap.get(cacheKey);
152    
153                    try {
154                            if (cipher == null) {
155                                    Security.addProvider(getProvider());
156    
157                                    cipher = Cipher.getInstance(algorithm);
158    
159                                    cipher.init(Cipher.ENCRYPT_MODE, key);
160    
161                                    _encryptCipherMap.put(cacheKey, cipher);
162                            }
163    
164                            synchronized (cipher) {
165                                    return cipher.doFinal(plainBytes);
166                            }
167                    }
168                    catch (Exception e) {
169                            throw new EncryptorException(e);
170                    }
171            }
172    
173            public static byte[] encryptUnencoded(Key key, String plainText)
174                    throws EncryptorException {
175    
176                    try {
177                            byte[] decryptedBytes = plainText.getBytes(ENCODING);
178    
179                            return encryptUnencoded(key, decryptedBytes);
180                    }
181                    catch (Exception e) {
182                            throw new EncryptorException(e);
183                    }
184            }
185    
186            public static Key generateKey() throws EncryptorException {
187                    return generateKey(KEY_ALGORITHM);
188            }
189    
190            public static Key generateKey(String algorithm) throws EncryptorException {
191                    try {
192                            Security.addProvider(getProvider());
193    
194                            KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm);
195    
196                            keyGenerator.init(KEY_SIZE, new SecureRandom());
197    
198                            Key key = keyGenerator.generateKey();
199    
200                            return key;
201                    }
202                    catch (Exception e) {
203                            throw new EncryptorException(e);
204                    }
205            }
206    
207            public static Provider getProvider()
208                    throws ClassNotFoundException, IllegalAccessException,
209                               InstantiationException {
210    
211                    Class<?> providerClass = null;
212    
213                    try {
214                            providerClass = Class.forName(PROVIDER_CLASS);
215                    }
216                    catch (ClassNotFoundException cnfe) {
217                            if (ServerDetector.isWebSphere() &&
218                                    PROVIDER_CLASS.equals(SUN_PROVIDER_CLASS)) {
219    
220                                    if (_log.isWarnEnabled()) {
221                                            _log.warn(
222                                                    "WebSphere does not have " + SUN_PROVIDER_CLASS +
223                                                            ", using " + IBM_PROVIDER_CLASS + " instead");
224                                    }
225    
226                                    providerClass = Class.forName(IBM_PROVIDER_CLASS);
227                            }
228                            else if (System.getProperty("java.vm.vendor").equals(
229                                                    "IBM Corporation")) {
230    
231                                    if (_log.isWarnEnabled()) {
232                                            _log.warn(
233                                                    "IBM JVM does not have " + SUN_PROVIDER_CLASS +
234                                                            ", using " + IBM_PROVIDER_CLASS + " instead");
235                                    }
236    
237                                    providerClass = Class.forName(IBM_PROVIDER_CLASS);
238                            }
239                            else {
240                                    throw cnfe;
241                            }
242                    }
243    
244                    return (Provider)providerClass.newInstance();
245            }
246    
247            private static Log _log = LogFactoryUtil.getLog(Encryptor.class);
248    
249            private static Map<String, Cipher> _decryptCipherMap =
250                    new ConcurrentHashMap<String, Cipher>(1, 1f, 1);
251            private static Map<String, Cipher> _encryptCipherMap =
252                    new ConcurrentHashMap<String, Cipher>(1, 1f, 1);
253    
254    }