/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library 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 Lesser General Public License for more * details. */ package com.liferay.util; import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.kernel.util.Base64; import com.liferay.portal.kernel.util.Digester; import com.liferay.portal.kernel.util.DigesterUtil; import com.liferay.portal.kernel.util.GetterUtil; import com.liferay.portal.kernel.util.PropsKeys; import com.liferay.portal.kernel.util.PropsUtil; import com.liferay.portal.kernel.util.ServerDetector; import com.liferay.portal.kernel.util.StringPool; import com.liferay.portal.kernel.util.StringUtil; import com.liferay.portal.kernel.util.SystemProperties; import java.security.Key; import java.security.Provider; import java.security.SecureRandom; import java.security.Security; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.spec.SecretKeySpec; /** * @author Brian Wing Shun Chan * @author Shuyang Zhou * @see com.liferay.petra.encryptor.Encryptor */ public class Encryptor { public static final String ENCODING = Digester.ENCODING; public static final String IBM_PROVIDER_CLASS = "com.ibm.crypto.provider.IBMJCE"; public static final String KEY_ALGORITHM = StringUtil.toUpperCase( GetterUtil.getString( PropsUtil.get(PropsKeys.COMPANY_ENCRYPTION_ALGORITHM))); public static final int KEY_SIZE = GetterUtil.getInteger( PropsUtil.get(PropsKeys.COMPANY_ENCRYPTION_KEY_SIZE)); public static final String PROVIDER_CLASS = GetterUtil.getString( SystemProperties.get(Encryptor.class.getName() + ".provider.class"), Encryptor.SUN_PROVIDER_CLASS); public static final String SUN_PROVIDER_CLASS = "com.sun.crypto.provider.SunJCE"; public static String decrypt(Key key, String encryptedString) throws EncryptorException { byte[] encryptedBytes = Base64.decode(encryptedString); return decryptUnencodedAsString(key, encryptedBytes); } public static byte[] decryptUnencodedAsBytes(Key key, byte[] encryptedBytes) throws EncryptorException { String algorithm = key.getAlgorithm(); String cacheKey = algorithm.concat(StringPool.POUND).concat( key.toString()); Cipher cipher = _decryptCipherMap.get(cacheKey); try { if (cipher == null) { Security.addProvider(getProvider()); cipher = Cipher.getInstance(algorithm); cipher.init(Cipher.DECRYPT_MODE, key); _decryptCipherMap.put(cacheKey, cipher); } synchronized (cipher) { return cipher.doFinal(encryptedBytes); } } catch (Exception e) { throw new EncryptorException(e); } } public static String decryptUnencodedAsString( Key key, byte[] encryptedBytes) throws EncryptorException { try { byte[] decryptedBytes = decryptUnencodedAsBytes( key, encryptedBytes); return new String(decryptedBytes, ENCODING); } catch (Exception e) { throw new EncryptorException(e); } } public static Key deserializeKey(String base64String) { byte[] bytes = Base64.decode(base64String); return new SecretKeySpec(bytes, Encryptor.KEY_ALGORITHM); } public static String digest(String text) { return DigesterUtil.digest(text); } public static String digest(String algorithm, String text) { return DigesterUtil.digest(algorithm, text); } public static String encrypt(Key key, String plainText) throws EncryptorException { if (key == null) { if (_log.isWarnEnabled()) { _log.warn("Skip encrypting based on a null key"); } return plainText; } byte[] encryptedBytes = encryptUnencoded(key, plainText); return Base64.encode(encryptedBytes); } public static byte[] encryptUnencoded(Key key, byte[] plainBytes) throws EncryptorException { String algorithm = key.getAlgorithm(); String cacheKey = algorithm.concat(StringPool.POUND).concat( key.toString()); Cipher cipher = _encryptCipherMap.get(cacheKey); try { if (cipher == null) { Security.addProvider(getProvider()); cipher = Cipher.getInstance(algorithm); cipher.init(Cipher.ENCRYPT_MODE, key); _encryptCipherMap.put(cacheKey, cipher); } synchronized (cipher) { return cipher.doFinal(plainBytes); } } catch (Exception e) { throw new EncryptorException(e); } } public static byte[] encryptUnencoded(Key key, String plainText) throws EncryptorException { try { byte[] decryptedBytes = plainText.getBytes(ENCODING); return encryptUnencoded(key, decryptedBytes); } catch (Exception e) { throw new EncryptorException(e); } } public static Key generateKey() throws EncryptorException { return generateKey(KEY_ALGORITHM); } public static Key generateKey(String algorithm) throws EncryptorException { try { Security.addProvider(getProvider()); KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm); keyGenerator.init(KEY_SIZE, new SecureRandom()); Key key = keyGenerator.generateKey(); return key; } catch (Exception e) { throw new EncryptorException(e); } } public static Provider getProvider() throws ClassNotFoundException, IllegalAccessException, InstantiationException { Class<?> providerClass = null; try { providerClass = Class.forName(PROVIDER_CLASS); } catch (ClassNotFoundException cnfe) { if (ServerDetector.isWebSphere() && PROVIDER_CLASS.equals(SUN_PROVIDER_CLASS)) { if (_log.isInfoEnabled()) { _log.info( "WebSphere does not have " + SUN_PROVIDER_CLASS + ", using " + IBM_PROVIDER_CLASS + " instead"); } providerClass = Class.forName(IBM_PROVIDER_CLASS); } else if (System.getProperty("java.vm.vendor").equals( "IBM Corporation")) { if (_log.isInfoEnabled()) { _log.info( "IBM JVM does not have " + SUN_PROVIDER_CLASS + ", using " + IBM_PROVIDER_CLASS + " instead"); } providerClass = Class.forName(IBM_PROVIDER_CLASS); } else { throw cnfe; } } return (Provider)providerClass.newInstance(); } public static String serializeKey(Key key) { return Base64.encode(key.getEncoded()); } private static final Log _log = LogFactoryUtil.getLog(Encryptor.class); private static final Map<String, Cipher> _decryptCipherMap = new ConcurrentHashMap<>(1, 1F, 1); private static final Map<String, Cipher> _encryptCipherMap = new ConcurrentHashMap<>(1, 1F, 1); }