|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 package org.mozilla.gecko.sync.crypto; |
|
6 |
|
7 import org.mozilla.gecko.background.common.log.Logger; |
|
8 import org.mozilla.gecko.sync.CollectionKeys; |
|
9 import org.mozilla.gecko.sync.CryptoRecord; |
|
10 |
|
11 import android.content.SharedPreferences; |
|
12 |
|
13 public class PersistedCrypto5Keys { |
|
14 public static final String LOG_TAG = "PersistedC5Keys"; |
|
15 |
|
16 public static final String CRYPTO5_KEYS_SERVER_RESPONSE_BODY = "crypto5KeysServerResponseBody"; |
|
17 public static final String CRYPTO5_KEYS_LAST_MODIFIED = "crypto5KeysLastModified"; |
|
18 |
|
19 protected SharedPreferences prefs; |
|
20 protected KeyBundle syncKeyBundle; |
|
21 |
|
22 public PersistedCrypto5Keys(SharedPreferences prefs, KeyBundle syncKeyBundle) { |
|
23 if (syncKeyBundle == null) { |
|
24 throw new IllegalArgumentException("Null syncKeyBundle passed in to PersistedCrypto5Keys constructor."); |
|
25 } |
|
26 this.prefs = prefs; |
|
27 this.syncKeyBundle = syncKeyBundle; |
|
28 } |
|
29 |
|
30 /** |
|
31 * Get persisted crypto/keys. |
|
32 * <p> |
|
33 * crypto/keys is fetched from an encrypted JSON-encoded <code>CryptoRecord</code>. |
|
34 * |
|
35 * @return A <code>CollectionKeys</code> instance or <code>null</code> if none |
|
36 * is currently persisted. |
|
37 */ |
|
38 public CollectionKeys keys() { |
|
39 String keysJSON = prefs.getString(CRYPTO5_KEYS_SERVER_RESPONSE_BODY, null); |
|
40 if (keysJSON == null) { |
|
41 return null; |
|
42 } |
|
43 try { |
|
44 CryptoRecord cryptoRecord = CryptoRecord.fromJSONRecord(keysJSON); |
|
45 CollectionKeys keys = new CollectionKeys(); |
|
46 keys.setKeyPairsFromWBO(cryptoRecord, syncKeyBundle); |
|
47 return keys; |
|
48 } catch (Exception e) { |
|
49 Logger.warn(LOG_TAG, "Got exception decrypting persisted crypto/keys.", e); |
|
50 return null; |
|
51 } |
|
52 } |
|
53 |
|
54 /** |
|
55 * Persist crypto/keys. |
|
56 * <p> |
|
57 * crypto/keys is stored as an encrypted JSON-encoded <code>CryptoRecord</code>. |
|
58 * |
|
59 * @param keys |
|
60 * The <code>CollectionKeys</code> object to persist, which should |
|
61 * have the same default key bundle as the sync key bundle. |
|
62 */ |
|
63 public void persistKeys(CollectionKeys keys) { |
|
64 if (keys == null) { |
|
65 Logger.debug(LOG_TAG, "Clearing persisted crypto/keys."); |
|
66 prefs.edit().remove(CRYPTO5_KEYS_SERVER_RESPONSE_BODY).commit(); |
|
67 return; |
|
68 } |
|
69 try { |
|
70 CryptoRecord cryptoRecord = keys.asCryptoRecord(); |
|
71 cryptoRecord.keyBundle = syncKeyBundle; |
|
72 cryptoRecord.encrypt(); |
|
73 String keysJSON = cryptoRecord.toJSONString(); |
|
74 Logger.debug(LOG_TAG, "Persisting crypto/keys."); |
|
75 prefs.edit().putString(CRYPTO5_KEYS_SERVER_RESPONSE_BODY, keysJSON).commit(); |
|
76 } catch (Exception e) { |
|
77 Logger.warn(LOG_TAG, "Got exception encrypting while persisting crypto/keys.", e); |
|
78 } |
|
79 } |
|
80 |
|
81 public boolean persistedKeysExist() { |
|
82 return lastModified() > 0; |
|
83 } |
|
84 |
|
85 public long lastModified() { |
|
86 return prefs.getLong(CRYPTO5_KEYS_LAST_MODIFIED, -1); |
|
87 } |
|
88 |
|
89 public void persistLastModified(long lastModified) { |
|
90 if (lastModified <= 0) { |
|
91 Logger.debug(LOG_TAG, "Clearing persisted crypto/keys last modified timestamp."); |
|
92 prefs.edit().remove(CRYPTO5_KEYS_LAST_MODIFIED).commit(); |
|
93 return; |
|
94 } |
|
95 Logger.debug(LOG_TAG, "Persisting crypto/keys last modified timestamp " + lastModified + "."); |
|
96 prefs.edit().putLong(CRYPTO5_KEYS_LAST_MODIFIED, lastModified).commit(); |
|
97 } |
|
98 |
|
99 public void purge() { |
|
100 persistLastModified(-1); |
|
101 persistKeys(null); |
|
102 } |
|
103 } |