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 &gt; 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    }