From d173913ebabbf8de2725dd296ae6428defd4b3b3 Mon Sep 17 00:00:00 2001 From: Andreas Straub Date: Thu, 9 Jul 2015 14:23:17 +0200 Subject: Overhauled Message tagging Messages are now tagged with the IdentityKey fingerprint of the originating session. IdentityKeys have one of three trust states: undecided (default), trusted, and untrusted/not yet trusted. --- .../crypto/axolotl/AxolotlService.java | 100 ++++++++++++--------- .../crypto/axolotl/XmppAxolotlMessage.java | 11 ++- 2 files changed, 68 insertions(+), 43 deletions(-) (limited to 'src/main/java/eu/siacs/conversations/crypto') 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 ef7c523d..9c5c82ff 100644 --- a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java +++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java @@ -85,6 +85,7 @@ public class AxolotlService { public static final String DEVICE_ID = "device_id"; public static final String ID = "id"; public static final String KEY = "key"; + public static final String FINGERPRINT = "fingerprint"; public static final String NAME = "name"; public static final String TRUSTED = "trusted"; public static final String OWN = "ownkey"; @@ -99,6 +100,23 @@ public class AxolotlService { private final int localRegistrationId; private int currentPreKeyId = 0; + public enum Trust { + UNDECIDED, // 0 + TRUSTED, + UNTRUSTED; + + public String toString() { + switch(this){ + case UNDECIDED: + return "Trust undecided"; + case TRUSTED: + return "Trusted"; + case UNTRUSTED: + default: + return "Untrusted"; + } + } + }; private static IdentityKeyPair generateIdentityKeyPair() { Log.i(Config.LOGTAG, AxolotlService.LOGPREFIX+" : "+"Generating axolotl IdentityKeyPair..."); @@ -242,11 +260,17 @@ public class AxolotlService { */ @Override public boolean isTrustedIdentity(String name, IdentityKey identityKey) { - //Set trustedKeys = mXmppConnectionService.databaseBackend.loadIdentityKeys(account, name); - //return trustedKeys.isEmpty() || trustedKeys.contains(identityKey); return true; } + public Trust getFingerprintTrust(String name, String fingerprint) { + return mXmppConnectionService.databaseBackend.isIdentityKeyTrusted(account, name, fingerprint); + } + + public void setFingerprintTrust(String name, String fingerprint, Trust trust) { + mXmppConnectionService.databaseBackend.setIdentityKeyTrust(account, name, fingerprint, trust); + } + // -------------------------------------- // SessionStore // -------------------------------------- @@ -325,14 +349,6 @@ public class AxolotlService { new AxolotlAddress(name, 0)); } - public boolean isTrustedSession(AxolotlAddress address) { - return mXmppConnectionService.databaseBackend.isTrustedSession(this.account, address); - } - - public void setTrustedSession(AxolotlAddress address, boolean trusted) { - mXmppConnectionService.databaseBackend.setTrustedSession(this.account, address, trusted); - } - // -------------------------------------- // PreKeyStore // -------------------------------------- @@ -453,27 +469,22 @@ public class AxolotlService { public static class XmppAxolotlSession { private final SessionCipher cipher; - private boolean isTrusted = false; private Integer preKeyId = null; private final SQLiteAxolotlStore sqLiteAxolotlStore; private final AxolotlAddress remoteAddress; private final Account account; + private String fingerprint = null; + + public XmppAxolotlSession(Account account, SQLiteAxolotlStore store, AxolotlAddress remoteAddress, String fingerprint) { + this(account, store, remoteAddress); + this.fingerprint = fingerprint; + } public XmppAxolotlSession(Account account, SQLiteAxolotlStore store, AxolotlAddress remoteAddress) { this.cipher = new SessionCipher(store, remoteAddress); this.remoteAddress = remoteAddress; this.sqLiteAxolotlStore = store; this.account = account; - this.isTrusted = sqLiteAxolotlStore.isTrustedSession(remoteAddress); - } - - public void trust() { - sqLiteAxolotlStore.setTrustedSession(remoteAddress, true); - this.isTrusted = true; - } - - public boolean isTrusted() { - return this.isTrusted; } public Integer getPreKeyId() { @@ -481,18 +492,29 @@ public class AxolotlService { } public void resetPreKeyId() { + preKeyId = null; } + public String getFingerprint() { + return fingerprint; + } + 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()); - plaintext = cipher.decrypt(message); - if (message.getPreKeyId().isPresent()) { - preKeyId = message.getPreKeyId().get(); + 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"); @@ -582,7 +604,9 @@ public class AxolotlService { List deviceIDs = store.getSubDeviceSessions(address); for (Integer deviceId : deviceIDs) { AxolotlAddress axolotlAddress = new AxolotlAddress(address, deviceId); - this.put(axolotlAddress, new XmppAxolotlSession(account, store, axolotlAddress)); + Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Building session for remote address: "+axolotlAddress.toString()); + String fingerprint = store.loadSession(axolotlAddress).getSessionState().getRemoteIdentityKey().getFingerprint().replaceAll("\\s", ""); + this.put(axolotlAddress, new XmppAxolotlSession(account, store, axolotlAddress, fingerprint)); } } } @@ -619,18 +643,6 @@ public class AxolotlService { return axolotlStore.getIdentityKeyPair().getPublicKey(); } - public void trustSession(AxolotlAddress counterpart) { - XmppAxolotlSession session = sessions.get(counterpart); - if (session != null) { - session.trust(); - } - } - - public boolean isTrustedSession(AxolotlAddress counterpart) { - XmppAxolotlSession session = sessions.get(counterpart); - return session != null && session.isTrusted(); - } - private AxolotlAddress getAddressForJid(Jid jid) { return new AxolotlAddress(jid.toString(), 0); } @@ -808,11 +820,19 @@ public class AxolotlService { } public boolean isContactAxolotlCapable(Contact contact) { + Jid jid = contact.getJid().toBareJid(); AxolotlAddress address = new AxolotlAddress(jid.toString(), 0); return sessions.hasAny(address) || ( deviceIds.containsKey(jid) && !deviceIds.get(jid).isEmpty()); } + public SQLiteAxolotlStore.Trust getFingerprintTrust(String name, String fingerprint) { + return axolotlStore.getFingerprintTrust(name, fingerprint); + } + + public void setFingerprintTrust(String name, String fingerprint, SQLiteAxolotlStore.Trust trust) { + axolotlStore.setFingerprintTrust(name, fingerprint, trust); + } private void buildSessionFromPEP(final Conversation conversation, final AxolotlAddress address) { Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Building new sesstion for " + address.getDeviceId()); @@ -851,7 +871,7 @@ public class AxolotlService { try { SessionBuilder builder = new SessionBuilder(axolotlStore, address); builder.process(preKeyBundle); - XmppAxolotlSession session = new XmppAxolotlSession(account, axolotlStore, address); + XmppAxolotlSession session = new XmppAxolotlSession(account, axolotlStore, address, bundle.getIdentityKey().getFingerprint().replaceAll("\\s", "")); sessions.put(address, session); fetchStatusMap.put(address, FetchStatus.SUCCESS); } catch (UntrustedIdentityException|InvalidKeyException e) { @@ -890,7 +910,7 @@ public class AxolotlService { addresses.add(new AxolotlAddress(contactJid.toString(), foreignId)); } } else { - Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Have no target devices in PEP!"); + Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Have no target devices in PEP!"); } Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Checking own account "+account.getJid().toBareJid()); if(deviceIds.get(account.getJid().toBareJid()) != null) { @@ -1003,7 +1023,7 @@ public class AxolotlService { byte[] payloadKey = session.processReceiving(header); if (payloadKey != null) { Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Got payload key from axolotl header. Decrypting message..."); - plaintextMessage = message.decrypt(session, payloadKey); + plaintextMessage = message.decrypt(session, payloadKey, session.getFingerprint()); } Integer preKeyId = session.getPreKeyId(); if (preKeyId != null) { 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 06dd2cda..45995228 100644 --- a/src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlMessage.java +++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlMessage.java @@ -67,10 +67,12 @@ public class XmppAxolotlMessage { public static class XmppAxolotlPlaintextMessage { private final AxolotlService.XmppAxolotlSession session; private final String plaintext; + private final String fingerprint; - public XmppAxolotlPlaintextMessage(AxolotlService.XmppAxolotlSession session, String plaintext) { + public XmppAxolotlPlaintextMessage(AxolotlService.XmppAxolotlSession session, String plaintext, String fingerprint) { this.session = session; this.plaintext = plaintext; + this.fingerprint = fingerprint; } public String getPlaintext() { @@ -81,6 +83,9 @@ public class XmppAxolotlMessage { return session; } + public String getFingerprint() { + return fingerprint; + } } public XmppAxolotlMessage(Jid from, Element axolotlMessage) { @@ -167,7 +172,7 @@ public class XmppAxolotlMessage { } - public XmppAxolotlPlaintextMessage decrypt(AxolotlService.XmppAxolotlSession session, byte[] key) { + public XmppAxolotlPlaintextMessage decrypt(AxolotlService.XmppAxolotlSession session, byte[] key, String fingerprint) { XmppAxolotlPlaintextMessage plaintextMessage = null; try { @@ -178,7 +183,7 @@ public class XmppAxolotlMessage { cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec); String plaintext = new String(cipher.doFinal(ciphertext)); - plaintextMessage = new XmppAxolotlPlaintextMessage(session, plaintext); + plaintextMessage = new XmppAxolotlPlaintextMessage(session, plaintext, fingerprint); } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException -- cgit v1.2.3