Use more generic AxololAddress for identifying recipients.

This commit is contained in:
Moxie Marlinspike 2015-03-03 11:20:36 -08:00
parent d53ed1bb00
commit 327f82be41
13 changed files with 254 additions and 227 deletions

View File

@ -0,0 +1,39 @@
package org.whispersystems.libaxolotl;
public class AxolotlAddress {
private final String name;
private final int deviceId;
public AxolotlAddress(String name, int deviceId) {
this.name = name;
this.deviceId = deviceId;
}
public String getName() {
return name;
}
public int getDeviceId() {
return deviceId;
}
@Override
public String toString() {
return name + ":" + deviceId;
}
@Override
public boolean equals(Object other) {
if (other == null) return false;
if (!(other instanceof AxolotlAddress)) return false;
AxolotlAddress that = (AxolotlAddress)other;
return this.name.equals(that.name) && this.deviceId == that.deviceId;
}
@Override
public int hashCode() {
return this.name.hashCode() ^ this.deviceId;
}
}

View File

@ -49,8 +49,7 @@ public class SessionBuilder {
private final PreKeyStore preKeyStore; private final PreKeyStore preKeyStore;
private final SignedPreKeyStore signedPreKeyStore; private final SignedPreKeyStore signedPreKeyStore;
private final IdentityKeyStore identityKeyStore; private final IdentityKeyStore identityKeyStore;
private final long recipientId; private final AxolotlAddress remoteAddress;
private final int deviceId;
/** /**
* Constructs a SessionBuilder. * Constructs a SessionBuilder.
@ -58,31 +57,28 @@ public class SessionBuilder {
* @param sessionStore The {@link org.whispersystems.libaxolotl.state.SessionStore} to store the constructed session in. * @param sessionStore The {@link org.whispersystems.libaxolotl.state.SessionStore} to store the constructed session in.
* @param preKeyStore The {@link org.whispersystems.libaxolotl.state.PreKeyStore} where the client's local {@link org.whispersystems.libaxolotl.state.PreKeyRecord}s are stored. * @param preKeyStore The {@link org.whispersystems.libaxolotl.state.PreKeyStore} where the client's local {@link org.whispersystems.libaxolotl.state.PreKeyRecord}s are stored.
* @param identityKeyStore The {@link org.whispersystems.libaxolotl.state.IdentityKeyStore} containing the client's identity key information. * @param identityKeyStore The {@link org.whispersystems.libaxolotl.state.IdentityKeyStore} containing the client's identity key information.
* @param recipientId The recipient ID of the remote user to build a session with. * @param remoteAddress The address of the remote user to build a session with.
* @param deviceId The device ID of the remote user's physical device.
*/ */
public SessionBuilder(SessionStore sessionStore, public SessionBuilder(SessionStore sessionStore,
PreKeyStore preKeyStore, PreKeyStore preKeyStore,
SignedPreKeyStore signedPreKeyStore, SignedPreKeyStore signedPreKeyStore,
IdentityKeyStore identityKeyStore, IdentityKeyStore identityKeyStore,
long recipientId, int deviceId) AxolotlAddress remoteAddress)
{ {
this.sessionStore = sessionStore; this.sessionStore = sessionStore;
this.preKeyStore = preKeyStore; this.preKeyStore = preKeyStore;
this.signedPreKeyStore = signedPreKeyStore; this.signedPreKeyStore = signedPreKeyStore;
this.identityKeyStore = identityKeyStore; this.identityKeyStore = identityKeyStore;
this.recipientId = recipientId; this.remoteAddress = remoteAddress;
this.deviceId = deviceId;
} }
/** /**
* Constructs a SessionBuilder * Constructs a SessionBuilder
* @param store The {@link org.whispersystems.libaxolotl.state.AxolotlStore} to store all state information in. * @param store The {@link org.whispersystems.libaxolotl.state.AxolotlStore} to store all state information in.
* @param recipientId The recipient ID of the remote user to build a session with. * @param remoteAddress The address of the remote user to build a session with.
* @param deviceId The device ID of the remote user's physical device.
*/ */
public SessionBuilder(AxolotlStore store, long recipientId, int deviceId) { public SessionBuilder(AxolotlStore store, AxolotlAddress remoteAddress) {
this(store, store, store, store, recipientId, deviceId); this(store, store, store, store, remoteAddress);
} }
/** /**
@ -107,7 +103,7 @@ public class SessionBuilder {
Optional<Integer> unsignedPreKeyId; Optional<Integer> unsignedPreKeyId;
if (!identityKeyStore.isTrustedIdentity(recipientId, theirIdentityKey)) { if (!identityKeyStore.isTrustedIdentity(remoteAddress.getName(), theirIdentityKey)) {
throw new UntrustedIdentityException(); throw new UntrustedIdentityException();
} }
@ -117,7 +113,7 @@ public class SessionBuilder {
default: throw new AssertionError("Unknown version: " + messageVersion); default: throw new AssertionError("Unknown version: " + messageVersion);
} }
identityKeyStore.saveIdentity(recipientId, theirIdentityKey); identityKeyStore.saveIdentity(remoteAddress.getName(), theirIdentityKey);
return unsignedPreKeyId; return unsignedPreKeyId;
} }
@ -169,7 +165,7 @@ public class SessionBuilder {
} }
if (!preKeyStore.containsPreKey(message.getPreKeyId().get()) && if (!preKeyStore.containsPreKey(message.getPreKeyId().get()) &&
sessionStore.containsSession(recipientId, deviceId)) sessionStore.containsSession(remoteAddress))
{ {
Log.w(TAG, "We've already processed the prekey part of this V2 session, letting bundled message fall through..."); Log.w(TAG, "We've already processed the prekey part of this V2 session, letting bundled message fall through...");
return Optional.absent(); return Optional.absent();
@ -214,7 +210,7 @@ public class SessionBuilder {
*/ */
public void process(PreKeyBundle preKey) throws InvalidKeyException, UntrustedIdentityException { public void process(PreKeyBundle preKey) throws InvalidKeyException, UntrustedIdentityException {
synchronized (SessionCipher.SESSION_LOCK) { synchronized (SessionCipher.SESSION_LOCK) {
if (!identityKeyStore.isTrustedIdentity(recipientId, preKey.getIdentityKey())) { if (!identityKeyStore.isTrustedIdentity(remoteAddress.getName(), preKey.getIdentityKey())) {
throw new UntrustedIdentityException(); throw new UntrustedIdentityException();
} }
@ -231,7 +227,7 @@ public class SessionBuilder {
} }
boolean supportsV3 = preKey.getSignedPreKey() != null; boolean supportsV3 = preKey.getSignedPreKey() != null;
SessionRecord sessionRecord = sessionStore.loadSession(recipientId, deviceId); SessionRecord sessionRecord = sessionStore.loadSession(remoteAddress);
ECKeyPair ourBaseKey = Curve.generateKeyPair(); ECKeyPair ourBaseKey = Curve.generateKeyPair();
ECPublicKey theirSignedPreKey = supportsV3 ? preKey.getSignedPreKey() : preKey.getPreKey(); ECPublicKey theirSignedPreKey = supportsV3 ? preKey.getSignedPreKey() : preKey.getPreKey();
Optional<ECPublicKey> theirOneTimePreKey = Optional.fromNullable(preKey.getPreKey()); Optional<ECPublicKey> theirOneTimePreKey = Optional.fromNullable(preKey.getPreKey());
@ -258,8 +254,8 @@ public class SessionBuilder {
sessionRecord.getSessionState().setRemoteRegistrationId(preKey.getRegistrationId()); sessionRecord.getSessionState().setRemoteRegistrationId(preKey.getRegistrationId());
sessionRecord.getSessionState().setAliceBaseKey(ourBaseKey.getPublicKey().serialize()); sessionRecord.getSessionState().setAliceBaseKey(ourBaseKey.getPublicKey().serialize());
sessionStore.storeSession(recipientId, deviceId, sessionRecord); sessionStore.storeSession(remoteAddress, sessionRecord);
identityKeyStore.saveIdentity(recipientId, preKey.getIdentityKey()); identityKeyStore.saveIdentity(remoteAddress.getName(), preKey.getIdentityKey());
} }
} }
@ -275,7 +271,7 @@ public class SessionBuilder {
throws InvalidKeyException, UntrustedIdentityException, StaleKeyExchangeException throws InvalidKeyException, UntrustedIdentityException, StaleKeyExchangeException
{ {
synchronized (SessionCipher.SESSION_LOCK) { synchronized (SessionCipher.SESSION_LOCK) {
if (!identityKeyStore.isTrustedIdentity(recipientId, message.getIdentityKey())) { if (!identityKeyStore.isTrustedIdentity(remoteAddress.getName(), message.getIdentityKey())) {
throw new UntrustedIdentityException(); throw new UntrustedIdentityException();
} }
@ -290,7 +286,7 @@ public class SessionBuilder {
private KeyExchangeMessage processInitiate(KeyExchangeMessage message) throws InvalidKeyException { private KeyExchangeMessage processInitiate(KeyExchangeMessage message) throws InvalidKeyException {
int flags = KeyExchangeMessage.RESPONSE_FLAG; int flags = KeyExchangeMessage.RESPONSE_FLAG;
SessionRecord sessionRecord = sessionStore.loadSession(recipientId, deviceId); SessionRecord sessionRecord = sessionStore.loadSession(remoteAddress);
if (message.getVersion() >= 3 && if (message.getVersion() >= 3 &&
!Curve.verifySignature(message.getIdentityKey().getPublicKey(), !Curve.verifySignature(message.getIdentityKey().getPublicKey(),
@ -325,8 +321,8 @@ public class SessionBuilder {
Math.min(message.getMaxVersion(), CiphertextMessage.CURRENT_VERSION), Math.min(message.getMaxVersion(), CiphertextMessage.CURRENT_VERSION),
parameters); parameters);
sessionStore.storeSession(recipientId, deviceId, sessionRecord); sessionStore.storeSession(remoteAddress, sessionRecord);
identityKeyStore.saveIdentity(recipientId, message.getIdentityKey()); identityKeyStore.saveIdentity(remoteAddress.getName(), message.getIdentityKey());
byte[] baseKeySignature = Curve.calculateSignature(parameters.getOurIdentityKey().getPrivateKey(), byte[] baseKeySignature = Curve.calculateSignature(parameters.getOurIdentityKey().getPrivateKey(),
parameters.getOurBaseKey().getPublicKey().serialize()); parameters.getOurBaseKey().getPublicKey().serialize());
@ -341,7 +337,7 @@ public class SessionBuilder {
private void processResponse(KeyExchangeMessage message) private void processResponse(KeyExchangeMessage message)
throws StaleKeyExchangeException, InvalidKeyException throws StaleKeyExchangeException, InvalidKeyException
{ {
SessionRecord sessionRecord = sessionStore.loadSession(recipientId, deviceId); SessionRecord sessionRecord = sessionStore.loadSession(remoteAddress);
SessionState sessionState = sessionRecord.getSessionState(); SessionState sessionState = sessionRecord.getSessionState();
boolean hasPendingKeyExchange = sessionState.hasPendingKeyExchange(); boolean hasPendingKeyExchange = sessionState.hasPendingKeyExchange();
boolean isSimultaneousInitiateResponse = message.isResponseForSimultaneousInitiate(); boolean isSimultaneousInitiateResponse = message.isResponseForSimultaneousInitiate();
@ -375,8 +371,8 @@ public class SessionBuilder {
throw new InvalidKeyException("Base key signature doesn't match!"); throw new InvalidKeyException("Base key signature doesn't match!");
} }
sessionStore.storeSession(recipientId, deviceId, sessionRecord); sessionStore.storeSession(remoteAddress, sessionRecord);
identityKeyStore.saveIdentity(recipientId, message.getIdentityKey()); identityKeyStore.saveIdentity(remoteAddress.getName(), message.getIdentityKey());
} }
@ -394,10 +390,10 @@ public class SessionBuilder {
ECKeyPair ratchetKey = Curve.generateKeyPair(); ECKeyPair ratchetKey = Curve.generateKeyPair();
IdentityKeyPair identityKey = identityKeyStore.getIdentityKeyPair(); IdentityKeyPair identityKey = identityKeyStore.getIdentityKeyPair();
byte[] baseKeySignature = Curve.calculateSignature(identityKey.getPrivateKey(), baseKey.getPublicKey().serialize()); byte[] baseKeySignature = Curve.calculateSignature(identityKey.getPrivateKey(), baseKey.getPublicKey().serialize());
SessionRecord sessionRecord = sessionStore.loadSession(recipientId, deviceId); SessionRecord sessionRecord = sessionStore.loadSession(remoteAddress);
sessionRecord.getSessionState().setPendingKeyExchange(sequence, baseKey, ratchetKey, identityKey); sessionRecord.getSessionState().setPendingKeyExchange(sequence, baseKey, ratchetKey, identityKey);
sessionStore.storeSession(recipientId, deviceId, sessionRecord); sessionStore.storeSession(remoteAddress, sessionRecord);
return new KeyExchangeMessage(2, sequence, flags, baseKey.getPublicKey(), baseKeySignature, return new KeyExchangeMessage(2, sequence, flags, baseKey.getPublicKey(), baseKeySignature,
ratchetKey.getPublicKey(), identityKey.getPublicKey()); ratchetKey.getPublicKey(), identityKey.getPublicKey());

View File

@ -67,8 +67,7 @@ public class SessionCipher {
private final SessionStore sessionStore; private final SessionStore sessionStore;
private final SessionBuilder sessionBuilder; private final SessionBuilder sessionBuilder;
private final PreKeyStore preKeyStore; private final PreKeyStore preKeyStore;
private final long recipientId; private final AxolotlAddress remoteAddress;
private final int deviceId;
/** /**
* Construct a SessionCipher for encrypt/decrypt operations on a session. * Construct a SessionCipher for encrypt/decrypt operations on a session.
@ -76,23 +75,21 @@ public class SessionCipher {
* and stored using {@link SessionBuilder}. * and stored using {@link SessionBuilder}.
* *
* @param sessionStore The {@link SessionStore} that contains a session for this recipient. * @param sessionStore The {@link SessionStore} that contains a session for this recipient.
* @param recipientId The remote ID that messages will be encrypted to or decrypted from. * @param remoteAddress The remote address that messages will be encrypted to or decrypted from.
* @param deviceId The device corresponding to the recipientId.
*/ */
public SessionCipher(SessionStore sessionStore, PreKeyStore preKeyStore, public SessionCipher(SessionStore sessionStore, PreKeyStore preKeyStore,
SignedPreKeyStore signedPreKeyStore, IdentityKeyStore identityKeyStore, SignedPreKeyStore signedPreKeyStore, IdentityKeyStore identityKeyStore,
long recipientId, int deviceId) AxolotlAddress remoteAddress)
{ {
this.sessionStore = sessionStore; this.sessionStore = sessionStore;
this.recipientId = recipientId;
this.deviceId = deviceId;
this.preKeyStore = preKeyStore; this.preKeyStore = preKeyStore;
this.remoteAddress = remoteAddress;
this.sessionBuilder = new SessionBuilder(sessionStore, preKeyStore, signedPreKeyStore, this.sessionBuilder = new SessionBuilder(sessionStore, preKeyStore, signedPreKeyStore,
identityKeyStore, recipientId, deviceId); identityKeyStore, remoteAddress);
} }
public SessionCipher(AxolotlStore store, long recipientId, int deviceId) { public SessionCipher(AxolotlStore store, AxolotlAddress remoteAddress) {
this(store, store, store, store, recipientId, deviceId); this(store, store, store, store, remoteAddress);
} }
/** /**
@ -103,7 +100,7 @@ public class SessionCipher {
*/ */
public CiphertextMessage encrypt(byte[] paddedMessage) { public CiphertextMessage encrypt(byte[] paddedMessage) {
synchronized (SESSION_LOCK) { synchronized (SESSION_LOCK) {
SessionRecord sessionRecord = sessionStore.loadSession(recipientId, deviceId); SessionRecord sessionRecord = sessionStore.loadSession(remoteAddress);
SessionState sessionState = sessionRecord.getSessionState(); SessionState sessionState = sessionRecord.getSessionState();
ChainKey chainKey = sessionState.getSenderChainKey(); ChainKey chainKey = sessionState.getSenderChainKey();
MessageKeys messageKeys = chainKey.getMessageKeys(); MessageKeys messageKeys = chainKey.getMessageKeys();
@ -129,7 +126,7 @@ public class SessionCipher {
} }
sessionState.setSenderChainKey(chainKey.getNextChainKey()); sessionState.setSenderChainKey(chainKey.getNextChainKey());
sessionStore.storeSession(recipientId, deviceId, sessionRecord); sessionStore.storeSession(remoteAddress, sessionRecord);
return ciphertextMessage; return ciphertextMessage;
} }
} }
@ -182,13 +179,13 @@ public class SessionCipher {
InvalidKeyIdException, InvalidKeyException, UntrustedIdentityException InvalidKeyIdException, InvalidKeyException, UntrustedIdentityException
{ {
synchronized (SESSION_LOCK) { synchronized (SESSION_LOCK) {
SessionRecord sessionRecord = sessionStore.loadSession(recipientId, deviceId); SessionRecord sessionRecord = sessionStore.loadSession(remoteAddress);
Optional<Integer> unsignedPreKeyId = sessionBuilder.process(sessionRecord, ciphertext); Optional<Integer> unsignedPreKeyId = sessionBuilder.process(sessionRecord, ciphertext);
byte[] plaintext = decrypt(sessionRecord, ciphertext.getWhisperMessage()); byte[] plaintext = decrypt(sessionRecord, ciphertext.getWhisperMessage());
callback.handlePlaintext(plaintext); callback.handlePlaintext(plaintext);
sessionStore.storeSession(recipientId, deviceId, sessionRecord); sessionStore.storeSession(remoteAddress, sessionRecord);
if (unsignedPreKeyId.isPresent()) { if (unsignedPreKeyId.isPresent()) {
preKeyStore.removePreKey(unsignedPreKeyId.get()); preKeyStore.removePreKey(unsignedPreKeyId.get());
@ -241,16 +238,16 @@ public class SessionCipher {
{ {
synchronized (SESSION_LOCK) { synchronized (SESSION_LOCK) {
if (!sessionStore.containsSession(recipientId, deviceId)) { if (!sessionStore.containsSession(remoteAddress)) {
throw new NoSessionException("No session for: " + recipientId + ", " + deviceId); throw new NoSessionException("No session for: " + remoteAddress);
} }
SessionRecord sessionRecord = sessionStore.loadSession(recipientId, deviceId); SessionRecord sessionRecord = sessionStore.loadSession(remoteAddress);
byte[] plaintext = decrypt(sessionRecord, ciphertext); byte[] plaintext = decrypt(sessionRecord, ciphertext);
callback.handlePlaintext(plaintext); callback.handlePlaintext(plaintext);
sessionStore.storeSession(recipientId, deviceId, sessionRecord); sessionStore.storeSession(remoteAddress, sessionRecord);
return plaintext; return plaintext;
} }
@ -325,18 +322,18 @@ public class SessionCipher {
public int getRemoteRegistrationId() { public int getRemoteRegistrationId() {
synchronized (SESSION_LOCK) { synchronized (SESSION_LOCK) {
SessionRecord record = sessionStore.loadSession(recipientId, deviceId); SessionRecord record = sessionStore.loadSession(remoteAddress);
return record.getSessionState().getRemoteRegistrationId(); return record.getSessionState().getRemoteRegistrationId();
} }
} }
public int getSessionVersion() { public int getSessionVersion() {
synchronized (SESSION_LOCK) { synchronized (SESSION_LOCK) {
if (!sessionStore.containsSession(recipientId, deviceId)) { if (!sessionStore.containsSession(remoteAddress)) {
throw new IllegalStateException(String.format("No session for (%d, %d)!", recipientId, deviceId)); throw new IllegalStateException(String.format("No session for (%s)!", remoteAddress));
} }
SessionRecord record = sessionStore.loadSession(recipientId, deviceId); SessionRecord record = sessionStore.loadSession(remoteAddress);
return record.getSessionState().getSessionVersion(); return record.getSessionState().getSessionVersion();
} }
} }

View File

@ -16,35 +16,31 @@
*/ */
package org.whispersystems.libaxolotl.groups; package org.whispersystems.libaxolotl.groups;
import org.whispersystems.libaxolotl.AxolotlAddress;
/** /**
* A representation of a (groupId + senderId + deviceId) tuple. * A representation of a (groupId + senderId + deviceId) tuple.
*/ */
public class SenderKeyName { public class SenderKeyName {
private final String groupId; private final String groupId;
private final long senderId; private final AxolotlAddress sender;
private final int deviceId;
public SenderKeyName(String groupId, long senderId, int deviceId) { public SenderKeyName(String groupId, AxolotlAddress sender) {
this.groupId = groupId; this.groupId = groupId;
this.senderId = senderId; this.sender = sender;
this.deviceId = deviceId;
} }
public String getGroupId() { public String getGroupId() {
return groupId; return groupId;
} }
public long getSenderId() { public AxolotlAddress getSender() {
return senderId; return sender;
}
public int getDeviceId() {
return deviceId;
} }
public String serialize() { public String serialize() {
return groupId + "::" + String.valueOf(senderId) + "::" + String.valueOf(deviceId); return groupId + "::" + sender.getName() + "::" + String.valueOf(sender.getDeviceId());
} }
@Override @Override
@ -56,13 +52,12 @@ public class SenderKeyName {
return return
this.groupId.equals(that.groupId) && this.groupId.equals(that.groupId) &&
this.senderId == that.senderId && this.sender.equals(that.sender);
this.deviceId == that.deviceId;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return this.groupId.hashCode() ^ (int)this.senderId ^ this.deviceId; return this.groupId.hashCode() ^ this.sender.hashCode();
} }
} }

View File

@ -32,10 +32,10 @@ public interface IdentityKeyStore {
* <p> * <p>
* Store a remote client's identity key as trusted. * Store a remote client's identity key as trusted.
* *
* @param recipientId The recipient ID of the remote client. * @param name The name of the remote client.
* @param identityKey The remote client's identity key. * @param identityKey The remote client's identity key.
*/ */
public void saveIdentity(long recipientId, IdentityKey identityKey); public void saveIdentity(String name, IdentityKey identityKey);
/** /**
@ -48,10 +48,10 @@ public interface IdentityKeyStore {
* store. Only if it mismatches an entry in the local store is it considered * store. Only if it mismatches an entry in the local store is it considered
* 'untrusted.' * 'untrusted.'
* *
* @param recipientId The recipient ID of the remote client. * @param name The name of the remote client.
* @param identityKey The identity key to verify. * @param identityKey The identity key to verify.
* @return true if trusted, false if untrusted. * @return true if trusted, false if untrusted.
*/ */
public boolean isTrustedIdentity(long recipientId, IdentityKey identityKey); public boolean isTrustedIdentity(String name, IdentityKey identityKey);
} }

View File

@ -1,5 +1,7 @@
package org.whispersystems.libaxolotl.state; package org.whispersystems.libaxolotl.state;
import org.whispersystems.libaxolotl.AxolotlAddress;
import java.util.List; import java.util.List;
/** /**
@ -19,50 +21,46 @@ public interface SessionStore {
* durable session state (what is returned by subsequent calls to this method) without the * durable session state (what is returned by subsequent calls to this method) without the
* store method being called here first. * store method being called here first.
* *
* @param recipientId The recipientID of the remote client. * @param address The name and device ID of the remote client.
* @param deviceId The deviceID of the remote client.
* @return a copy of the SessionRecord corresponding to the recipientId + deviceId tuple, or * @return a copy of the SessionRecord corresponding to the recipientId + deviceId tuple, or
* a new SessionRecord if one does not currently exist. * a new SessionRecord if one does not currently exist.
*/ */
public SessionRecord loadSession(long recipientId, int deviceId); public SessionRecord loadSession(AxolotlAddress address);
/** /**
* Returns all known devices with active sessions for a recipient * Returns all known devices with active sessions for a recipient
* *
* @param recipientId the recipient ID. * @param name the name of the client.
* @return all known sub-devices with active sessions. * @return all known sub-devices with active sessions.
*/ */
public List<Integer> getSubDeviceSessions(long recipientId); public List<Integer> getSubDeviceSessions(String name);
/** /**
* Commit to storage the {@link SessionRecord} for a given recipientId + deviceId tuple. * Commit to storage the {@link SessionRecord} for a given recipientId + deviceId tuple.
* @param recipientId the recipient ID of the remote client. * @param address the address of the remote client.
* @param deviceId the device ID of the remote client.
* @param record the current SessionRecord for the remote client. * @param record the current SessionRecord for the remote client.
*/ */
public void storeSession(long recipientId, int deviceId, SessionRecord record); public void storeSession(AxolotlAddress address, SessionRecord record);
/** /**
* Determine whether there is a committed {@link SessionRecord} for a recipientId + deviceId tuple. * Determine whether there is a committed {@link SessionRecord} for a recipientId + deviceId tuple.
* @param recipientId the recipient ID of the remote client. * @param address the address of the remote client.
* @param deviceId the device ID of the remote client.
* @return true if a {@link SessionRecord} exists, false otherwise. * @return true if a {@link SessionRecord} exists, false otherwise.
*/ */
public boolean containsSession(long recipientId, int deviceId); public boolean containsSession(AxolotlAddress address);
/** /**
* Remove a {@link SessionRecord} for a recipientId + deviceId tuple. * Remove a {@link SessionRecord} for a recipientId + deviceId tuple.
* *
* @param recipientId the recipient ID of the remote client. * @param address the address of the remote client.
* @param deviceId the device ID of the remote client.
*/ */
public void deleteSession(long recipientId, int deviceId); public void deleteSession(AxolotlAddress address);
/** /**
* Remove the {@link SessionRecord}s corresponding to all devices of a recipientId. * Remove the {@link SessionRecord}s corresponding to all devices of a recipientId.
* *
* @param recipientId the recipient ID of the remote client. * @param name the name of the remote client.
*/ */
public void deleteAllSessions(long recipientId); public void deleteAllSessions(String name);
} }

View File

@ -26,13 +26,13 @@ public class InMemoryAxolotlStore implements AxolotlStore {
} }
@Override @Override
public void saveIdentity(long recipientId, IdentityKey identityKey) { public void saveIdentity(String name, IdentityKey identityKey) {
identityKeyStore.saveIdentity(recipientId, identityKey); identityKeyStore.saveIdentity(name, identityKey);
} }
@Override @Override
public boolean isTrustedIdentity(long recipientId, IdentityKey identityKey) { public boolean isTrustedIdentity(String name, IdentityKey identityKey) {
return identityKeyStore.isTrustedIdentity(recipientId, identityKey); return identityKeyStore.isTrustedIdentity(name, identityKey);
} }
@Override @Override
@ -56,33 +56,33 @@ public class InMemoryAxolotlStore implements AxolotlStore {
} }
@Override @Override
public SessionRecord loadSession(long recipientId, int deviceId) { public SessionRecord loadSession(AxolotlAddress address) {
return sessionStore.loadSession(recipientId, deviceId); return sessionStore.loadSession(address);
} }
@Override @Override
public List<Integer> getSubDeviceSessions(long recipientId) { public List<Integer> getSubDeviceSessions(String name) {
return sessionStore.getSubDeviceSessions(recipientId); return sessionStore.getSubDeviceSessions(name);
} }
@Override @Override
public void storeSession(long recipientId, int deviceId, SessionRecord record) { public void storeSession(AxolotlAddress address, SessionRecord record) {
sessionStore.storeSession(recipientId, deviceId, record); sessionStore.storeSession(address, record);
} }
@Override @Override
public boolean containsSession(long recipientId, int deviceId) { public boolean containsSession(AxolotlAddress address) {
return sessionStore.containsSession(recipientId, deviceId); return sessionStore.containsSession(address);
} }
@Override @Override
public void deleteSession(long recipientId, int deviceId) { public void deleteSession(AxolotlAddress address) {
sessionStore.deleteSession(recipientId, deviceId); sessionStore.deleteSession(address);
} }
@Override @Override
public void deleteAllSessions(long recipientId) { public void deleteAllSessions(String name) {
sessionStore.deleteAllSessions(recipientId); sessionStore.deleteAllSessions(name);
} }
@Override @Override

View File

@ -11,7 +11,7 @@ import java.util.Map;
public class InMemoryIdentityKeyStore implements IdentityKeyStore { public class InMemoryIdentityKeyStore implements IdentityKeyStore {
private final Map<Long, IdentityKey> trustedKeys = new HashMap<>(); private final Map<String, IdentityKey> trustedKeys = new HashMap<>();
private final IdentityKeyPair identityKeyPair; private final IdentityKeyPair identityKeyPair;
private final int localRegistrationId; private final int localRegistrationId;
@ -39,13 +39,13 @@ public class InMemoryIdentityKeyStore implements IdentityKeyStore {
} }
@Override @Override
public void saveIdentity(long recipientId, IdentityKey identityKey) { public void saveIdentity(String name, IdentityKey identityKey) {
trustedKeys.put(recipientId, identityKey); trustedKeys.put(name, identityKey);
} }
@Override @Override
public boolean isTrustedIdentity(long recipientId, IdentityKey identityKey) { public boolean isTrustedIdentity(String name, IdentityKey identityKey) {
IdentityKey trusted = trustedKeys.get(recipientId); IdentityKey trusted = trustedKeys.get(name);
return (trusted == null || trusted.equals(identityKey)); return (trusted == null || trusted.equals(identityKey));
} }
} }

View File

@ -2,7 +2,6 @@ package org.whispersystems.libaxolotl;
import org.whispersystems.libaxolotl.state.SessionRecord; import org.whispersystems.libaxolotl.state.SessionRecord;
import org.whispersystems.libaxolotl.state.SessionStore; import org.whispersystems.libaxolotl.state.SessionStore;
import org.whispersystems.libaxolotl.util.Pair;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
@ -12,15 +11,15 @@ import java.util.Map;
public class InMemorySessionStore implements SessionStore { public class InMemorySessionStore implements SessionStore {
private Map<Pair<Long, Integer>, byte[]> sessions = new HashMap<>(); private Map<AxolotlAddress, byte[]> sessions = new HashMap<>();
public InMemorySessionStore() {} public InMemorySessionStore() {}
@Override @Override
public synchronized SessionRecord loadSession(long recipientId, int deviceId) { public synchronized SessionRecord loadSession(AxolotlAddress remoteAddress) {
try { try {
if (containsSession(recipientId, deviceId)) { if (containsSession(remoteAddress)) {
return new SessionRecord(sessions.get(new Pair<>(recipientId, deviceId))); return new SessionRecord(sessions.get(remoteAddress));
} else { } else {
return new SessionRecord(); return new SessionRecord();
} }
@ -30,12 +29,12 @@ public class InMemorySessionStore implements SessionStore {
} }
@Override @Override
public synchronized List<Integer> getSubDeviceSessions(long recipientId) { public synchronized List<Integer> getSubDeviceSessions(String name) {
List<Integer> deviceIds = new LinkedList<>(); List<Integer> deviceIds = new LinkedList<>();
for (Pair<Long, Integer> key : sessions.keySet()) { for (AxolotlAddress key : sessions.keySet()) {
if (key.first() == recipientId) { if (key.getName().equals(name)) {
deviceIds.add(key.second()); deviceIds.add(key.getDeviceId());
} }
} }
@ -43,24 +42,24 @@ public class InMemorySessionStore implements SessionStore {
} }
@Override @Override
public synchronized void storeSession(long recipientId, int deviceId, SessionRecord record) { public synchronized void storeSession(AxolotlAddress address, SessionRecord record) {
sessions.put(new Pair<>(recipientId, deviceId), record.serialize()); sessions.put(address, record.serialize());
} }
@Override @Override
public synchronized boolean containsSession(long recipientId, int deviceId) { public synchronized boolean containsSession(AxolotlAddress address) {
return sessions.containsKey(new Pair<>(recipientId, deviceId)); return sessions.containsKey(address);
} }
@Override @Override
public synchronized void deleteSession(long recipientId, int deviceId) { public synchronized void deleteSession(AxolotlAddress address) {
sessions.remove(new Pair<>(recipientId, deviceId)); sessions.remove(address);
} }
@Override @Override
public synchronized void deleteAllSessions(long recipientId) { public synchronized void deleteAllSessions(String name) {
for (Pair<Long, Integer> key : sessions.keySet()) { for (AxolotlAddress key : sessions.keySet()) {
if (key.first() == recipientId) { if (key.getName().equals(name)) {
sessions.remove(key); sessions.remove(key);
} }
} }

View File

@ -20,13 +20,13 @@ import java.util.Set;
public class SessionBuilderTest extends TestCase { public class SessionBuilderTest extends TestCase {
private static final long ALICE_RECIPIENT_ID = 5L; private static final AxolotlAddress ALICE_ADDRESS = new AxolotlAddress("+14151111111", 1);
private static final long BOB_RECIPIENT_ID = 2L; private static final AxolotlAddress BOB_ADDRESS = new AxolotlAddress("+14152222222", 1);
public void testBasicPreKeyV2() public void testBasicPreKeyV2()
throws InvalidKeyException, InvalidVersionException, InvalidMessageException, InvalidKeyIdException, DuplicateMessageException, LegacyMessageException, UntrustedIdentityException, NoSessionException { throws InvalidKeyException, InvalidVersionException, InvalidMessageException, InvalidKeyIdException, DuplicateMessageException, LegacyMessageException, UntrustedIdentityException, NoSessionException {
AxolotlStore aliceStore = new InMemoryAxolotlStore(); AxolotlStore aliceStore = new InMemoryAxolotlStore();
SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_RECIPIENT_ID, 1); SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);
AxolotlStore bobStore = new InMemoryAxolotlStore(); AxolotlStore bobStore = new InMemoryAxolotlStore();
ECKeyPair bobPreKeyPair = Curve.generateKeyPair(); ECKeyPair bobPreKeyPair = Curve.generateKeyPair();
@ -37,11 +37,11 @@ public class SessionBuilderTest extends TestCase {
aliceSessionBuilder.process(bobPreKey); aliceSessionBuilder.process(bobPreKey);
assertTrue(aliceStore.containsSession(BOB_RECIPIENT_ID, 1)); assertTrue(aliceStore.containsSession(BOB_ADDRESS));
assertTrue(aliceStore.loadSession(BOB_RECIPIENT_ID, 1).getSessionState().getSessionVersion() == 2); assertTrue(aliceStore.loadSession(BOB_ADDRESS).getSessionState().getSessionVersion() == 2);
String originalMessage = "L'homme est condamné à être libre"; String originalMessage = "L'homme est condamné à être libre";
SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_RECIPIENT_ID, 1); SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_ADDRESS);
CiphertextMessage outgoingMessage = aliceSessionCipher.encrypt(originalMessage.getBytes()); CiphertextMessage outgoingMessage = aliceSessionCipher.encrypt(originalMessage.getBytes());
assertTrue(outgoingMessage.getType() == CiphertextMessage.PREKEY_TYPE); assertTrue(outgoingMessage.getType() == CiphertextMessage.PREKEY_TYPE);
@ -49,11 +49,11 @@ public class SessionBuilderTest extends TestCase {
PreKeyWhisperMessage incomingMessage = new PreKeyWhisperMessage(outgoingMessage.serialize()); PreKeyWhisperMessage incomingMessage = new PreKeyWhisperMessage(outgoingMessage.serialize());
bobStore.storePreKey(31337, new PreKeyRecord(bobPreKey.getPreKeyId(), bobPreKeyPair)); bobStore.storePreKey(31337, new PreKeyRecord(bobPreKey.getPreKeyId(), bobPreKeyPair));
SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_RECIPIENT_ID, 1); SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_ADDRESS);
byte[] plaintext = bobSessionCipher.decrypt(incomingMessage); byte[] plaintext = bobSessionCipher.decrypt(incomingMessage);
assertTrue(bobStore.containsSession(ALICE_RECIPIENT_ID, 1)); assertTrue(bobStore.containsSession(ALICE_ADDRESS));
assertTrue(bobStore.loadSession(ALICE_RECIPIENT_ID, 1).getSessionState().getSessionVersion() == 2); assertTrue(bobStore.loadSession(ALICE_ADDRESS).getSessionState().getSessionVersion() == 2);
assertTrue(originalMessage.equals(new String(plaintext))); assertTrue(originalMessage.equals(new String(plaintext)));
CiphertextMessage bobOutgoingMessage = bobSessionCipher.encrypt(originalMessage.getBytes()); CiphertextMessage bobOutgoingMessage = bobSessionCipher.encrypt(originalMessage.getBytes());
@ -65,8 +65,8 @@ public class SessionBuilderTest extends TestCase {
runInteraction(aliceStore, bobStore); runInteraction(aliceStore, bobStore);
aliceStore = new InMemoryAxolotlStore(); aliceStore = new InMemoryAxolotlStore();
aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_RECIPIENT_ID, 1); aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);
aliceSessionCipher = new SessionCipher(aliceStore, BOB_RECIPIENT_ID, 1); aliceSessionCipher = new SessionCipher(aliceStore, BOB_ADDRESS);
bobPreKeyPair = Curve.generateKeyPair(); bobPreKeyPair = Curve.generateKeyPair();
bobPreKey = new PreKeyBundle(bobStore.getLocalRegistrationId(), bobPreKey = new PreKeyBundle(bobStore.getLocalRegistrationId(),
@ -82,7 +82,7 @@ public class SessionBuilderTest extends TestCase {
bobSessionCipher.decrypt(new PreKeyWhisperMessage(outgoingMessage.serialize())); bobSessionCipher.decrypt(new PreKeyWhisperMessage(outgoingMessage.serialize()));
throw new AssertionError("shouldn't be trusted!"); throw new AssertionError("shouldn't be trusted!");
} catch (UntrustedIdentityException uie) { } catch (UntrustedIdentityException uie) {
bobStore.saveIdentity(ALICE_RECIPIENT_ID, new PreKeyWhisperMessage(outgoingMessage.serialize()).getIdentityKey()); bobStore.saveIdentity(ALICE_ADDRESS.getName(), new PreKeyWhisperMessage(outgoingMessage.serialize()).getIdentityKey());
} }
plaintext = bobSessionCipher.decrypt(new PreKeyWhisperMessage(outgoingMessage.serialize())); plaintext = bobSessionCipher.decrypt(new PreKeyWhisperMessage(outgoingMessage.serialize()));
@ -105,7 +105,7 @@ public class SessionBuilderTest extends TestCase {
public void testBasicPreKeyV3() public void testBasicPreKeyV3()
throws InvalidKeyException, InvalidVersionException, InvalidMessageException, InvalidKeyIdException, DuplicateMessageException, LegacyMessageException, UntrustedIdentityException, NoSessionException { throws InvalidKeyException, InvalidVersionException, InvalidMessageException, InvalidKeyIdException, DuplicateMessageException, LegacyMessageException, UntrustedIdentityException, NoSessionException {
AxolotlStore aliceStore = new InMemoryAxolotlStore(); AxolotlStore aliceStore = new InMemoryAxolotlStore();
SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_RECIPIENT_ID, 1); SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);
final AxolotlStore bobStore = new InMemoryAxolotlStore(); final AxolotlStore bobStore = new InMemoryAxolotlStore();
ECKeyPair bobPreKeyPair = Curve.generateKeyPair(); ECKeyPair bobPreKeyPair = Curve.generateKeyPair();
@ -121,11 +121,11 @@ public class SessionBuilderTest extends TestCase {
aliceSessionBuilder.process(bobPreKey); aliceSessionBuilder.process(bobPreKey);
assertTrue(aliceStore.containsSession(BOB_RECIPIENT_ID, 1)); assertTrue(aliceStore.containsSession(BOB_ADDRESS));
assertTrue(aliceStore.loadSession(BOB_RECIPIENT_ID, 1).getSessionState().getSessionVersion() == 3); assertTrue(aliceStore.loadSession(BOB_ADDRESS).getSessionState().getSessionVersion() == 3);
final String originalMessage = "L'homme est condamné à être libre"; final String originalMessage = "L'homme est condamné à être libre";
SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_RECIPIENT_ID, 1); SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_ADDRESS);
CiphertextMessage outgoingMessage = aliceSessionCipher.encrypt(originalMessage.getBytes()); CiphertextMessage outgoingMessage = aliceSessionCipher.encrypt(originalMessage.getBytes());
assertTrue(outgoingMessage.getType() == CiphertextMessage.PREKEY_TYPE); assertTrue(outgoingMessage.getType() == CiphertextMessage.PREKEY_TYPE);
@ -134,18 +134,18 @@ public class SessionBuilderTest extends TestCase {
bobStore.storePreKey(31337, new PreKeyRecord(bobPreKey.getPreKeyId(), bobPreKeyPair)); bobStore.storePreKey(31337, new PreKeyRecord(bobPreKey.getPreKeyId(), bobPreKeyPair));
bobStore.storeSignedPreKey(22, new SignedPreKeyRecord(22, System.currentTimeMillis(), bobSignedPreKeyPair, bobSignedPreKeySignature)); bobStore.storeSignedPreKey(22, new SignedPreKeyRecord(22, System.currentTimeMillis(), bobSignedPreKeyPair, bobSignedPreKeySignature));
SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_RECIPIENT_ID, 1); SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_ADDRESS);
byte[] plaintext = bobSessionCipher.decrypt(incomingMessage, new SessionCipher.DecryptionCallback() { byte[] plaintext = bobSessionCipher.decrypt(incomingMessage, new SessionCipher.DecryptionCallback() {
@Override @Override
public void handlePlaintext(byte[] plaintext) { public void handlePlaintext(byte[] plaintext) {
assertTrue(originalMessage.equals(new String(plaintext))); assertTrue(originalMessage.equals(new String(plaintext)));
assertFalse(bobStore.containsSession(ALICE_RECIPIENT_ID, 1)); assertFalse(bobStore.containsSession(ALICE_ADDRESS));
} }
}); });
assertTrue(bobStore.containsSession(ALICE_RECIPIENT_ID, 1)); assertTrue(bobStore.containsSession(ALICE_ADDRESS));
assertTrue(bobStore.loadSession(ALICE_RECIPIENT_ID, 1).getSessionState().getSessionVersion() == 3); assertTrue(bobStore.loadSession(ALICE_ADDRESS).getSessionState().getSessionVersion() == 3);
assertTrue(bobStore.loadSession(ALICE_RECIPIENT_ID, 1).getSessionState().getAliceBaseKey() != null); assertTrue(bobStore.loadSession(ALICE_ADDRESS).getSessionState().getAliceBaseKey() != null);
assertTrue(originalMessage.equals(new String(plaintext))); assertTrue(originalMessage.equals(new String(plaintext)));
CiphertextMessage bobOutgoingMessage = bobSessionCipher.encrypt(originalMessage.getBytes()); CiphertextMessage bobOutgoingMessage = bobSessionCipher.encrypt(originalMessage.getBytes());
@ -157,8 +157,8 @@ public class SessionBuilderTest extends TestCase {
runInteraction(aliceStore, bobStore); runInteraction(aliceStore, bobStore);
aliceStore = new InMemoryAxolotlStore(); aliceStore = new InMemoryAxolotlStore();
aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_RECIPIENT_ID, 1); aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);
aliceSessionCipher = new SessionCipher(aliceStore, BOB_RECIPIENT_ID, 1); aliceSessionCipher = new SessionCipher(aliceStore, BOB_ADDRESS);
bobPreKeyPair = Curve.generateKeyPair(); bobPreKeyPair = Curve.generateKeyPair();
bobSignedPreKeyPair = Curve.generateKeyPair(); bobSignedPreKeyPair = Curve.generateKeyPair();
@ -178,7 +178,7 @@ public class SessionBuilderTest extends TestCase {
plaintext = bobSessionCipher.decrypt(new PreKeyWhisperMessage(outgoingMessage.serialize())); plaintext = bobSessionCipher.decrypt(new PreKeyWhisperMessage(outgoingMessage.serialize()));
throw new AssertionError("shouldn't be trusted!"); throw new AssertionError("shouldn't be trusted!");
} catch (UntrustedIdentityException uie) { } catch (UntrustedIdentityException uie) {
bobStore.saveIdentity(ALICE_RECIPIENT_ID, new PreKeyWhisperMessage(outgoingMessage.serialize()).getIdentityKey()); bobStore.saveIdentity(ALICE_ADDRESS.getName(), new PreKeyWhisperMessage(outgoingMessage.serialize()).getIdentityKey());
} }
plaintext = bobSessionCipher.decrypt(new PreKeyWhisperMessage(outgoingMessage.serialize())); plaintext = bobSessionCipher.decrypt(new PreKeyWhisperMessage(outgoingMessage.serialize()));
@ -199,7 +199,7 @@ public class SessionBuilderTest extends TestCase {
public void testBadSignedPreKeySignature() throws InvalidKeyException, UntrustedIdentityException { public void testBadSignedPreKeySignature() throws InvalidKeyException, UntrustedIdentityException {
AxolotlStore aliceStore = new InMemoryAxolotlStore(); AxolotlStore aliceStore = new InMemoryAxolotlStore();
SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_RECIPIENT_ID, 1); SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);
IdentityKeyStore bobIdentityKeyStore = new InMemoryIdentityKeyStore(); IdentityKeyStore bobIdentityKeyStore = new InMemoryIdentityKeyStore();
@ -238,7 +238,7 @@ public class SessionBuilderTest extends TestCase {
public void testRepeatBundleMessageV2() throws InvalidKeyException, UntrustedIdentityException, InvalidVersionException, InvalidMessageException, InvalidKeyIdException, DuplicateMessageException, LegacyMessageException, NoSessionException { public void testRepeatBundleMessageV2() throws InvalidKeyException, UntrustedIdentityException, InvalidVersionException, InvalidMessageException, InvalidKeyIdException, DuplicateMessageException, LegacyMessageException, NoSessionException {
AxolotlStore aliceStore = new InMemoryAxolotlStore(); AxolotlStore aliceStore = new InMemoryAxolotlStore();
SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_RECIPIENT_ID, 1); SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);
AxolotlStore bobStore = new InMemoryAxolotlStore(); AxolotlStore bobStore = new InMemoryAxolotlStore();
@ -258,7 +258,7 @@ public class SessionBuilderTest extends TestCase {
aliceSessionBuilder.process(bobPreKey); aliceSessionBuilder.process(bobPreKey);
String originalMessage = "L'homme est condamné à être libre"; String originalMessage = "L'homme est condamné à être libre";
SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_RECIPIENT_ID, 1); SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_ADDRESS);
CiphertextMessage outgoingMessageOne = aliceSessionCipher.encrypt(originalMessage.getBytes()); CiphertextMessage outgoingMessageOne = aliceSessionCipher.encrypt(originalMessage.getBytes());
CiphertextMessage outgoingMessageTwo = aliceSessionCipher.encrypt(originalMessage.getBytes()); CiphertextMessage outgoingMessageTwo = aliceSessionCipher.encrypt(originalMessage.getBytes());
@ -266,7 +266,7 @@ public class SessionBuilderTest extends TestCase {
PreKeyWhisperMessage incomingMessage = new PreKeyWhisperMessage(outgoingMessageOne.serialize()); PreKeyWhisperMessage incomingMessage = new PreKeyWhisperMessage(outgoingMessageOne.serialize());
SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_RECIPIENT_ID, 1); SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_ADDRESS);
byte[] plaintext = bobSessionCipher.decrypt(incomingMessage); byte[] plaintext = bobSessionCipher.decrypt(incomingMessage);
assertTrue(originalMessage.equals(new String(plaintext))); assertTrue(originalMessage.equals(new String(plaintext)));
@ -291,7 +291,7 @@ public class SessionBuilderTest extends TestCase {
public void testRepeatBundleMessageV3() throws InvalidKeyException, UntrustedIdentityException, InvalidVersionException, InvalidMessageException, InvalidKeyIdException, DuplicateMessageException, LegacyMessageException, NoSessionException { public void testRepeatBundleMessageV3() throws InvalidKeyException, UntrustedIdentityException, InvalidVersionException, InvalidMessageException, InvalidKeyIdException, DuplicateMessageException, LegacyMessageException, NoSessionException {
AxolotlStore aliceStore = new InMemoryAxolotlStore(); AxolotlStore aliceStore = new InMemoryAxolotlStore();
SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_RECIPIENT_ID, 1); SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);
AxolotlStore bobStore = new InMemoryAxolotlStore(); AxolotlStore bobStore = new InMemoryAxolotlStore();
@ -311,7 +311,7 @@ public class SessionBuilderTest extends TestCase {
aliceSessionBuilder.process(bobPreKey); aliceSessionBuilder.process(bobPreKey);
String originalMessage = "L'homme est condamné à être libre"; String originalMessage = "L'homme est condamné à être libre";
SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_RECIPIENT_ID, 1); SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_ADDRESS);
CiphertextMessage outgoingMessageOne = aliceSessionCipher.encrypt(originalMessage.getBytes()); CiphertextMessage outgoingMessageOne = aliceSessionCipher.encrypt(originalMessage.getBytes());
CiphertextMessage outgoingMessageTwo = aliceSessionCipher.encrypt(originalMessage.getBytes()); CiphertextMessage outgoingMessageTwo = aliceSessionCipher.encrypt(originalMessage.getBytes());
@ -320,7 +320,7 @@ public class SessionBuilderTest extends TestCase {
PreKeyWhisperMessage incomingMessage = new PreKeyWhisperMessage(outgoingMessageOne.serialize()); PreKeyWhisperMessage incomingMessage = new PreKeyWhisperMessage(outgoingMessageOne.serialize());
SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_RECIPIENT_ID, 1); SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_ADDRESS);
byte[] plaintext = bobSessionCipher.decrypt(incomingMessage); byte[] plaintext = bobSessionCipher.decrypt(incomingMessage);
assertTrue(originalMessage.equals(new String(plaintext))); assertTrue(originalMessage.equals(new String(plaintext)));
@ -345,7 +345,7 @@ public class SessionBuilderTest extends TestCase {
public void testBadMessageBundle() throws InvalidKeyException, UntrustedIdentityException, InvalidVersionException, InvalidMessageException, DuplicateMessageException, LegacyMessageException, InvalidKeyIdException { public void testBadMessageBundle() throws InvalidKeyException, UntrustedIdentityException, InvalidVersionException, InvalidMessageException, DuplicateMessageException, LegacyMessageException, InvalidKeyIdException {
AxolotlStore aliceStore = new InMemoryAxolotlStore(); AxolotlStore aliceStore = new InMemoryAxolotlStore();
SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_RECIPIENT_ID, 1); SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);
AxolotlStore bobStore = new InMemoryAxolotlStore(); AxolotlStore bobStore = new InMemoryAxolotlStore();
@ -365,7 +365,7 @@ public class SessionBuilderTest extends TestCase {
aliceSessionBuilder.process(bobPreKey); aliceSessionBuilder.process(bobPreKey);
String originalMessage = "L'homme est condamné à être libre"; String originalMessage = "L'homme est condamné à être libre";
SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_RECIPIENT_ID, 1); SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_ADDRESS);
CiphertextMessage outgoingMessageOne = aliceSessionCipher.encrypt(originalMessage.getBytes()); CiphertextMessage outgoingMessageOne = aliceSessionCipher.encrypt(originalMessage.getBytes());
assertTrue(outgoingMessageOne.getType() == CiphertextMessage.PREKEY_TYPE); assertTrue(outgoingMessageOne.getType() == CiphertextMessage.PREKEY_TYPE);
@ -377,7 +377,7 @@ public class SessionBuilderTest extends TestCase {
badMessage[badMessage.length-10] ^= 0x01; badMessage[badMessage.length-10] ^= 0x01;
PreKeyWhisperMessage incomingMessage = new PreKeyWhisperMessage(badMessage); PreKeyWhisperMessage incomingMessage = new PreKeyWhisperMessage(badMessage);
SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_RECIPIENT_ID, 1); SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_ADDRESS);
byte[] plaintext = new byte[0]; byte[] plaintext = new byte[0];
@ -398,10 +398,10 @@ public class SessionBuilderTest extends TestCase {
public void testBasicKeyExchange() throws InvalidKeyException, LegacyMessageException, InvalidMessageException, DuplicateMessageException, UntrustedIdentityException, StaleKeyExchangeException, InvalidVersionException, NoSessionException { public void testBasicKeyExchange() throws InvalidKeyException, LegacyMessageException, InvalidMessageException, DuplicateMessageException, UntrustedIdentityException, StaleKeyExchangeException, InvalidVersionException, NoSessionException {
AxolotlStore aliceStore = new InMemoryAxolotlStore(); AxolotlStore aliceStore = new InMemoryAxolotlStore();
SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_RECIPIENT_ID, 1); SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);
AxolotlStore bobStore = new InMemoryAxolotlStore(); AxolotlStore bobStore = new InMemoryAxolotlStore();
SessionBuilder bobSessionBuilder = new SessionBuilder(bobStore, ALICE_RECIPIENT_ID, 1); SessionBuilder bobSessionBuilder = new SessionBuilder(bobStore, ALICE_ADDRESS);
KeyExchangeMessage aliceKeyExchangeMessage = aliceSessionBuilder.process(); KeyExchangeMessage aliceKeyExchangeMessage = aliceSessionBuilder.process();
assertTrue(aliceKeyExchangeMessage != null); assertTrue(aliceKeyExchangeMessage != null);
@ -415,20 +415,20 @@ public class SessionBuilderTest extends TestCase {
KeyExchangeMessage response = aliceSessionBuilder.process(new KeyExchangeMessage(bobKeyExchangeMessageBytes)); KeyExchangeMessage response = aliceSessionBuilder.process(new KeyExchangeMessage(bobKeyExchangeMessageBytes));
assertTrue(response == null); assertTrue(response == null);
assertTrue(aliceStore.containsSession(BOB_RECIPIENT_ID, 1)); assertTrue(aliceStore.containsSession(BOB_ADDRESS));
assertTrue(bobStore.containsSession(ALICE_RECIPIENT_ID, 1)); assertTrue(bobStore.containsSession(ALICE_ADDRESS));
runInteraction(aliceStore, bobStore); runInteraction(aliceStore, bobStore);
aliceStore = new InMemoryAxolotlStore(); aliceStore = new InMemoryAxolotlStore();
aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_RECIPIENT_ID, 1); aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);
aliceKeyExchangeMessage = aliceSessionBuilder.process(); aliceKeyExchangeMessage = aliceSessionBuilder.process();
try { try {
bobKeyExchangeMessage = bobSessionBuilder.process(aliceKeyExchangeMessage); bobKeyExchangeMessage = bobSessionBuilder.process(aliceKeyExchangeMessage);
throw new AssertionError("This identity shouldn't be trusted!"); throw new AssertionError("This identity shouldn't be trusted!");
} catch (UntrustedIdentityException uie) { } catch (UntrustedIdentityException uie) {
bobStore.saveIdentity(ALICE_RECIPIENT_ID, aliceKeyExchangeMessage.getIdentityKey()); bobStore.saveIdentity(ALICE_ADDRESS.getName(), aliceKeyExchangeMessage.getIdentityKey());
bobKeyExchangeMessage = bobSessionBuilder.process(aliceKeyExchangeMessage); bobKeyExchangeMessage = bobSessionBuilder.process(aliceKeyExchangeMessage);
} }
@ -440,10 +440,10 @@ public class SessionBuilderTest extends TestCase {
public void testSimultaneousKeyExchange() public void testSimultaneousKeyExchange()
throws InvalidKeyException, DuplicateMessageException, LegacyMessageException, InvalidMessageException, UntrustedIdentityException, StaleKeyExchangeException, NoSessionException { throws InvalidKeyException, DuplicateMessageException, LegacyMessageException, InvalidMessageException, UntrustedIdentityException, StaleKeyExchangeException, NoSessionException {
AxolotlStore aliceStore = new InMemoryAxolotlStore(); AxolotlStore aliceStore = new InMemoryAxolotlStore();
SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_RECIPIENT_ID, 1); SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);
AxolotlStore bobStore = new InMemoryAxolotlStore(); AxolotlStore bobStore = new InMemoryAxolotlStore();
SessionBuilder bobSessionBuilder = new SessionBuilder(bobStore, ALICE_RECIPIENT_ID, 1); SessionBuilder bobSessionBuilder = new SessionBuilder(bobStore, ALICE_ADDRESS);
KeyExchangeMessage aliceKeyExchange = aliceSessionBuilder.process(); KeyExchangeMessage aliceKeyExchange = aliceSessionBuilder.process();
KeyExchangeMessage bobKeyExchange = bobSessionBuilder.process(); KeyExchangeMessage bobKeyExchange = bobSessionBuilder.process();
@ -468,7 +468,7 @@ public class SessionBuilderTest extends TestCase {
public void testOptionalOneTimePreKey() throws Exception { public void testOptionalOneTimePreKey() throws Exception {
AxolotlStore aliceStore = new InMemoryAxolotlStore(); AxolotlStore aliceStore = new InMemoryAxolotlStore();
SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_RECIPIENT_ID, 1); SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);
AxolotlStore bobStore = new InMemoryAxolotlStore(); AxolotlStore bobStore = new InMemoryAxolotlStore();
@ -485,11 +485,11 @@ public class SessionBuilderTest extends TestCase {
aliceSessionBuilder.process(bobPreKey); aliceSessionBuilder.process(bobPreKey);
assertTrue(aliceStore.containsSession(BOB_RECIPIENT_ID, 1)); assertTrue(aliceStore.containsSession(BOB_ADDRESS));
assertTrue(aliceStore.loadSession(BOB_RECIPIENT_ID, 1).getSessionState().getSessionVersion() == 3); assertTrue(aliceStore.loadSession(BOB_ADDRESS).getSessionState().getSessionVersion() == 3);
String originalMessage = "L'homme est condamné à être libre"; String originalMessage = "L'homme est condamné à être libre";
SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_RECIPIENT_ID, 1); SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_ADDRESS);
CiphertextMessage outgoingMessage = aliceSessionCipher.encrypt(originalMessage.getBytes()); CiphertextMessage outgoingMessage = aliceSessionCipher.encrypt(originalMessage.getBytes());
assertTrue(outgoingMessage.getType() == CiphertextMessage.PREKEY_TYPE); assertTrue(outgoingMessage.getType() == CiphertextMessage.PREKEY_TYPE);
@ -500,12 +500,12 @@ public class SessionBuilderTest extends TestCase {
bobStore.storePreKey(31337, new PreKeyRecord(bobPreKey.getPreKeyId(), bobPreKeyPair)); bobStore.storePreKey(31337, new PreKeyRecord(bobPreKey.getPreKeyId(), bobPreKeyPair));
bobStore.storeSignedPreKey(22, new SignedPreKeyRecord(22, System.currentTimeMillis(), bobSignedPreKeyPair, bobSignedPreKeySignature)); bobStore.storeSignedPreKey(22, new SignedPreKeyRecord(22, System.currentTimeMillis(), bobSignedPreKeyPair, bobSignedPreKeySignature));
SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_RECIPIENT_ID, 1); SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_ADDRESS);
byte[] plaintext = bobSessionCipher.decrypt(incomingMessage); byte[] plaintext = bobSessionCipher.decrypt(incomingMessage);
assertTrue(bobStore.containsSession(ALICE_RECIPIENT_ID, 1)); assertTrue(bobStore.containsSession(ALICE_ADDRESS));
assertTrue(bobStore.loadSession(ALICE_RECIPIENT_ID, 1).getSessionState().getSessionVersion() == 3); assertTrue(bobStore.loadSession(ALICE_ADDRESS).getSessionState().getSessionVersion() == 3);
assertTrue(bobStore.loadSession(ALICE_RECIPIENT_ID, 1).getSessionState().getAliceBaseKey() != null); assertTrue(bobStore.loadSession(ALICE_ADDRESS).getSessionState().getAliceBaseKey() != null);
assertTrue(originalMessage.equals(new String(plaintext))); assertTrue(originalMessage.equals(new String(plaintext)));
} }
@ -513,8 +513,8 @@ public class SessionBuilderTest extends TestCase {
private void runInteraction(AxolotlStore aliceStore, AxolotlStore bobStore) private void runInteraction(AxolotlStore aliceStore, AxolotlStore bobStore)
throws DuplicateMessageException, LegacyMessageException, InvalidMessageException, NoSessionException throws DuplicateMessageException, LegacyMessageException, InvalidMessageException, NoSessionException
{ {
SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_RECIPIENT_ID, 1); SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_ADDRESS);
SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_RECIPIENT_ID, 1); SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_ADDRESS);
String originalMessage = "smert ze smert"; String originalMessage = "smert ze smert";
CiphertextMessage aliceMessage = aliceSessionCipher.encrypt(originalMessage.getBytes()); CiphertextMessage aliceMessage = aliceSessionCipher.encrypt(originalMessage.getBytes());

View File

@ -52,11 +52,11 @@ public class SessionCipherTest extends TestCase {
AxolotlStore aliceStore = new InMemoryAxolotlStore(); AxolotlStore aliceStore = new InMemoryAxolotlStore();
AxolotlStore bobStore = new InMemoryAxolotlStore(); AxolotlStore bobStore = new InMemoryAxolotlStore();
aliceStore.storeSession(2L, 1, aliceSessionRecord); aliceStore.storeSession(new AxolotlAddress("+14159999999", 1), aliceSessionRecord);
bobStore.storeSession(3L, 1, bobSessionRecord); bobStore.storeSession(new AxolotlAddress("+14158888888", 1), bobSessionRecord);
SessionCipher aliceCipher = new SessionCipher(aliceStore, 2L, 1); SessionCipher aliceCipher = new SessionCipher(aliceStore, new AxolotlAddress("+14159999999", 1));
SessionCipher bobCipher = new SessionCipher(bobStore, 3L, 1); SessionCipher bobCipher = new SessionCipher(bobStore, new AxolotlAddress("+14158888888", 1));
byte[] alicePlaintext = "This is a plaintext message.".getBytes(); byte[] alicePlaintext = "This is a plaintext message.".getBytes();
CiphertextMessage message = aliceCipher.encrypt(alicePlaintext); CiphertextMessage message = aliceCipher.encrypt(alicePlaintext);

View File

@ -18,8 +18,8 @@ import java.util.Random;
public class SimultaneousInitiateTests extends TestCase { public class SimultaneousInitiateTests extends TestCase {
private static final long BOB_RECIPENT_ID = 12345; private static final AxolotlAddress BOB_ADDRESS = new AxolotlAddress("+14151231234", 1);
private static final long ALICE_RECIPIENT_ID = 6789; private static final AxolotlAddress ALICE_ADDRESS = new AxolotlAddress("+14159998888", 1);
private static final ECKeyPair aliceSignedPreKey = Curve.generateKeyPair(); private static final ECKeyPair aliceSignedPreKey = Curve.generateKeyPair();
private static final ECKeyPair bobSignedPreKey = Curve.generateKeyPair(); private static final ECKeyPair bobSignedPreKey = Curve.generateKeyPair();
@ -38,11 +38,11 @@ public class SimultaneousInitiateTests extends TestCase {
PreKeyBundle alicePreKeyBundle = createAlicePreKeyBundle(aliceStore); PreKeyBundle alicePreKeyBundle = createAlicePreKeyBundle(aliceStore);
PreKeyBundle bobPreKeyBundle = createBobPreKeyBundle(bobStore); PreKeyBundle bobPreKeyBundle = createBobPreKeyBundle(bobStore);
SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_RECIPENT_ID, 1); SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);
SessionBuilder bobSessionBuilder = new SessionBuilder(bobStore, ALICE_RECIPIENT_ID, 1); SessionBuilder bobSessionBuilder = new SessionBuilder(bobStore, ALICE_ADDRESS);
SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_RECIPENT_ID, 1); SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_ADDRESS);
SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_RECIPIENT_ID, 1); SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_ADDRESS);
aliceSessionBuilder.process(bobPreKeyBundle); aliceSessionBuilder.process(bobPreKeyBundle);
bobSessionBuilder.process(alicePreKeyBundle); bobSessionBuilder.process(alicePreKeyBundle);
@ -61,8 +61,8 @@ public class SimultaneousInitiateTests extends TestCase {
assertTrue(new String(alicePlaintext).equals("sample message")); assertTrue(new String(alicePlaintext).equals("sample message"));
assertTrue(new String(bobPlaintext).equals("hey there")); assertTrue(new String(bobPlaintext).equals("hey there"));
assertTrue(aliceStore.loadSession(BOB_RECIPENT_ID, 1).getSessionState().getSessionVersion() == 3); assertTrue(aliceStore.loadSession(BOB_ADDRESS).getSessionState().getSessionVersion() == 3);
assertTrue(bobStore.loadSession(ALICE_RECIPIENT_ID, 1).getSessionState().getSessionVersion() == 3); assertTrue(bobStore.loadSession(ALICE_ADDRESS).getSessionState().getSessionVersion() == 3);
assertFalse(isSessionIdEqual(aliceStore, bobStore)); assertFalse(isSessionIdEqual(aliceStore, bobStore));
@ -92,11 +92,11 @@ public class SimultaneousInitiateTests extends TestCase {
PreKeyBundle alicePreKeyBundle = createAlicePreKeyBundle(aliceStore); PreKeyBundle alicePreKeyBundle = createAlicePreKeyBundle(aliceStore);
PreKeyBundle bobPreKeyBundle = createBobPreKeyBundle(bobStore); PreKeyBundle bobPreKeyBundle = createBobPreKeyBundle(bobStore);
SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_RECIPENT_ID, 1); SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);
SessionBuilder bobSessionBuilder = new SessionBuilder(bobStore, ALICE_RECIPIENT_ID, 1); SessionBuilder bobSessionBuilder = new SessionBuilder(bobStore, ALICE_ADDRESS);
SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_RECIPENT_ID, 1); SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_ADDRESS);
SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_RECIPIENT_ID, 1); SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_ADDRESS);
aliceSessionBuilder.process(bobPreKeyBundle); aliceSessionBuilder.process(bobPreKeyBundle);
bobSessionBuilder.process(alicePreKeyBundle); bobSessionBuilder.process(alicePreKeyBundle);
@ -112,7 +112,7 @@ public class SimultaneousInitiateTests extends TestCase {
byte[] bobPlaintext = bobSessionCipher.decrypt(new PreKeyWhisperMessage(messageForBob.serialize())); byte[] bobPlaintext = bobSessionCipher.decrypt(new PreKeyWhisperMessage(messageForBob.serialize()));
assertTrue(new String(bobPlaintext).equals("hey there")); assertTrue(new String(bobPlaintext).equals("hey there"));
assertTrue(bobStore.loadSession(ALICE_RECIPIENT_ID, 1).getSessionState().getSessionVersion() == 3); assertTrue(bobStore.loadSession(ALICE_ADDRESS).getSessionState().getSessionVersion() == 3);
CiphertextMessage aliceResponse = aliceSessionCipher.encrypt("second message".getBytes()); CiphertextMessage aliceResponse = aliceSessionCipher.encrypt("second message".getBytes());
@ -144,11 +144,11 @@ public class SimultaneousInitiateTests extends TestCase {
PreKeyBundle alicePreKeyBundle = createAlicePreKeyBundle(aliceStore); PreKeyBundle alicePreKeyBundle = createAlicePreKeyBundle(aliceStore);
PreKeyBundle bobPreKeyBundle = createBobPreKeyBundle(bobStore); PreKeyBundle bobPreKeyBundle = createBobPreKeyBundle(bobStore);
SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_RECIPENT_ID, 1); SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);
SessionBuilder bobSessionBuilder = new SessionBuilder(bobStore, ALICE_RECIPIENT_ID, 1); SessionBuilder bobSessionBuilder = new SessionBuilder(bobStore, ALICE_ADDRESS);
SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_RECIPENT_ID, 1); SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_ADDRESS);
SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_RECIPIENT_ID, 1); SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_ADDRESS);
aliceSessionBuilder.process(bobPreKeyBundle); aliceSessionBuilder.process(bobPreKeyBundle);
bobSessionBuilder.process(alicePreKeyBundle); bobSessionBuilder.process(alicePreKeyBundle);
@ -167,8 +167,8 @@ public class SimultaneousInitiateTests extends TestCase {
assertTrue(new String(alicePlaintext).equals("sample message")); assertTrue(new String(alicePlaintext).equals("sample message"));
assertTrue(new String(bobPlaintext).equals("hey there")); assertTrue(new String(bobPlaintext).equals("hey there"));
assertTrue(aliceStore.loadSession(BOB_RECIPENT_ID, 1).getSessionState().getSessionVersion() == 3); assertTrue(aliceStore.loadSession(BOB_ADDRESS).getSessionState().getSessionVersion() == 3);
assertTrue(bobStore.loadSession(ALICE_RECIPIENT_ID, 1).getSessionState().getSessionVersion() == 3); assertTrue(bobStore.loadSession(ALICE_ADDRESS).getSessionState().getSessionVersion() == 3);
assertFalse(isSessionIdEqual(aliceStore, bobStore)); assertFalse(isSessionIdEqual(aliceStore, bobStore));
@ -203,11 +203,11 @@ public class SimultaneousInitiateTests extends TestCase {
PreKeyBundle alicePreKeyBundle = createAlicePreKeyBundle(aliceStore); PreKeyBundle alicePreKeyBundle = createAlicePreKeyBundle(aliceStore);
PreKeyBundle bobPreKeyBundle = createBobPreKeyBundle(bobStore); PreKeyBundle bobPreKeyBundle = createBobPreKeyBundle(bobStore);
SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_RECIPENT_ID, 1); SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);
SessionBuilder bobSessionBuilder = new SessionBuilder(bobStore, ALICE_RECIPIENT_ID, 1); SessionBuilder bobSessionBuilder = new SessionBuilder(bobStore, ALICE_ADDRESS);
SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_RECIPENT_ID, 1); SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_ADDRESS);
SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_RECIPIENT_ID, 1); SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_ADDRESS);
aliceSessionBuilder.process(bobPreKeyBundle); aliceSessionBuilder.process(bobPreKeyBundle);
bobSessionBuilder.process(alicePreKeyBundle); bobSessionBuilder.process(alicePreKeyBundle);
@ -226,8 +226,8 @@ public class SimultaneousInitiateTests extends TestCase {
assertTrue(new String(alicePlaintext).equals("sample message")); assertTrue(new String(alicePlaintext).equals("sample message"));
assertTrue(new String(bobPlaintext).equals("hey there")); assertTrue(new String(bobPlaintext).equals("hey there"));
assertTrue(aliceStore.loadSession(BOB_RECIPENT_ID, 1).getSessionState().getSessionVersion() == 3); assertTrue(aliceStore.loadSession(BOB_ADDRESS).getSessionState().getSessionVersion() == 3);
assertTrue(bobStore.loadSession(ALICE_RECIPIENT_ID, 1).getSessionState().getSessionVersion() == 3); assertTrue(bobStore.loadSession(ALICE_ADDRESS).getSessionState().getSessionVersion() == 3);
assertFalse(isSessionIdEqual(aliceStore, bobStore)); assertFalse(isSessionIdEqual(aliceStore, bobStore));
@ -277,11 +277,11 @@ public class SimultaneousInitiateTests extends TestCase {
AxolotlStore bobStore = new InMemoryAxolotlStore(); AxolotlStore bobStore = new InMemoryAxolotlStore();
SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_RECIPENT_ID, 1); SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);
SessionBuilder bobSessionBuilder = new SessionBuilder(bobStore, ALICE_RECIPIENT_ID, 1); SessionBuilder bobSessionBuilder = new SessionBuilder(bobStore, ALICE_ADDRESS);
SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_RECIPENT_ID, 1); SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_ADDRESS);
SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_RECIPIENT_ID, 1); SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_ADDRESS);
for (int i=0;i<15;i++) { for (int i=0;i<15;i++) {
PreKeyBundle alicePreKeyBundle = createAlicePreKeyBundle(aliceStore); PreKeyBundle alicePreKeyBundle = createAlicePreKeyBundle(aliceStore);
@ -304,8 +304,8 @@ public class SimultaneousInitiateTests extends TestCase {
assertTrue(new String(alicePlaintext).equals("sample message")); assertTrue(new String(alicePlaintext).equals("sample message"));
assertTrue(new String(bobPlaintext).equals("hey there")); assertTrue(new String(bobPlaintext).equals("hey there"));
assertTrue(aliceStore.loadSession(BOB_RECIPENT_ID, 1).getSessionState().getSessionVersion() == 3); assertTrue(aliceStore.loadSession(BOB_ADDRESS).getSessionState().getSessionVersion() == 3);
assertTrue(bobStore.loadSession(ALICE_RECIPIENT_ID, 1).getSessionState().getSessionVersion() == 3); assertTrue(bobStore.loadSession(ALICE_ADDRESS).getSessionState().getSessionVersion() == 3);
assertFalse(isSessionIdEqual(aliceStore, bobStore)); assertFalse(isSessionIdEqual(aliceStore, bobStore));
} }
@ -356,11 +356,11 @@ public class SimultaneousInitiateTests extends TestCase {
AxolotlStore bobStore = new InMemoryAxolotlStore(); AxolotlStore bobStore = new InMemoryAxolotlStore();
SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_RECIPENT_ID, 1); SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);
SessionBuilder bobSessionBuilder = new SessionBuilder(bobStore, ALICE_RECIPIENT_ID, 1); SessionBuilder bobSessionBuilder = new SessionBuilder(bobStore, ALICE_ADDRESS);
SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_RECIPENT_ID, 1); SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_ADDRESS);
SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_RECIPIENT_ID, 1); SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_ADDRESS);
// PreKeyBundle aliceLostPreKeyBundle = createAlicePreKeyBundle(aliceStore); // PreKeyBundle aliceLostPreKeyBundle = createAlicePreKeyBundle(aliceStore);
PreKeyBundle bobLostPreKeyBundle = createBobPreKeyBundle(bobStore); PreKeyBundle bobLostPreKeyBundle = createBobPreKeyBundle(bobStore);
@ -392,8 +392,8 @@ public class SimultaneousInitiateTests extends TestCase {
assertTrue(new String(alicePlaintext).equals("sample message")); assertTrue(new String(alicePlaintext).equals("sample message"));
assertTrue(new String(bobPlaintext).equals("hey there")); assertTrue(new String(bobPlaintext).equals("hey there"));
assertTrue(aliceStore.loadSession(BOB_RECIPENT_ID, 1).getSessionState().getSessionVersion() == 3); assertTrue(aliceStore.loadSession(BOB_ADDRESS).getSessionState().getSessionVersion() == 3);
assertTrue(bobStore.loadSession(ALICE_RECIPIENT_ID, 1).getSessionState().getSessionVersion() == 3); assertTrue(bobStore.loadSession(ALICE_ADDRESS).getSessionState().getSessionVersion() == 3);
assertFalse(isSessionIdEqual(aliceStore, bobStore)); assertFalse(isSessionIdEqual(aliceStore, bobStore));
} }
@ -447,8 +447,8 @@ public class SimultaneousInitiateTests extends TestCase {
} }
private boolean isSessionIdEqual(AxolotlStore aliceStore, AxolotlStore bobStore) { private boolean isSessionIdEqual(AxolotlStore aliceStore, AxolotlStore bobStore) {
return Arrays.equals(aliceStore.loadSession(BOB_RECIPENT_ID, 1).getSessionState().getAliceBaseKey(), return Arrays.equals(aliceStore.loadSession(BOB_ADDRESS).getSessionState().getAliceBaseKey(),
bobStore.loadSession(ALICE_RECIPIENT_ID, 1).getSessionState().getAliceBaseKey()); bobStore.loadSession(ALICE_ADDRESS).getSessionState().getAliceBaseKey());
} }
private PreKeyBundle createAlicePreKeyBundle(AxolotlStore aliceStore) throws InvalidKeyException { private PreKeyBundle createAlicePreKeyBundle(AxolotlStore aliceStore) throws InvalidKeyException {

View File

@ -2,6 +2,7 @@ package org.whispersystems.libaxolotl.groups;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.whispersystems.libaxolotl.AxolotlAddress;
import org.whispersystems.libaxolotl.DuplicateMessageException; import org.whispersystems.libaxolotl.DuplicateMessageException;
import org.whispersystems.libaxolotl.InvalidMessageException; import org.whispersystems.libaxolotl.InvalidMessageException;
import org.whispersystems.libaxolotl.LegacyMessageException; import org.whispersystems.libaxolotl.LegacyMessageException;
@ -14,6 +15,9 @@ import java.util.ArrayList;
public class GroupCipherTest extends TestCase { public class GroupCipherTest extends TestCase {
private static final AxolotlAddress SENDER_ADDRESS = new AxolotlAddress("+14150001111", 1);
private static final SenderKeyName GROUP_SENDER = new SenderKeyName("nihilist history reading group", SENDER_ADDRESS);
public void testBasicEncryptDecrypt() public void testBasicEncryptDecrypt()
throws LegacyMessageException, DuplicateMessageException, InvalidMessageException, NoSessionException throws LegacyMessageException, DuplicateMessageException, InvalidMessageException, NoSessionException
{ {
@ -23,13 +27,12 @@ public class GroupCipherTest extends TestCase {
GroupSessionBuilder aliceSessionBuilder = new GroupSessionBuilder(aliceStore); GroupSessionBuilder aliceSessionBuilder = new GroupSessionBuilder(aliceStore);
GroupSessionBuilder bobSessionBuilder = new GroupSessionBuilder(bobStore); GroupSessionBuilder bobSessionBuilder = new GroupSessionBuilder(bobStore);
GroupCipher aliceGroupCipher = new GroupCipher(aliceStore, new SenderKeyName("cool group", 1111, 0)); GroupCipher aliceGroupCipher = new GroupCipher(aliceStore, GROUP_SENDER);
GroupCipher bobGroupCipher = new GroupCipher(bobStore, new SenderKeyName("cool group", 1111, 0)); GroupCipher bobGroupCipher = new GroupCipher(bobStore, GROUP_SENDER);
SenderKeyDistributionMessage aliceDistributionMessage = SenderKeyDistributionMessage aliceDistributionMessage = aliceSessionBuilder.create(GROUP_SENDER);
aliceSessionBuilder.create(new SenderKeyName("cool group", 1111, 0));
bobSessionBuilder.process(new SenderKeyName("cool group", 1111, 0), aliceDistributionMessage); bobSessionBuilder.process(GROUP_SENDER, aliceDistributionMessage);
byte[] ciphertextFromAlice = aliceGroupCipher.encrypt("smert ze smert".getBytes()); byte[] ciphertextFromAlice = aliceGroupCipher.encrypt("smert ze smert".getBytes());
byte[] plaintextFromAlice = bobGroupCipher.decrypt(ciphertextFromAlice); byte[] plaintextFromAlice = bobGroupCipher.decrypt(ciphertextFromAlice);
@ -46,7 +49,7 @@ public class GroupCipherTest extends TestCase {
GroupSessionBuilder aliceSessionBuilder = new GroupSessionBuilder(aliceStore); GroupSessionBuilder aliceSessionBuilder = new GroupSessionBuilder(aliceStore);
GroupSessionBuilder bobSessionBuilder = new GroupSessionBuilder(bobStore); GroupSessionBuilder bobSessionBuilder = new GroupSessionBuilder(bobStore);
SenderKeyName aliceName = new SenderKeyName("cool group", 1111, 0); SenderKeyName aliceName = GROUP_SENDER;
GroupCipher aliceGroupCipher = new GroupCipher(aliceStore, aliceName); GroupCipher aliceGroupCipher = new GroupCipher(aliceStore, aliceName);
GroupCipher bobGroupCipher = new GroupCipher(bobStore, aliceName); GroupCipher bobGroupCipher = new GroupCipher(bobStore, aliceName);
@ -86,7 +89,7 @@ public class GroupCipherTest extends TestCase {
GroupSessionBuilder aliceSessionBuilder = new GroupSessionBuilder(aliceStore); GroupSessionBuilder aliceSessionBuilder = new GroupSessionBuilder(aliceStore);
GroupSessionBuilder bobSessionBuilder = new GroupSessionBuilder(bobStore); GroupSessionBuilder bobSessionBuilder = new GroupSessionBuilder(bobStore);
SenderKeyName aliceName = new SenderKeyName("cool group", 1111, 0); SenderKeyName aliceName = GROUP_SENDER;
GroupCipher aliceGroupCipher = new GroupCipher(aliceStore, aliceName); GroupCipher aliceGroupCipher = new GroupCipher(aliceStore, aliceName);
GroupCipher bobGroupCipher = new GroupCipher(bobStore, aliceName); GroupCipher bobGroupCipher = new GroupCipher(bobStore, aliceName);
@ -113,7 +116,7 @@ public class GroupCipherTest extends TestCase {
public void testEncryptNoSession() { public void testEncryptNoSession() {
InMemorySenderKeyStore aliceStore = new InMemorySenderKeyStore(); InMemorySenderKeyStore aliceStore = new InMemorySenderKeyStore();
GroupCipher aliceGroupCipher = new GroupCipher(aliceStore, new SenderKeyName("coolio groupio", 1111, 0)); GroupCipher aliceGroupCipher = new GroupCipher(aliceStore, new SenderKeyName("coolio groupio", new AxolotlAddress("+10002223333", 1)));
try { try {
aliceGroupCipher.encrypt("up the punks".getBytes()); aliceGroupCipher.encrypt("up the punks".getBytes());
throw new AssertionError("Should have failed!"); throw new AssertionError("Should have failed!");