aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Straub <andy@strb.org>2015-07-20 22:18:24 +0200
committerAndreas Straub <andy@strb.org>2015-07-20 22:18:24 +0200
commitab2d114bbc21a5c2d684f8760cb8e4cea54be5de (patch)
tree03755711067759016f0940986746506eb63b7630
parent0ee64124fe317f6959d1ff61cc9e70b272bf8eb5 (diff)
Add purge axolotl key option
Can now long-press a key to permanently purge it.
-rw-r--r--src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java84
-rw-r--r--src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlMessage.java7
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java3
-rw-r--r--src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java3
-rw-r--r--src/main/java/eu/siacs/conversations/ui/XmppActivity.java37
-rw-r--r--src/main/res/values/strings.xml3
6 files changed, 99 insertions, 38 deletions
diff --git a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java
index 1fe455ff..6e28f111 100644
--- a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java
+++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java
@@ -100,7 +100,8 @@ public class AxolotlService {
public enum Trust {
UNDECIDED, // 0
TRUSTED,
- UNTRUSTED;
+ UNTRUSTED,
+ COMPROMISED;
public String toString() {
switch(this){
@@ -514,41 +515,64 @@ public class AxolotlService {
return fingerprint;
}
+ private SQLiteAxolotlStore.Trust getTrust() {
+ return sqLiteAxolotlStore.getFingerprintTrust(fingerprint);
+ }
+
+ @Nullable
public byte[] processReceiving(XmppAxolotlMessage.XmppAxolotlMessageHeader incomingHeader) {
byte[] plaintext = null;
- try {
- try {
- PreKeyWhisperMessage message = new PreKeyWhisperMessage(incomingHeader.getContents());
- Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account)+"PreKeyWhisperMessage received, new session ID:" + message.getSignedPreKeyId() + "/" + message.getPreKeyId());
- String fingerprint = message.getIdentityKey().getFingerprint().replaceAll("\\s", "");
- if (this.fingerprint != null && !this.fingerprint.equals(fingerprint)) {
- Log.e(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Had session with fingerprint "+ this.fingerprint+", received message with fingerprint "+fingerprint);
- } else {
- this.fingerprint = fingerprint;
- plaintext = cipher.decrypt(message);
- if (message.getPreKeyId().isPresent()) {
- preKeyId = message.getPreKeyId().get();
+ switch (getTrust()) {
+ case UNDECIDED:
+ case TRUSTED:
+ try {
+ try {
+ PreKeyWhisperMessage message = new PreKeyWhisperMessage(incomingHeader.getContents());
+ Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account)+"PreKeyWhisperMessage received, new session ID:" + message.getSignedPreKeyId() + "/" + message.getPreKeyId());
+ String fingerprint = message.getIdentityKey().getFingerprint().replaceAll("\\s", "");
+ if (this.fingerprint != null && !this.fingerprint.equals(fingerprint)) {
+ Log.e(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Had session with fingerprint "+ this.fingerprint+", received message with fingerprint "+fingerprint);
+ } else {
+ this.fingerprint = fingerprint;
+ plaintext = cipher.decrypt(message);
+ if (message.getPreKeyId().isPresent()) {
+ preKeyId = message.getPreKeyId().get();
+ }
+ }
+ } catch (InvalidMessageException | InvalidVersionException e) {
+ Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account)+"WhisperMessage received");
+ WhisperMessage message = new WhisperMessage(incomingHeader.getContents());
+ plaintext = cipher.decrypt(message);
+ } catch (InvalidKeyException | InvalidKeyIdException | UntrustedIdentityException e) {
+ Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Error decrypting axolotl header, "+e.getClass().getName()+": " + e.getMessage());
}
+ } catch (LegacyMessageException | InvalidMessageException | DuplicateMessageException | NoSessionException e) {
+ Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Error decrypting axolotl header, "+e.getClass().getName()+": " + e.getMessage());
}
- } catch (InvalidMessageException | InvalidVersionException e) {
- Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account)+"WhisperMessage received");
- WhisperMessage message = new WhisperMessage(incomingHeader.getContents());
- plaintext = cipher.decrypt(message);
- } catch (InvalidKeyException | InvalidKeyIdException | UntrustedIdentityException e) {
- Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Error decrypting axolotl header, "+e.getClass().getName()+": " + e.getMessage());
- }
- } catch (LegacyMessageException | InvalidMessageException | DuplicateMessageException | NoSessionException e) {
- Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Error decrypting axolotl header, "+e.getClass().getName()+": " + e.getMessage());
+
+ break;
+
+ case COMPROMISED:
+ case UNTRUSTED:
+ default:
+ // ignore
+ break;
}
return plaintext;
}
- public XmppAxolotlMessage.XmppAxolotlMessageHeader processSending(byte[] outgoingMessage) {
- CiphertextMessage ciphertextMessage = cipher.encrypt(outgoingMessage);
- XmppAxolotlMessage.XmppAxolotlMessageHeader header =
- new XmppAxolotlMessage.XmppAxolotlMessageHeader(remoteAddress.getDeviceId(),
- ciphertextMessage.serialize());
- return header;
+ @Nullable
+ public XmppAxolotlMessage.XmppAxolotlMessageHeader processSending(@NonNull byte[] outgoingMessage) {
+ SQLiteAxolotlStore.Trust trust = getTrust();
+ if (trust == SQLiteAxolotlStore.Trust.TRUSTED) {
+ CiphertextMessage ciphertextMessage = cipher.encrypt(outgoingMessage);
+ XmppAxolotlMessage.XmppAxolotlMessageHeader header =
+ new XmppAxolotlMessage.XmppAxolotlMessageHeader(remoteAddress.getDeviceId(),
+ ciphertextMessage.serialize());
+ return header;
+ } else {
+ return null;
+ }
}
}
@@ -742,6 +766,10 @@ public class AxolotlService {
});
}
+ public void purgeKey(IdentityKey identityKey) {
+ axolotlStore.setFingerprintTrust(identityKey.getFingerprint().replaceAll("\\s",""), SQLiteAxolotlStore.Trust.COMPROMISED);
+ }
+
public void publishOwnDeviceIdIfNeeded() {
IqPacket packet = mXmppConnectionService.getIqGenerator().retrieveDeviceIds(account.getJid().toBareJid());
mXmppConnectionService.sendIqPacket(account, packet, new OnIqPacketReceived() {
diff --git a/src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlMessage.java b/src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlMessage.java
index 1378c94a..ec068ec7 100644
--- a/src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlMessage.java
+++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlMessage.java
@@ -1,5 +1,6 @@
package eu.siacs.conversations.crypto.axolotl;
+import android.support.annotation.Nullable;
import android.util.Base64;
import java.security.InvalidAlgorithmParameterException;
@@ -145,8 +146,10 @@ public class XmppAxolotlMessage {
return headers;
}
- public void addHeader(XmppAxolotlMessageHeader header) {
- headers.add(header);
+ public void addHeader(@Nullable XmppAxolotlMessageHeader header) {
+ if (header != null) {
+ headers.add(header);
+ }
}
public byte[] getInnerKey(){
diff --git a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java
index cc2ef27c..16e16cff 100644
--- a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java
@@ -384,8 +384,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
}
for(final IdentityKey identityKey : xmppConnectionService.databaseBackend.loadIdentityKeys(
contact.getAccount(), contact.getJid().toBareJid().toString())) {
- hasKeys = true;
- addFingerprintRow(keys, contact.getAccount(), identityKey);
+ hasKeys |= addFingerprintRow(keys, contact.getAccount(), identityKey);
}
if (contact.getPgpKeyId() != 0) {
hasKeys = true;
diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
index e7b51329..c9e70082 100644
--- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
@@ -566,8 +566,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
if(ownKey.equals(identityKey)) {
continue;
}
- hasKeys = true;
- addFingerprintRow(keys, mAccount, identityKey);
+ hasKeys |= addFingerprintRow(keys, mAccount, identityKey);
}
if (hasKeys) {
keysCard.setVisibility(View.VISIBLE);
diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
index 69357224..19783627 100644
--- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
@@ -601,11 +601,11 @@ public abstract class XmppActivity extends Activity {
builder.create().show();
}
- protected void addFingerprintRow(LinearLayout keys, final Account account, IdentityKey identityKey) {
+ protected boolean addFingerprintRow(LinearLayout keys, final Account account, IdentityKey identityKey) {
final String fingerprint = identityKey.getFingerprint().replaceAll("\\s", "");
final AxolotlService.SQLiteAxolotlStore.Trust trust = account.getAxolotlService()
.getFingerprintTrust(fingerprint);
- addFingerprintRowWithListeners(keys, account, identityKey, trust, true,
+ return addFingerprintRowWithListeners(keys, account, identityKey, trust, true,
new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
@@ -633,13 +633,16 @@ public abstract class XmppActivity extends Activity {
);
}
- protected void addFingerprintRowWithListeners(LinearLayout keys, final Account account,
- IdentityKey identityKey,
+ protected boolean addFingerprintRowWithListeners(LinearLayout keys, final Account account,
+ final IdentityKey identityKey,
AxolotlService.SQLiteAxolotlStore.Trust trust,
boolean showTag,
CompoundButton.OnCheckedChangeListener
onCheckedChangeListener,
View.OnClickListener onClickListener) {
+ if (trust == AxolotlService.SQLiteAxolotlStore.Trust.COMPROMISED) {
+ return false;
+ }
View view = getLayoutInflater().inflate(R.layout.contact_key, keys, false);
TextView key = (TextView) view.findViewById(R.id.key);
TextView keyType = (TextView) view.findViewById(R.id.key_type);
@@ -647,6 +650,13 @@ public abstract class XmppActivity extends Activity {
trustToggle.setVisibility(View.VISIBLE);
trustToggle.setOnCheckedChangeListener(onCheckedChangeListener);
trustToggle.setOnClickListener(onClickListener);
+ view.setOnLongClickListener(new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ showPurgeKeyDialog(account, identityKey);
+ return true;
+ }
+ });
switch (trust) {
case UNTRUSTED:
@@ -668,7 +678,26 @@ public abstract class XmppActivity extends Activity {
key.setText(CryptoHelper.prettifyFingerprint(identityKey.getFingerprint()));
keys.addView(view);
+ return true;
+ }
+ public void showPurgeKeyDialog(final Account account, final IdentityKey identityKey) {
+ Builder builder = new Builder(this);
+ builder.setTitle(getString(R.string.purge_key));
+ builder.setIconAttribute(android.R.attr.alertDialogIcon);
+ builder.setMessage(getString(R.string.purge_key_desc_part1)
+ + "\n\n" + CryptoHelper.prettifyFingerprint(identityKey.getFingerprint())
+ + "\n\n" + getString(R.string.purge_key_desc_part2));
+ builder.setNegativeButton(getString(R.string.cancel), null);
+ builder.setPositiveButton(getString(R.string.accept),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ account.getAxolotlService().purgeKey(identityKey);
+ refreshUi();
+ }
+ });
+ builder.create().show();
}
public void selectPresence(final Conversation conversation,
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index 0f992884..7f3408fc 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -393,6 +393,9 @@
<string name="wipe_axolotl_pep">Wipe other devices from PEP</string>
<string name="clear_other_devices">Clear devices</string>
<string name="clear_other_devices_desc">Are you sure you want to clear all other devices from the axolotl announcement? The next time your devices connect, they will reannounce themselves, but they might not receive messages sent in the meantime.</string>
+ <string name="purge_key">Purge key</string>
+ <string name="purge_key_desc_part1">Are you sure you want to purge this key?</string>
+ <string name="purge_key_desc_part2">It will irreversibly be considered compromised, and you can never build a session with it again.</string>
<string name="fetching_history_from_server">Fetching history from server</string>
<string name="no_more_history_on_server">No more history on server</string>
<string name="updating">Updating…</string>