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