1
0
mirror of https://github.com/etesync/android synced 2024-12-23 23:18:46 +00:00

Journal: use journal keys if available.

If a journal has a key set to it (usually used for shared journals), use
it instead of the symmetric key. The key of the journal is asymmetrically
encrypted using our keypair.
This commit is contained in:
Tom Hacohen 2017-04-13 13:29:05 +01:00
parent 43803b6d3e
commit beccb33904
5 changed files with 43 additions and 16 deletions

View File

@ -123,8 +123,21 @@ public class Crypto {
private SecureRandom _random = null; private SecureRandom _random = null;
@Getter @Getter
private final byte version; private final byte version;
private final byte[] cipherKey; private byte[] cipherKey;
private final byte[] hmacKey; private byte[] hmacKey;
private void setDerivedKey(byte[] derivedKey) {
cipherKey = hmac256("aes".getBytes(Charsets.UTF_8), derivedKey);
hmacKey = hmac256("hmac".getBytes(Charsets.UTF_8), derivedKey);
}
public CryptoManager(int version, AsymmetricKeyPair keyPair, byte[] encryptedKey) {
Crypto.AsymmetricCryptoManager cryptoManager = new Crypto.AsymmetricCryptoManager(keyPair);
byte[] derivedKey = cryptoManager.decrypt(encryptedKey);
this.version = (byte) version;
setDerivedKey(derivedKey);
}
public CryptoManager(int version, @NonNull String keyBase64, @NonNull String salt) throws Exceptions.IntegrityException, Exceptions.VersionTooNewException { public CryptoManager(int version, @NonNull String keyBase64, @NonNull String salt) throws Exceptions.IntegrityException, Exceptions.VersionTooNewException {
byte[] derivedKey; byte[] derivedKey;
@ -139,8 +152,7 @@ public class Crypto {
} }
this.version = (byte) version; this.version = (byte) version;
cipherKey = hmac256("aes".getBytes(Charsets.UTF_8), derivedKey); setDerivedKey(derivedKey);
hmacKey = hmac256("hmac".getBytes(Charsets.UTF_8), derivedKey);
} }
private static final int blockSize = 16; // AES's block size in bytes private static final int blockSize = 16; // AES's block size in bytes

View File

