001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (https://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software, please see the 018 * company website: https://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: https://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.crypto; 029 030import org.opencms.configuration.CmsParameterConfiguration; 031import org.opencms.file.CmsObject; 032import org.opencms.main.CmsLog; 033 034import java.nio.charset.StandardCharsets; 035 036import javax.crypto.Cipher; 037import javax.crypto.SecretKey; 038import javax.crypto.spec.SecretKeySpec; 039 040import org.apache.commons.logging.Log; 041 042import org.bouncycastle.crypto.digests.SHA256Digest; 043import org.bouncycastle.crypto.generators.HKDFBytesGenerator; 044import org.bouncycastle.crypto.params.HKDFParameters; 045 046import com.google.common.io.BaseEncoding; 047 048/** 049 * Default text encryption class using AES, where the encryption key is generated from a string passed in as a parameter. 050 */ 051public class CmsAESTextEncryption implements I_CmsTextEncryption { 052 053 /** The name of the algorithm. */ 054 public static final String AES = "AES"; 055 056 /** URL parameter safe base64 encoder. */ 057 public static final BaseEncoding BASE64 = BaseEncoding.base64Url().withPadChar('.'); 058 059 /** The configuration parameter for configuring the secret. */ 060 public static final String PARAM_SECRET = "secret"; 061 062 /** Logger instance for this class. */ 063 private static final Log LOG = CmsLog.getLog(CmsAESTextEncryption.class); 064 065 /** The default cipher - what you'd effectively get with Cipher.getInstance("AES"). */ 066 protected String m_aesVariant = "AES/ECB/PKCS5Padding"; 067 068 /** The parameter configuration. */ 069 private CmsParameterConfiguration m_config = new CmsParameterConfiguration(); 070 071 /** The key used for encryption / decryption. */ 072 private SecretKey m_key; 073 074 /** The name under which this is registered. */ 075 private String m_name; 076 077 /** 078 * Default constructor (used when instantiated automatically during OpenCms configuration). 079 */ 080 public CmsAESTextEncryption() {} 081 082 /** 083 * Constructor used to manually, conveniently create a new encryption object with a given secret. 084 * 085 * <p>When using this constructor, it is not necessary to call initialize() to make the object usable. 086 * 087 * @param secret the secret used to generate the key 088 */ 089 public CmsAESTextEncryption(String secret) { 090 091 m_key = generateAESKey(secret); 092 } 093 094 /** 095 * Helper method for generating an AES key from a secret string. 096 * 097 * @param secret the secret string 098 * @return the AES key 099 */ 100 public static SecretKey generateAESKey(String secret) { 101 102 HKDFParameters params = HKDFParameters.defaultParameters(secret.getBytes(StandardCharsets.UTF_8)); 103 HKDFBytesGenerator keyGenerator = new HKDFBytesGenerator(new SHA256Digest()); 104 keyGenerator.init(params); 105 byte[] keyBytes = new byte[16]; 106 keyGenerator.generateBytes(keyBytes, 0, 16); 107 SecretKeySpec keySpec = new SecretKeySpec(keyBytes, AES); 108 return keySpec; 109 } 110 111 /** 112 * @see org.opencms.configuration.I_CmsConfigurationParameterHandler#addConfigurationParameter(java.lang.String, java.lang.String) 113 */ 114 public void addConfigurationParameter(String paramName, String paramValue) { 115 116 m_config.add(paramName, paramValue); 117 } 118 119 /** 120 * @see org.opencms.crypto.I_CmsTextEncryption#decrypt(java.lang.String) 121 */ 122 public String decrypt(String input) throws CmsEncryptionException { 123 124 byte[] encryptedBytes = BASE64.decode(input); 125 try { 126 Cipher cipher = Cipher.getInstance(m_aesVariant); 127 cipher.init(Cipher.DECRYPT_MODE, m_key); 128 byte[] decData = cipher.doFinal(encryptedBytes); 129 String result = new String(decData, StandardCharsets.UTF_8); 130 return result; 131 } catch (Exception e) { 132 throw new CmsEncryptionException(e.getLocalizedMessage(), e); 133 } 134 } 135 136 /** 137 * @see org.opencms.crypto.I_CmsTextEncryption#encrypt(java.lang.String) 138 */ 139 public String encrypt(String input) throws CmsEncryptionException { 140 141 try { 142 Cipher cipher = Cipher.getInstance(m_aesVariant); 143 cipher.init(Cipher.ENCRYPT_MODE, m_key); 144 byte[] encData = cipher.doFinal(input.getBytes(StandardCharsets.UTF_8)); 145 String lit = BASE64.encode(encData); 146 return lit; 147 } catch (Exception e) { 148 throw new CmsEncryptionException(e.getLocalizedMessage(), e); 149 } 150 } 151 152 /** 153 * @see org.opencms.configuration.I_CmsConfigurationParameterHandler#getConfiguration() 154 */ 155 public CmsParameterConfiguration getConfiguration() { 156 157 return m_config; 158 } 159 160 /** 161 * @see org.opencms.crypto.I_CmsTextEncryption#getName() 162 */ 163 public String getName() { 164 165 return m_name; 166 167 } 168 169 /** 170 * @see org.opencms.configuration.I_CmsConfigurationParameterHandler#initConfiguration() 171 */ 172 public void initConfiguration() { 173 174 // never called. 175 } 176 177 /** 178 * @see org.opencms.crypto.I_CmsTextEncryption#initialize(org.opencms.file.CmsObject) 179 */ 180 public void initialize(CmsObject cms) { 181 182 String secret = m_config.get(PARAM_SECRET); 183 if (secret == null) { 184 throw new IllegalArgumentException("Parameter 'secret' must be set!"); 185 } 186 m_key = generateAESKey(secret); 187 } 188 189 /** 190 * @see org.opencms.crypto.I_CmsTextEncryption#setName(java.lang.String) 191 */ 192 public void setName(String name) { 193 194 if (m_name != null) { 195 throw new IllegalStateException("Can't call setName twice!"); 196 } 197 m_name = name; 198 } 199 200}