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 }