@ -40,7 +40,7 @@ public class JournalManager extends BaseManager {
this.client = httpClient; this.client = httpClient;
} }
public List<Journal> getJournals(String keyBase64) throws Exceptions.HttpException, Exceptions.IntegrityException, Exceptions.GenericCryptoException { public List<Journal> getJournals() throws Exceptions.HttpException {
Request request = new Request.Builder() Request request = new Request.Builder()
.get() .get()
.url(remote) .url(remote)
@ -51,9 +51,7 @@ public class JournalManager extends BaseManager {
List<Journal> ret = GsonHelper.gson.fromJson(body.charStream(), journalType); List<Journal> ret = GsonHelper.gson.fromJson(body.charStream(), journalType);
for (Journal journal : ret) { for (Journal journal : ret) {
Crypto.CryptoManager crypto = new Crypto.CryptoManager(journal.getVersion(), keyBase64, journal.getUid());
journal.processFromJson(); journal.processFromJson();
journal.verify(crypto);
} }
return ret; return ret;
@ -157,7 +155,7 @@ public class JournalManager extends BaseManager {
setContent(Arrays.copyOfRange(getContent(), HMAC_SIZE, getContent().length)); setContent(Arrays.copyOfRange(getContent(), HMAC_SIZE, getContent().length));
} }
void verify(Crypto.CryptoManager crypto) throws Exceptions.IntegrityException { public void verify(Crypto.CryptoManager crypto) throws Exceptions.IntegrityException {
if (hmac == null) { if (hmac == null) {
throw new Exceptions.IntegrityException("HMAC is null!"); throw new Exceptions.IntegrityException("HMAC is null!");
} }

View File

@ -158,8 +158,16 @@ public abstract class SyncAdapterService extends Service {
List<Pair<JournalManager.Journal, CollectionInfo>> journals = new LinkedList<>(); List<Pair<JournalManager.Journal, CollectionInfo>> journals = new LinkedList<>();
for (JournalManager.Journal journal : journalsManager.getJournals(settings.password())) { for (JournalManager.Journal journal : journalsManager.getJournals()) {
Crypto.CryptoManager crypto = new Crypto.CryptoManager(journal.getVersion(), settings.password(), journal.getUid()); Crypto.CryptoManager crypto;
if (journal.getKey() != null) {
crypto = new Crypto.CryptoManager(journal.getVersion(), settings.getKeyPair(), journal.getKey());
} else {
crypto = new Crypto.CryptoManager(journal.getVersion(), settings.password(), journal.getUid());
}
journal.verify(crypto);
CollectionInfo info = CollectionInfo.fromJson(journal.getContent(crypto)); CollectionInfo info = CollectionInfo.fromJson(journal.getContent(crypto));
info.updateFromJournal(journal); info.updateFromJournal(journal);

View File

@ -33,6 +33,7 @@ import com.etesync.syncadapter.model.SyncEntry;
import com.etesync.syncadapter.resource.LocalCollection; import com.etesync.syncadapter.resource.LocalCollection;
import com.etesync.syncadapter.resource.LocalResource; import com.etesync.syncadapter.resource.LocalResource;
import com.etesync.syncadapter.ui.DebugInfoActivity; import com.etesync.syncadapter.ui.DebugInfoActivity;
import com.etesync.syncadapter.utils.Base64;
import org.apache.commons.collections4.ListUtils; import org.apache.commons.collections4.ListUtils;
@ -118,7 +119,12 @@ abstract public class SyncManager {
notificationManager.cancel(); notificationManager.cancel();
App.log.info(String.format(Locale.getDefault(), "Syncing collection %s (version: %d)", journalUid, info.version)); App.log.info(String.format(Locale.getDefault(), "Syncing collection %s (version: %d)", journalUid, info.version));
crypto = new Crypto.CryptoManager(info.version, settings.password(), journalUid);
if (getJournalEntity().getEncryptedKey() != null) {
crypto = new Crypto.CryptoManager(info.version, settings.getKeyPair(), getJournalEntity().getEncryptedKey());
} else {
crypto = new Crypto.CryptoManager(info.version, settings.password(), info.uid);
}
} }
protected abstract int notificationId(); protected abstract int notificationId();
@ -235,7 +241,7 @@ abstract public class SyncManager {
private JournalEntity getJournalEntity() { private JournalEntity getJournalEntity() {
if (_journalEntity == null) if (_journalEntity == null)
_journalEntity = JournalModel.Journal.fetch(data, info.getServiceEntity(data), journal.getUid()); _journalEntity = JournalModel.Journal.fetch(data, info.getServiceEntity(data), info.uid);
return _journalEntity; return _journalEntity;
} }

View File

@ -93,7 +93,7 @@ public class ServiceTest {
} }
assertNotNull(caught); assertNotNull(caught);
List<JournalManager.Journal> journals = journalManager.getJournals(Helpers.keyBase64); List<JournalManager.Journal> journals = journalManager.getJournals();
assertEquals(journals.size(), 1); assertEquals(journals.size(), 1);
CollectionInfo info2 = CollectionInfo.fromJson(journals.get(0).getContent(crypto)); CollectionInfo info2 = CollectionInfo.fromJson(journals.get(0).getContent(crypto));
assertEquals(info2.displayName, info.displayName); assertEquals(info2.displayName, info.displayName);
@ -103,7 +103,7 @@ public class ServiceTest {
journal = new JournalManager.Journal(crypto, info.toJson(), info.uid); journal = new JournalManager.Journal(crypto, info.toJson(), info.uid);
journalManager.updateJournal(journal); journalManager.updateJournal(journal);
journals = journalManager.getJournals(Helpers.keyBase64); journals = journalManager.getJournals();
assertEquals(journals.size(), 1); assertEquals(journals.size(), 1);
info2 = CollectionInfo.fromJson(journals.get(0).getContent(crypto)); info2 = CollectionInfo.fromJson(journals.get(0).getContent(crypto));
assertEquals(info2.displayName, info.displayName); assertEquals(info2.displayName, info.displayName);
@ -111,7 +111,7 @@ public class ServiceTest {
// Delete journal // Delete journal
journalManager.deleteJournal(journal); journalManager.deleteJournal(journal);
journals = journalManager.getJournals(Helpers.keyBase64); journals = journalManager.getJournals();
assertEquals(journals.size(), 0); assertEquals(journals.size(), 0);
// Bad HMAC // Bad HMAC
@ -124,7 +124,10 @@ public class ServiceTest {
try { try {
caught = null; caught = null;
journalManager.getJournals(Helpers.keyBase64); for (JournalManager.Journal journal1 : journalManager.getJournals()) {
Crypto.CryptoManager crypto1 = new Crypto.CryptoManager(info.version, Helpers.keyBase64, journal1.getUid());
journal1.verify(crypto1);
}
} catch (Exceptions.IntegrityException e) { } catch (Exceptions.IntegrityException e) {
caught = e; caught = e;
} }