001 /* 002 * Cumulus4j - Securing your data in the cloud - http://cumulus4j.org 003 * Copyright (C) 2011 NightLabs Consulting GmbH 004 * 005 * This program is free software: you can redistribute it and/or modify 006 * it under the terms of the GNU Affero General Public License as 007 * published by the Free Software Foundation, either version 3 of the 008 * License, or (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU Affero General Public License for more details. 014 * 015 * You should have received a copy of the GNU Affero General Public License 016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 017 */ 018 package org.cumulus4j.store.crypto; 019 020 import org.cumulus4j.store.model.EncryptionCoordinateSet; 021 import org.datanucleus.NucleusContext; 022 023 /** 024 * <p> 025 * {@link CryptoManager}s allow the Cumulus4j-DataNucleus-plug-in to encrypt and decrypt data. 026 * </p> 027 * <p> 028 * The primary purpose to make this feature pluggable is to provide different possibilities 029 * of the communication between the Cumulus4j-backend and a key store. For example, one client 030 * might prefer to manage the keys on the client while another client provides the coordinates 031 * of a key server to the backend. 032 * </p> 033 * <p> 034 * There is one shared instance of <code>CryptoManager</code> per {@link NucleusContext} and 035 * {@link #getCryptoManagerID() cryptoManagerID}. Due to this, instances of <code>CryptoManager</code> 036 * must be thread-safe! 037 * </p> 038 * <p> 039 * A <code>CryptoManager</code> must not be instantiated directly, but instead obtained via 040 * {@link CryptoManagerRegistry#getCryptoManager(String)}. 041 * </p> 042 * <p> 043 * <b>Important:</b> It is strongly recommended to subclass {@link AbstractCryptoManager} instead of 044 * directly implementing this interface! 045 * </p> 046 * 047 * @author Marco หงุ่ยตระกูล-Schulze - marco at nightlabs dot de 048 */ 049 public interface CryptoManager 050 { 051 /** 052 * <p> 053 * Property-name used to pass the {@link #getCryptoManagerID() cryptoManagerID} to the Cumulus4j-core. 054 * </p> 055 * <p> 056 * The property can either be set in the persistence-unit/persistence-properties-file for the 057 * <code>PersistenceManagerFactory</code>/<code>EntityManagerFactory</code> or it can be 058 * passed via 059 * {@link javax.jdo.PersistenceManager#setProperty(String, Object)} or 060 * {@link javax.persistence.EntityManager#setProperty(String, Object)}. If it is not set 061 * on the PM/EM level, the default-value set on the PMF/EMF level will be used. 062 * </p> 063 */ 064 static final String PROPERTY_CRYPTO_MANAGER_ID = "cumulus4j.cryptoManagerID"; 065 066 /** 067 * <p> 068 * Property to control the encryption algorithm that is used to encrypt data within the datastore. Both 069 * data and index are encrypted using this algorithm. 070 * </p> 071 * <p> 072 * By default (if the property {@value #PROPERTY_ENCRYPTION_ALGORITHM} is not specified), 073 * "Twofish/GCM/NoPadding" is used. For example, to switch to "AES/CFB/NoPadding", you'd have 074 * to specify "cumulus4j.encryptionAlgorithm=AES/CFB/NoPadding" in the persistence-unit/persistence-properties-file. 075 * </p> 076 * <p> 077 * See <a target="_blank" href="http://cumulus4j.org/1.2.0/documentation/supported-algorithms.html">this document</a> 078 * for further information about what values are supported. 079 * </p> 080 * <p> 081 * The encryption algorithm used during encryption is stored in the encryption-record's meta-data in order 082 * to use the correct algorithm during decryption, no matter what current encryption algorithm is configured. 083 * Therefore, you can safely change this setting at any time - it will affect future encryption 084 * operations, only. 085 * </p> 086 * <p> 087 * <b>Important:</b> The default MAC algorithm is "NONE", which is a very bad choice for most encryption algorithms! 088 * Therefore, you must change the MAC algorithm via the property {@value #PROPERTY_MAC_ALGORITHM} 089 * if you change the encryption algorithm! 090 * </p> 091 * <p> 092 * The property can be set in the persistence-unit/persistence-properties-file for the 093 * <code>PersistenceManagerFactory</code>/<code>EntityManagerFactory</code>. 094 * </p> 095 * @see #getEncryptionAlgorithm() 096 */ 097 static final String PROPERTY_ENCRYPTION_ALGORITHM = "cumulus4j.encryptionAlgorithm"; 098 099 /** 100 * <p> 101 * Property to control the <a target="_blank" href="http://en.wikipedia.org/wiki/Message_authentication_code">MAC</a> 102 * algorithm that is used to protect the data within the key-store against manipulation. 103 * </p> 104 * <p> 105 * Whenever data is encrypted, this MAC algorithm is used to calculate a MAC over the original plain-text-data. 106 * The MAC is then stored together with the plain-text-data within the encrypted area. 107 * When data is decrypted, the MAC is calculated again over the decrypted plain-text-data and compared to the 108 * original MAC in order to make sure (1) that data was correctly decrypted [i.e. the key is correct] and 109 * (2) that the data in the datastore was not manipulated by an attacker. 110 * </p> 111 * <p> 112 * The MAC algorithm used during encryption is stored in the encryption-record's meta-data in order 113 * to use the correct algorithm during decryption, no matter what current MAC algorithm is configured. 114 * Therefore, you can safely change this setting at any time - it will affect future encryption 115 * operations, only. 116 * </p> 117 * <p> 118 * Some block cipher modes (e.g. <a target="_blank" href="http://en.wikipedia.org/wiki/Galois/Counter_Mode">GCM</a>) already include authentication 119 * and therefore no MAC is necessary. In this case, you can specify the MAC algorithm {@value #MAC_ALGORITHM_NONE}. 120 * </p> 121 * <p> 122 * <b>Important:</b> If you specify the MAC algorithm "NONE" and use an encryption algorithm without 123 * authentication, the key store will not be able to detect a wrong password and instead return 124 * corrupt data!!! Be VERY careful with the MAC algorithm "NONE"!!! 125 * </p> 126 * <p> 127 * The default value (used when this system property is not specified) is "NONE", because the default 128 * encryption algorithm is "Twofish/GCM/NoPadding", which (due to "GCM") does not require an additional 129 * MAC. 130 * </p> 131 * <p> 132 * The property can be set in the persistence-unit/persistence-properties-file for the 133 * <code>PersistenceManagerFactory</code>/<code>EntityManagerFactory</code>. 134 * </p> 135 * @see #getMACAlgorithm() 136 */ 137 static final String PROPERTY_MAC_ALGORITHM = "cumulus4j.macAlgorithm"; 138 139 /** 140 * <p> 141 * Constant for deactivating the <a target="_blank" href="http://en.wikipedia.org/wiki/Message_authentication_code">MAC</a>. 142 * </p> 143 * <p> 144 * <b>Important: Deactivating the MAC is dangerous!</b> Choose this value only, if you are absolutely 145 * sure that your {@link #PROPERTY_ENCRYPTION_ALGORITHM encryption algorithm} already 146 * provides authentication - like <a target="_blank" href="http://en.wikipedia.org/wiki/Galois/Counter_Mode">GCM</a> 147 * does for example. 148 * </p> 149 * @see #PROPERTY_MAC_ALGORITHM 150 */ 151 static final String MAC_ALGORITHM_NONE = EncryptionCoordinateSet.MAC_ALGORITHM_NONE; 152 153 /** 154 * <p> 155 * Persistence property to control when the timer for cleaning up expired {@link CryptoSession}s is called. The 156 * value configured here is a period, i.e. the timer will be triggered every X ms (roughly). 157 * </p><p> 158 * If this persistence property is not present (or not a valid number > 0), the default is 60000 (1 minute), which means 159 * the timer will wake up once a minute and do the clean-up (default implementation is calling 160 * {@link AbstractCryptoManager#closeExpiredCryptoSessions(boolean)} with <code>force = true</code>). 161 * </p><p> 162 * If this persistence property is set to 0, the timer is deactivated and cleanup happens only synchronously 163 * when {@link #getCryptoSession(String)} is called (periodically - not every time this method is called). 164 * </p> 165 * @see #PROPERTY_CRYPTO_SESSION_EXPIRY_TIMER_ENABLED 166 */ 167 public static final String PROPERTY_CRYPTO_SESSION_EXPIRY_TIMER_PERIOD = "cumulus4j.cryptoSessionExpiryTimer.period"; 168 169 /** 170 * Persistence property to control whether the timer for cleaning up expired {@link CryptoSession}s is enabled. 171 * The value configured here is a boolean (i.e. must be "true" or "false"). The default value (if the property 172 * is not specified or incorrect) is "true". 173 * @see #PROPERTY_CRYPTO_SESSION_EXPIRY_TIMER_PERIOD 174 */ 175 public static final String PROPERTY_CRYPTO_SESSION_EXPIRY_TIMER_ENABLED = "cumulus4j.cryptoSessionExpiryTimer.enabled"; 176 177 /** 178 * <p> 179 * Persistence property to control after which time an unused {@link CryptoSession} expires. 180 * </p><p> 181 * <code>CryptoSession</code>s that are unused for the configured time in milliseconds are considered expired and 182 * either periodically removed by a timer (see property {@value #PROPERTY_CRYPTO_SESSION_EXPIRY_TIMER_PERIOD}) 183 * or periodically removed synchronously during a call to {@link #getCryptoSession(String)}. 184 * </p><p> 185 * If this property is not present (or not a valid number), the default value is 1800000 (30 minutes). 186 * </p> 187 */ 188 public static final String PROPERTY_CRYPTO_SESSION_EXPIRY_AGE = "cumulus4j.cryptoSessionExpiryAge"; 189 190 /** 191 * Get the registry which manages this {@link CryptoManager}. 192 * This method should normally never return <code>null</code>, because 193 * the registry is {@link #setCryptoManagerRegistry(CryptoManagerRegistry) set} immediately 194 * after instantiation. 195 * @return the registry holding this {@link CryptoManager}. 196 * @see #setCryptoManagerRegistry(CryptoManagerRegistry) 197 */ 198 CryptoManagerRegistry getCryptoManagerRegistry(); 199 200 /** 201 * Set the registry which manages this {@link CryptoManager}. 202 * This method is called by the {@link CryptoManagerRegistry} whenever 203 * it creates a new instance of <code>CryptoManager</code>. 204 * 205 * @param cryptoManagerRegistry 206 * @see #getCryptoManagerRegistry() 207 */ 208 void setCryptoManagerRegistry(CryptoManagerRegistry cryptoManagerRegistry); 209 210 /** 211 * <p> 212 * Set the <code>cryptoManagerID</code> of this instance. 213 * </p> 214 * <p> 215 * This method is called with the value configured in the <code>plugin.xml</code> 216 * directly after instantiating the <code>CryptoManager</code>. 217 * </p> 218 * <p> 219 * <b>You must never directly call this method! It is not an API method!</b> 220 * </p> 221 * 222 * @param cryptoManagerID the identifier to set. 223 * @see #getCryptoManagerID() 224 */ 225 void setCryptoManagerID(String cryptoManagerID); 226 227 /** 228 * <p> 229 * Get the <code>cryptoManagerID</code> of this instance. 230 * </p> 231 * <p> 232 * The <code>cryptoManagerID</code> is configured in the <code>plugin.xml</code> when registering an extension 233 * to the extension-point <code>org.cumulus4j.api.cryptoManager</code>. It is then used by the client to 234 * specify which method of key-exchange (or key-management in general) and encryption/decryption is desired. 235 * This is done by setting the property {@link #PROPERTY_CRYPTO_MANAGER_ID}. 236 * </p> 237 * <p> 238 * This method is thread-safe. 239 * </p> 240 * 241 * @return the <code>cryptoManagerID</code> of this instance. 242 */ 243 String getCryptoManagerID(); 244 245 /** 246 * <p> 247 * Get the {@link CryptoSession} identified by the given <code>cryptoSessionID</code>. 248 * </p> 249 * <p> 250 * Usually, every client opens one crypto-session. How exactly this happens, is highly dependent 251 * on the <code>CryptoManager</code> and <code>CryptoSession</code> implementation. The 252 * {@link CryptoSession#getCryptoSessionID() cryptoSessionID} is then passed from the client to 253 * the server which itself passes it to the <code>PersistenceManager</code> (or <code>EntityManager</code>) 254 * via the property with the name {@link CryptoSession#PROPERTY_CRYPTO_SESSION_ID}. 255 * </p> 256 * <p> 257 * Calling this method with a non-existing <code>cryptoSessionID</code> implicitely creates 258 * a <code>CryptoSession</code> instance and returns it. A future call to this method with the same 259 * <code>cryptoSessionID</code> returns the same <code>CryptoSession</code> instance. 260 * </p> 261 * <p> 262 * A <code>CryptoSession</code> should only be kept in the memory of a <code>CryptoManager</code> for a limited time. 263 * It is recommended to remove it 264 * a short configurable time (e.g. 10 minutes) after the {@link CryptoSession#getLastUsageTimestamp() last usage}. 265 * </p> 266 * <p> 267 * This method must call {@link CryptoSession#updateLastUsageTimestamp()}. 268 * </p> 269 * <p> 270 * This method is thread-safe. 271 * </p> 272 * 273 * @param cryptoSessionID the {@link CryptoSession#getCryptoSessionID() cryptoSessionID} for which to look up or 274 * create a <code>CryptoSession</code>. 275 * @return the <code>CryptoSession</code> identified by the given identifier; never <code>null</code>. 276 */ 277 CryptoSession getCryptoSession(String cryptoSessionID); 278 279 /** 280 * <p> 281 * Notify the {@link CryptoManager} about the fact that a session is currently being closed. 282 * </p> 283 * <p> 284 * <b>Important:</b> This method must never be called directly! It must be called by {@link CryptoSession#close()}. 285 * </p> 286 * 287 * @param cryptoSession the session that is currently closed. 288 */ 289 void onCloseCryptoSession(CryptoSession cryptoSession); 290 291 /** 292 * Get the value of the property {@value #PROPERTY_ENCRYPTION_ALGORITHM}. 293 * This property can be configured in the persistence-unit/persistence-properties-file. 294 * @return the currently configured encryption algorithm. 295 * @see #PROPERTY_ENCRYPTION_ALGORITHM 296 */ 297 String getEncryptionAlgorithm(); 298 299 /** 300 * Get the value of the property {@value #PROPERTY_MAC_ALGORITHM}. 301 * This property can be configured in the persistence-unit/persistence-properties-file. 302 * @return the currently configured MAC algorithm. 303 * @see #PROPERTY_MAC_ALGORITHM 304 */ 305 String getMACAlgorithm(); 306 307 }