diff --git a/build.gradle b/build.gradle index c71520804..84e6cc5c5 100644 --- a/build.gradle +++ b/build.gradle @@ -101,6 +101,12 @@ android { } } +tasks.whenTaskAdded { task -> + if (task.name.equals("lint")) { + task.enabled = false + } +} + def Properties props = new Properties() def propFile = new File('signing.properties') diff --git a/libaxolotl/.gitignore b/libaxolotl/.gitignore new file mode 100644 index 000000000..7673526e0 --- /dev/null +++ b/libaxolotl/.gitignore @@ -0,0 +1,2 @@ +/build +/obj diff --git a/libaxolotl/build.gradle b/libaxolotl/build.gradle new file mode 100644 index 000000000..2774bffb1 --- /dev/null +++ b/libaxolotl/build.gradle @@ -0,0 +1,34 @@ +apply plugin: 'android-library' + +repositories { + mavenCentral() +} + +dependencies { + compile 'com.google.protobuf:protobuf-java:2.4.1' +} + +android { + compileSdkVersion 19 + buildToolsVersion '19.1.0' + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_7 + targetCompatibility JavaVersion.VERSION_1_7 + } + + android { + sourceSets { + main { + jniLibs.srcDirs = ['libs'] + } + } + } + +} + +tasks.whenTaskAdded { task -> + if (task.name.equals("lint")) { + task.enabled = false + } +} \ No newline at end of file diff --git a/library/jni/Android.mk b/libaxolotl/jni/Android.mk similarity index 100% rename from library/jni/Android.mk rename to libaxolotl/jni/Android.mk diff --git a/library/jni/Application.mk b/libaxolotl/jni/Application.mk similarity index 100% rename from library/jni/Application.mk rename to libaxolotl/jni/Application.mk diff --git a/library/jni/curve25519-donna-jni.c b/libaxolotl/jni/curve25519-donna-jni.c similarity index 88% rename from library/jni/curve25519-donna-jni.c rename to libaxolotl/jni/curve25519-donna-jni.c index 4ce32bb63..71862ce22 100644 --- a/library/jni/curve25519-donna-jni.c +++ b/libaxolotl/jni/curve25519-donna-jni.c @@ -21,7 +21,7 @@ #include #include "curve25519-donna.h" -JNIEXPORT jbyteArray JNICALL Java_org_whispersystems_textsecure_crypto_ecc_Curve25519_generatePrivateKey +JNIEXPORT jbyteArray JNICALL Java_org_whispersystems_libaxolotl_ecc_Curve25519_generatePrivateKey (JNIEnv *env, jclass clazz, jbyteArray random, jboolean ephemeral) { uint8_t* privateKey = (uint8_t*)(*env)->GetByteArrayElements(env, random, 0); @@ -40,7 +40,7 @@ JNIEXPORT jbyteArray JNICALL Java_org_whispersystems_textsecure_crypto_ecc_Curve return random; } -JNIEXPORT jbyteArray JNICALL Java_org_whispersystems_textsecure_crypto_ecc_Curve25519_generatePublicKey +JNIEXPORT jbyteArray JNICALL Java_org_whispersystems_libaxolotl_ecc_Curve25519_generatePublicKey (JNIEnv *env, jclass clazz, jbyteArray privateKey) { static const uint8_t basepoint[32] = {9}; @@ -57,7 +57,7 @@ JNIEXPORT jbyteArray JNICALL Java_org_whispersystems_textsecure_crypto_ecc_Curve return publicKey; } -JNIEXPORT jbyteArray JNICALL Java_org_whispersystems_textsecure_crypto_ecc_Curve25519_calculateAgreement +JNIEXPORT jbyteArray JNICALL Java_org_whispersystems_libaxolotl_ecc_Curve25519_calculateAgreement (JNIEnv *env, jclass clazz, jbyteArray privateKey, jbyteArray publicKey) { jbyteArray sharedKey = (*env)->NewByteArray(env, 32); diff --git a/library/jni/curve25519-donna.c b/libaxolotl/jni/curve25519-donna.c similarity index 100% rename from library/jni/curve25519-donna.c rename to libaxolotl/jni/curve25519-donna.c diff --git a/library/jni/curve25519-donna.h b/libaxolotl/jni/curve25519-donna.h similarity index 100% rename from library/jni/curve25519-donna.h rename to libaxolotl/jni/curve25519-donna.h diff --git a/library/libs/armeabi-v7a/libcurve25519.so b/libaxolotl/libs/armeabi-v7a/libcurve25519.so similarity index 76% rename from library/libs/armeabi-v7a/libcurve25519.so rename to libaxolotl/libs/armeabi-v7a/libcurve25519.so index 3fa1b15aa..57efd28a8 100755 Binary files a/library/libs/armeabi-v7a/libcurve25519.so and b/libaxolotl/libs/armeabi-v7a/libcurve25519.so differ diff --git a/library/libs/armeabi/libcurve25519.so b/libaxolotl/libs/armeabi/libcurve25519.so similarity index 80% rename from library/libs/armeabi/libcurve25519.so rename to libaxolotl/libs/armeabi/libcurve25519.so index f109b7eb4..e4816e5ca 100755 Binary files a/library/libs/armeabi/libcurve25519.so and b/libaxolotl/libs/armeabi/libcurve25519.so differ diff --git a/library/libs/x86/libcurve25519.so b/libaxolotl/libs/x86/libcurve25519.so similarity index 80% rename from library/libs/x86/libcurve25519.so rename to libaxolotl/libs/x86/libcurve25519.so index bb80ed1ea..f4bc66c4a 100755 Binary files a/library/libs/x86/libcurve25519.so and b/libaxolotl/libs/x86/libcurve25519.so differ diff --git a/libaxolotl/protobuf/Makefile b/libaxolotl/protobuf/Makefile new file mode 100644 index 000000000..fae3824f1 --- /dev/null +++ b/libaxolotl/protobuf/Makefile @@ -0,0 +1,3 @@ + +all: + protoc --java_out=../src/main/java/ WhisperTextProtocol.proto diff --git a/library/protobuf/WhisperTextProtocol.proto b/libaxolotl/protobuf/WhisperTextProtocol.proto similarity index 90% rename from library/protobuf/WhisperTextProtocol.proto rename to libaxolotl/protobuf/WhisperTextProtocol.proto index 259d93b8e..a0b0a5d0d 100644 --- a/library/protobuf/WhisperTextProtocol.proto +++ b/libaxolotl/protobuf/WhisperTextProtocol.proto @@ -1,6 +1,6 @@ package textsecure; -option java_package = "org.whispersystems.textsecure.crypto.protocol"; +option java_package = "org.whispersystems.libaxolotl.protocol"; option java_outer_classname = "WhisperProtos"; message WhisperMessage { diff --git a/libaxolotl/src/androidTest/java/org/whispersystems/test/InMemorySessionState.java b/libaxolotl/src/androidTest/java/org/whispersystems/test/InMemorySessionState.java new file mode 100644 index 000000000..44c103289 --- /dev/null +++ b/libaxolotl/src/androidTest/java/org/whispersystems/test/InMemorySessionState.java @@ -0,0 +1,321 @@ +package org.whispersystems.test; + +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.libaxolotl.IdentityKeyPair; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.SessionState; +import org.whispersystems.libaxolotl.ecc.ECKeyPair; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; +import org.whispersystems.libaxolotl.ratchet.ChainKey; +import org.whispersystems.libaxolotl.ratchet.MessageKeys; +import org.whispersystems.libaxolotl.ratchet.RootKey; +import org.whispersystems.libaxolotl.util.Pair; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import javax.crypto.spec.SecretKeySpec; + +public class InMemorySessionState implements SessionState { + + private Map receiverChains = new HashMap<>(); + + private boolean needsRefresh; + private int sessionVersion; + private IdentityKey remoteIdentityKey; + private IdentityKey localIdentityKey; + private int previousCounter; + private RootKey rootKey; + private ECKeyPair senderEphemeral; + private ChainKey senderChainKey; + private int pendingPreKeyid; + private ECPublicKey pendingPreKey; + private int remoteRegistrationId; + private int localRegistrationId; + + public InMemorySessionState() {} + + public InMemorySessionState(SessionState sessionState) { + try { + this.needsRefresh = sessionState.getNeedsRefresh(); + this.sessionVersion = sessionState.getSessionVersion(); + this.remoteIdentityKey = new IdentityKey(sessionState.getRemoteIdentityKey().serialize(), 0); + this.localIdentityKey = new IdentityKey(sessionState.getLocalIdentityKey().serialize(), 0); + this.previousCounter = sessionState.getPreviousCounter(); + this.rootKey = new RootKey(sessionState.getRootKey().getKeyBytes()); + this.senderEphemeral = sessionState.getSenderEphemeralPair(); + this.senderChainKey = new ChainKey(sessionState.getSenderChainKey().getKey(), + sessionState.getSenderChainKey().getIndex()); + this.pendingPreKeyid = sessionState.getPendingPreKey().first(); + this.pendingPreKey = sessionState.getPendingPreKey().second(); + this.remoteRegistrationId = sessionState.getRemoteRegistrationId(); + this.localRegistrationId = sessionState.getLocalRegistrationId(); + } catch (InvalidKeyException e) { + throw new AssertionError(e); + } + } + + @Override + public void setNeedsRefresh(boolean needsRefresh) { + this.needsRefresh = needsRefresh; + } + + @Override + public boolean getNeedsRefresh() { + return needsRefresh; + } + + @Override + public void setSessionVersion(int version) { + this.sessionVersion = version; + } + + @Override + public int getSessionVersion() { + return sessionVersion; + } + + @Override + public void setRemoteIdentityKey(IdentityKey identityKey) { + this.remoteIdentityKey = identityKey; + } + + @Override + public void setLocalIdentityKey(IdentityKey identityKey) { + this.localIdentityKey = identityKey; + + } + + @Override + public IdentityKey getRemoteIdentityKey() { + return remoteIdentityKey; + } + + @Override + public IdentityKey getLocalIdentityKey() { + return localIdentityKey; + } + + @Override + public int getPreviousCounter() { + return previousCounter; + } + + @Override + public void setPreviousCounter(int previousCounter) { + this.previousCounter = previousCounter; + } + + @Override + public RootKey getRootKey() { + return rootKey; + } + + @Override + public void setRootKey(RootKey rootKey) { + this.rootKey = rootKey; + } + + @Override + public ECPublicKey getSenderEphemeral() { + return senderEphemeral.getPublicKey(); + } + + @Override + public ECKeyPair getSenderEphemeralPair() { + return senderEphemeral; + } + + @Override + public boolean hasReceiverChain(ECPublicKey senderEphemeral) { + return receiverChains.containsKey(senderEphemeral); + } + + @Override + public boolean hasSenderChain() { + return senderChainKey != null; + } + + @Override + public ChainKey getReceiverChainKey(ECPublicKey senderEphemeral) { + InMemoryChain chain = receiverChains.get(senderEphemeral); + return new ChainKey(chain.chainKey, chain.index); + } + + @Override + public void addReceiverChain(ECPublicKey senderEphemeral, ChainKey chainKey) { + InMemoryChain chain = new InMemoryChain(); + chain.chainKey = chainKey.getKey(); + chain.index = chainKey.getIndex(); + + receiverChains.put(senderEphemeral, chain); + } + + @Override + public void setSenderChain(ECKeyPair senderEphemeralPair, ChainKey chainKey) { + this.senderEphemeral = senderEphemeralPair; + this.senderChainKey = chainKey; + } + + @Override + public ChainKey getSenderChainKey() { + return senderChainKey; + } + + @Override + public void setSenderChainKey(ChainKey nextChainKey) { + this.senderChainKey = nextChainKey; + } + + @Override + public boolean hasMessageKeys(ECPublicKey senderEphemeral, int counter) { + InMemoryChain chain = receiverChains.get(senderEphemeral); + + if (chain == null) return false; + + for (InMemoryChain.InMemoryMessageKey messageKey : chain.messageKeys) { + if (messageKey.index == counter) { + return true; + } + } + + return false; + } + + @Override + public MessageKeys removeMessageKeys(ECPublicKey senderEphemeral, int counter) { + InMemoryChain chain = receiverChains.get(senderEphemeral); + MessageKeys results = null; + + if (chain == null) return null; + + Iterator iterator = chain.messageKeys.iterator(); + + while (iterator.hasNext()) { + InMemoryChain.InMemoryMessageKey messageKey = iterator.next(); + + if (messageKey.index == counter) { + results = new MessageKeys(new SecretKeySpec(messageKey.cipherKey, "AES"), + new SecretKeySpec(messageKey.macKey, "HmacSHA256"), + messageKey.index); + + iterator.remove(); + break; + } + } + + return results; + } + + @Override + public void setMessageKeys(ECPublicKey senderEphemeral, MessageKeys messageKeys) { + InMemoryChain chain = receiverChains.get(senderEphemeral); + InMemoryChain.InMemoryMessageKey key = new InMemoryChain.InMemoryMessageKey(); + + key.cipherKey = messageKeys.getCipherKey().getEncoded(); + key.macKey = messageKeys.getMacKey().getEncoded(); + key.index = messageKeys.getCounter(); + + chain.messageKeys.add(key); + } + + @Override + public void setReceiverChainKey(ECPublicKey senderEphemeral, ChainKey chainKey) { + InMemoryChain chain = receiverChains.get(senderEphemeral); + chain.chainKey = chainKey.getKey(); + chain.index = chainKey.getIndex(); + } + + @Override + public void setPendingKeyExchange(int sequence, ECKeyPair ourBaseKey, ECKeyPair ourEphemeralKey, IdentityKeyPair ourIdentityKey) { + throw new AssertionError(); + } + + @Override + public int getPendingKeyExchangeSequence() { + throw new AssertionError(); + } + + @Override + public ECKeyPair getPendingKeyExchangeBaseKey() throws InvalidKeyException { + throw new AssertionError(); + } + + @Override + public ECKeyPair getPendingKeyExchangeEphemeralKey() throws InvalidKeyException { + throw new AssertionError(); + } + + @Override + public IdentityKeyPair getPendingKeyExchangeIdentityKey() throws InvalidKeyException { + throw new AssertionError(); + } + + @Override + public boolean hasPendingKeyExchange() { + throw new AssertionError(); + } + + @Override + public void setPendingPreKey(int preKeyId, ECPublicKey baseKey) { + this.pendingPreKeyid = preKeyId; + this.pendingPreKey = baseKey; + } + + @Override + public boolean hasPendingPreKey() { + return this.pendingPreKey != null; + } + + @Override + public Pair getPendingPreKey() { + return new Pair<>(pendingPreKeyid, pendingPreKey); + } + + @Override + public void clearPendingPreKey() { + this.pendingPreKey = null; + this.pendingPreKeyid = -1; + } + + @Override + public void setRemoteRegistrationId(int registrationId) { + this.remoteRegistrationId = registrationId; + } + + @Override + public int getRemoteRegistrationId() { + return remoteRegistrationId; + } + + @Override + public void setLocalRegistrationId(int registrationId) { + this.localRegistrationId = registrationId; + } + + @Override + public int getLocalRegistrationId() { + return localRegistrationId; + } + + @Override + public byte[] serialize() { + throw new AssertionError(); + } + + private static class InMemoryChain { + byte[] chainKey; + int index; + List messageKeys = new LinkedList<>(); + + public static class InMemoryMessageKey { + public InMemoryMessageKey(){} + int index; + byte[] cipherKey; + byte[] macKey; + } + } +} diff --git a/libaxolotl/src/androidTest/java/org/whispersystems/test/InMemorySessionStore.java b/libaxolotl/src/androidTest/java/org/whispersystems/test/InMemorySessionStore.java new file mode 100644 index 000000000..08f7eb5de --- /dev/null +++ b/libaxolotl/src/androidTest/java/org/whispersystems/test/InMemorySessionStore.java @@ -0,0 +1,44 @@ +package org.whispersystems.test; + +import org.whispersystems.libaxolotl.SessionState; +import org.whispersystems.libaxolotl.SessionStore; + +import java.util.LinkedList; +import java.util.List; + +public class InMemorySessionStore implements SessionStore { + + private SessionState currentSessionState; + private List previousSessionStates; + + private SessionState checkedOutSessionState; + private List checkedOutPreviousSessionStates; + + public InMemorySessionStore(SessionState sessionState) { + this.currentSessionState = sessionState; + this.previousSessionStates = new LinkedList<>(); + this.checkedOutPreviousSessionStates = new LinkedList<>(); + } + + @Override + public SessionState getSessionState() { + checkedOutSessionState = new InMemorySessionState(currentSessionState); + return checkedOutSessionState; + } + + @Override + public List getPreviousSessionStates() { + checkedOutPreviousSessionStates = new LinkedList<>(); + for (SessionState state : previousSessionStates) { + checkedOutPreviousSessionStates.add(new InMemorySessionState(state)); + } + + return checkedOutPreviousSessionStates; + } + + @Override + public void save() { + this.currentSessionState = this.checkedOutSessionState; + this.previousSessionStates = this.checkedOutPreviousSessionStates; + } +} diff --git a/libaxolotl/src/androidTest/java/org/whispersystems/test/SessionCipherTest.java b/libaxolotl/src/androidTest/java/org/whispersystems/test/SessionCipherTest.java new file mode 100644 index 000000000..39345c16d --- /dev/null +++ b/libaxolotl/src/androidTest/java/org/whispersystems/test/SessionCipherTest.java @@ -0,0 +1,76 @@ +package org.whispersystems.test; + +import android.test.AndroidTestCase; + +import org.whispersystems.libaxolotl.DuplicateMessageException; +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.libaxolotl.IdentityKeyPair; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.InvalidMessageException; +import org.whispersystems.libaxolotl.LegacyMessageException; +import org.whispersystems.libaxolotl.SessionCipher; +import org.whispersystems.libaxolotl.SessionState; +import org.whispersystems.libaxolotl.SessionStore; +import org.whispersystems.libaxolotl.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECKeyPair; +import org.whispersystems.libaxolotl.protocol.CiphertextMessage; +import org.whispersystems.libaxolotl.ratchet.RatchetingSession; + +import java.util.Arrays; + +public class SessionCipherTest extends AndroidTestCase { + + public void testBasicSession() + throws InvalidKeyException, DuplicateMessageException, + LegacyMessageException, InvalidMessageException + { + SessionState aliceSessionState = new InMemorySessionState(); + SessionState bobSessionState = new InMemorySessionState(); + + initializeSessions(aliceSessionState, bobSessionState); + + SessionStore aliceSessionStore = new InMemorySessionStore(aliceSessionState); + SessionStore bobSessionStore = new InMemorySessionStore(bobSessionState); + + SessionCipher aliceCipher = new SessionCipher(aliceSessionStore); + SessionCipher bobCipher = new SessionCipher(bobSessionStore); + + byte[] alicePlaintext = "This is a plaintext message.".getBytes(); + CiphertextMessage message = aliceCipher.encrypt(alicePlaintext); + byte[] bobPlaintext = bobCipher.decrypt(message.serialize()); + + assertTrue(Arrays.equals(alicePlaintext, bobPlaintext)); + + byte[] bobReply = "This is a message from Bob.".getBytes(); + CiphertextMessage reply = bobCipher.encrypt(bobReply); + byte[] receivedReply = aliceCipher.decrypt(reply.serialize()); + + assertTrue(Arrays.equals(bobReply, receivedReply)); + } + + + private void initializeSessions(SessionState aliceSessionState, SessionState bobSessionState) + throws InvalidKeyException + { + ECKeyPair aliceIdentityKeyPair = Curve.generateKeyPair(false); + IdentityKeyPair aliceIdentityKey = new IdentityKeyPair(new IdentityKey(aliceIdentityKeyPair.getPublicKey()), + aliceIdentityKeyPair.getPrivateKey()); + ECKeyPair aliceBaseKey = Curve.generateKeyPair(true); + ECKeyPair aliceEphemeralKey = Curve.generateKeyPair(true); + + ECKeyPair bobIdentityKeyPair = Curve.generateKeyPair(false); + IdentityKeyPair bobIdentityKey = new IdentityKeyPair(new IdentityKey(bobIdentityKeyPair.getPublicKey()), + bobIdentityKeyPair.getPrivateKey()); + ECKeyPair bobBaseKey = Curve.generateKeyPair(true); + ECKeyPair bobEphemeralKey = bobBaseKey; + + + RatchetingSession.initializeSession(aliceSessionState, aliceBaseKey, bobBaseKey.getPublicKey(), + aliceEphemeralKey, bobEphemeralKey.getPublicKey(), + aliceIdentityKey, bobIdentityKey.getPublicKey()); + + RatchetingSession.initializeSession(bobSessionState, bobBaseKey, aliceBaseKey.getPublicKey(), + bobEphemeralKey, aliceEphemeralKey.getPublicKey(), + bobIdentityKey, aliceIdentityKey.getPublicKey()); + } +} diff --git a/libaxolotl/src/androidTest/java/org/whispersystems/test/ecc/Curve25519Test.java b/libaxolotl/src/androidTest/java/org/whispersystems/test/ecc/Curve25519Test.java new file mode 100644 index 000000000..5903353de --- /dev/null +++ b/libaxolotl/src/androidTest/java/org/whispersystems/test/ecc/Curve25519Test.java @@ -0,0 +1,82 @@ +package org.whispersystems.test.ecc; + +import android.test.AndroidTestCase; + +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECKeyPair; +import org.whispersystems.libaxolotl.ecc.ECPrivateKey; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; + +import java.util.Arrays; + + +public class Curve25519Test extends AndroidTestCase { + + public void testAgreement() throws InvalidKeyException { + + byte[] alicePublic = {(byte) 0x05, (byte) 0x1b, (byte) 0xb7, (byte) 0x59, (byte) 0x66, + (byte) 0xf2, (byte) 0xe9, (byte) 0x3a, (byte) 0x36, (byte) 0x91, + (byte) 0xdf, (byte) 0xff, (byte) 0x94, (byte) 0x2b, (byte) 0xb2, + (byte) 0xa4, (byte) 0x66, (byte) 0xa1, (byte) 0xc0, (byte) 0x8b, + (byte) 0x8d, (byte) 0x78, (byte) 0xca, (byte) 0x3f, (byte) 0x4d, + (byte) 0x6d, (byte) 0xf8, (byte) 0xb8, (byte) 0xbf, (byte) 0xa2, + (byte) 0xe4, (byte) 0xee, (byte) 0x28}; + + byte[] alicePrivate = {(byte) 0xc8, (byte) 0x06, (byte) 0x43, (byte) 0x9d, (byte) 0xc9, + (byte) 0xd2, (byte) 0xc4, (byte) 0x76, (byte) 0xff, (byte) 0xed, + (byte) 0x8f, (byte) 0x25, (byte) 0x80, (byte) 0xc0, (byte) 0x88, + (byte) 0x8d, (byte) 0x58, (byte) 0xab, (byte) 0x40, (byte) 0x6b, + (byte) 0xf7, (byte) 0xae, (byte) 0x36, (byte) 0x98, (byte) 0x87, + (byte) 0x90, (byte) 0x21, (byte) 0xb9, (byte) 0x6b, (byte) 0xb4, + (byte) 0xbf, (byte) 0x59}; + + byte[] bobPublic = {(byte) 0x05, (byte) 0x65, (byte) 0x36, (byte) 0x14, (byte) 0x99, + (byte) 0x3d, (byte) 0x2b, (byte) 0x15, (byte) 0xee, (byte) 0x9e, + (byte) 0x5f, (byte) 0xd3, (byte) 0xd8, (byte) 0x6c, (byte) 0xe7, + (byte) 0x19, (byte) 0xef, (byte) 0x4e, (byte) 0xc1, (byte) 0xda, + (byte) 0xae, (byte) 0x18, (byte) 0x86, (byte) 0xa8, (byte) 0x7b, + (byte) 0x3f, (byte) 0x5f, (byte) 0xa9, (byte) 0x56, (byte) 0x5a, + (byte) 0x27, (byte) 0xa2, (byte) 0x2f}; + + byte[] bobPrivate = {(byte) 0xb0, (byte) 0x3b, (byte) 0x34, (byte) 0xc3, (byte) 0x3a, + (byte) 0x1c, (byte) 0x44, (byte) 0xf2, (byte) 0x25, (byte) 0xb6, + (byte) 0x62, (byte) 0xd2, (byte) 0xbf, (byte) 0x48, (byte) 0x59, + (byte) 0xb8, (byte) 0x13, (byte) 0x54, (byte) 0x11, (byte) 0xfa, + (byte) 0x7b, (byte) 0x03, (byte) 0x86, (byte) 0xd4, (byte) 0x5f, + (byte) 0xb7, (byte) 0x5d, (byte) 0xc5, (byte) 0xb9, (byte) 0x1b, + (byte) 0x44, (byte) 0x66}; + + byte[] shared = {(byte) 0x32, (byte) 0x5f, (byte) 0x23, (byte) 0x93, (byte) 0x28, + (byte) 0x94, (byte) 0x1c, (byte) 0xed, (byte) 0x6e, (byte) 0x67, + (byte) 0x3b, (byte) 0x86, (byte) 0xba, (byte) 0x41, (byte) 0x01, + (byte) 0x74, (byte) 0x48, (byte) 0xe9, (byte) 0x9b, (byte) 0x64, + (byte) 0x9a, (byte) 0x9c, (byte) 0x38, (byte) 0x06, (byte) 0xc1, + (byte) 0xdd, (byte) 0x7c, (byte) 0xa4, (byte) 0xc4, (byte) 0x77, + (byte) 0xe6, (byte) 0x29}; + + ECPublicKey alicePublicKey = Curve.decodePoint(alicePublic, 0); + ECPrivateKey alicePrivateKey = Curve.decodePrivatePoint(alicePrivate); + + ECPublicKey bobPublicKey = Curve.decodePoint(bobPublic, 0); + ECPrivateKey bobPrivateKey = Curve.decodePrivatePoint(bobPrivate); + + byte[] sharedOne = Curve.calculateAgreement(alicePublicKey, bobPrivateKey); + byte[] sharedTwo = Curve.calculateAgreement(bobPublicKey, alicePrivateKey); + + assertTrue(Arrays.equals(sharedOne, shared)); + assertTrue(Arrays.equals(sharedTwo, shared)); + } + + public void testRandomAgreements() throws InvalidKeyException { + for (int i=0;i<50;i++) { + ECKeyPair alice = Curve.generateKeyPair(false); + ECKeyPair bob = Curve.generateKeyPair(false); + + byte[] sharedAlice = Curve.calculateAgreement(bob.getPublicKey(), alice.getPrivateKey()); + byte[] sharedBob = Curve.calculateAgreement(alice.getPublicKey(), bob.getPrivateKey()); + + assertTrue(Arrays.equals(sharedAlice, sharedBob)); + } + } +} diff --git a/libaxolotl/src/androidTest/java/org/whispersystems/test/kdf/HKDFTest.java b/libaxolotl/src/androidTest/java/org/whispersystems/test/kdf/HKDFTest.java new file mode 100644 index 000000000..c26ffa1cb --- /dev/null +++ b/libaxolotl/src/androidTest/java/org/whispersystems/test/kdf/HKDFTest.java @@ -0,0 +1,44 @@ +package org.whispersystems.test.kdf; + +import android.test.AndroidTestCase; + +import org.whispersystems.libaxolotl.kdf.DerivedSecrets; +import org.whispersystems.libaxolotl.kdf.HKDF; + +import java.util.Arrays; + +public class HKDFTest extends AndroidTestCase { + + public void testVector() { + byte[] ikm = {0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b}; + + byte[] salt = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c}; + + byte[] info = {(byte)0xf0, (byte)0xf1, (byte)0xf2, (byte)0xf3, (byte)0xf4, + (byte)0xf5, (byte)0xf6, (byte)0xf7, (byte)0xf8, (byte)0xf9}; + + byte[] expectedOutputOne = {(byte)0x6e, (byte)0xc2, (byte)0x55, (byte)0x6d, (byte)0x5d, + (byte)0x7b, (byte)0x1d, (byte)0x81, (byte)0xde, (byte)0xe4, + (byte)0x22, (byte)0x2a, (byte)0xd7, (byte)0x48, (byte)0x36, + (byte)0x95, (byte)0xdd, (byte)0xc9, (byte)0x8f, (byte)0x4f, + (byte)0x5f, (byte)0xab, (byte)0xc0, (byte)0xe0, (byte)0x20, + (byte)0x5d, (byte)0xc2, (byte)0xef, (byte)0x87, (byte)0x52, + (byte)0xd4, (byte)0x1e}; + + byte[] expectedOutputTwo = {(byte)0x04, (byte)0xe2, (byte)0xe2, (byte)0x11, (byte)0x01, + (byte)0xc6, (byte)0x8f, (byte)0xf0, (byte)0x93, (byte)0x94, + (byte)0xb8, (byte)0xad, (byte)0x0b, (byte)0xdc, (byte)0xb9, + (byte)0x60, (byte)0x9c, (byte)0xd4, (byte)0xee, (byte)0x82, + (byte)0xac, (byte)0x13, (byte)0x19, (byte)0x9b, (byte)0x4a, + (byte)0xa9, (byte)0xfd, (byte)0xa8, (byte)0x99, (byte)0xda, + (byte)0xeb, (byte)0xec}; + + DerivedSecrets derivedSecrets = new HKDF().deriveSecrets(ikm, salt, info); + + assertTrue(Arrays.equals(derivedSecrets.getCipherKey().getEncoded(), expectedOutputOne)); + assertTrue(Arrays.equals(derivedSecrets.getMacKey().getEncoded(), expectedOutputTwo)); + } +} diff --git a/libaxolotl/src/androidTest/java/org/whispersystems/test/ratchet/ChainKeyTest.java b/libaxolotl/src/androidTest/java/org/whispersystems/test/ratchet/ChainKeyTest.java new file mode 100644 index 000000000..2cf5dcbd4 --- /dev/null +++ b/libaxolotl/src/androidTest/java/org/whispersystems/test/ratchet/ChainKeyTest.java @@ -0,0 +1,58 @@ +package org.whispersystems.test.ratchet; + +import android.test.AndroidTestCase; + +import org.whispersystems.libaxolotl.ratchet.ChainKey; + +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; + +public class ChainKeyTest extends AndroidTestCase { + + public void testChainKeyDerivation() throws NoSuchAlgorithmException { + + byte[] seed = {(byte) 0x8a, (byte) 0xb7, (byte) 0x2d, (byte) 0x6f, (byte) 0x4c, + (byte) 0xc5, (byte) 0xac, (byte) 0x0d, (byte) 0x38, (byte) 0x7e, + (byte) 0xaf, (byte) 0x46, (byte) 0x33, (byte) 0x78, (byte) 0xdd, + (byte) 0xb2, (byte) 0x8e, (byte) 0xdd, (byte) 0x07, (byte) 0x38, + (byte) 0x5b, (byte) 0x1c, (byte) 0xb0, (byte) 0x12, (byte) 0x50, + (byte) 0xc7, (byte) 0x15, (byte) 0x98, (byte) 0x2e, (byte) 0x7a, + (byte) 0xd4, (byte) 0x8f}; + + byte[] messageKey = {(byte) 0x02, (byte) 0xa9, (byte) 0xaa, (byte) 0x6c, (byte) 0x7d, + (byte) 0xbd, (byte) 0x64, (byte) 0xf9, (byte) 0xd3, (byte) 0xaa, + (byte) 0x92, (byte) 0xf9, (byte) 0x2a, (byte) 0x27, (byte) 0x7b, + (byte) 0xf5, (byte) 0x46, (byte) 0x09, (byte) 0xda, (byte) 0xdf, + (byte) 0x0b, (byte) 0x00, (byte) 0x82, (byte) 0x8a, (byte) 0xcf, + (byte) 0xc6, (byte) 0x1e, (byte) 0x3c, (byte) 0x72, (byte) 0x4b, + (byte) 0x84, (byte) 0xa7}; + + byte[] macKey = {(byte) 0xbf, (byte) 0xbe, (byte) 0x5e, (byte) 0xfb, (byte) 0x60, + (byte) 0x30, (byte) 0x30, (byte) 0x52, (byte) 0x67, (byte) 0x42, + (byte) 0xe3, (byte) 0xee, (byte) 0x89, (byte) 0xc7, (byte) 0x02, + (byte) 0x4e, (byte) 0x88, (byte) 0x4e, (byte) 0x44, (byte) 0x0f, + (byte) 0x1f, (byte) 0xf3, (byte) 0x76, (byte) 0xbb, (byte) 0x23, + (byte) 0x17, (byte) 0xb2, (byte) 0xd6, (byte) 0x4d, (byte) 0xeb, + (byte) 0x7c, (byte) 0x83}; + + byte[] nextChainKey = {(byte) 0x28, (byte) 0xe8, (byte) 0xf8, (byte) 0xfe, (byte) 0xe5, + (byte) 0x4b, (byte) 0x80, (byte) 0x1e, (byte) 0xef, (byte) 0x7c, + (byte) 0x5c, (byte) 0xfb, (byte) 0x2f, (byte) 0x17, (byte) 0xf3, + (byte) 0x2c, (byte) 0x7b, (byte) 0x33, (byte) 0x44, (byte) 0x85, + (byte) 0xbb, (byte) 0xb7, (byte) 0x0f, (byte) 0xac, (byte) 0x6e, + (byte) 0xc1, (byte) 0x03, (byte) 0x42, (byte) 0xa2, (byte) 0x46, + (byte) 0xd1, (byte) 0x5d}; + + ChainKey chainKey = new ChainKey(seed, 0); + + assertTrue(Arrays.equals(chainKey.getKey(), seed)); + assertTrue(Arrays.equals(chainKey.getMessageKeys().getCipherKey().getEncoded(), messageKey)); + assertTrue(Arrays.equals(chainKey.getMessageKeys().getMacKey().getEncoded(), macKey)); + assertTrue(Arrays.equals(chainKey.getNextChainKey().getKey(), nextChainKey)); + assertTrue(chainKey.getIndex() == 0); + assertTrue(chainKey.getMessageKeys().getCounter() == 0); + assertTrue(chainKey.getNextChainKey().getIndex() == 1); + assertTrue(chainKey.getNextChainKey().getMessageKeys().getCounter() == 1); + } + +} diff --git a/libaxolotl/src/androidTest/java/org/whispersystems/test/ratchet/RatchetingSessionTest.java b/libaxolotl/src/androidTest/java/org/whispersystems/test/ratchet/RatchetingSessionTest.java new file mode 100644 index 000000000..fa72ee192 --- /dev/null +++ b/libaxolotl/src/androidTest/java/org/whispersystems/test/ratchet/RatchetingSessionTest.java @@ -0,0 +1,218 @@ +package org.whispersystems.test.ratchet; + +import android.test.AndroidTestCase; + +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.libaxolotl.IdentityKeyPair; +import org.whispersystems.test.InMemorySessionState; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.SessionState; +import org.whispersystems.libaxolotl.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECKeyPair; +import org.whispersystems.libaxolotl.ecc.ECPrivateKey; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; +import org.whispersystems.libaxolotl.ratchet.RatchetingSession; + +import java.util.Arrays; + +public class RatchetingSessionTest extends AndroidTestCase { + + public void testRatchetingSessionAsBob() throws InvalidKeyException { + byte[] bobPublic = {(byte) 0x05, (byte) 0x2c, (byte) 0xb4, (byte) 0x97, + (byte) 0x76, (byte) 0xb8, (byte) 0x77, (byte) 0x02, + (byte) 0x05, (byte) 0x74, (byte) 0x5a, (byte) 0x3a, + (byte) 0x6e, (byte) 0x24, (byte) 0xf5, (byte) 0x79, + (byte) 0xcd, (byte) 0xb4, (byte) 0xba, (byte) 0x7a, + (byte) 0x89, (byte) 0x04, (byte) 0x10, (byte) 0x05, + (byte) 0x92, (byte) 0x8e, (byte) 0xbb, (byte) 0xad, + (byte) 0xc9, (byte) 0xc0, (byte) 0x5a, (byte) 0xd4, + (byte) 0x58}; + + byte[] bobPrivate = {(byte) 0xa1, (byte) 0xca, (byte) 0xb4, (byte) 0x8f, + (byte) 0x7c, (byte) 0x89, (byte) 0x3f, (byte) 0xaf, + (byte) 0xa9, (byte) 0x88, (byte) 0x0a, (byte) 0x28, + (byte) 0xc3, (byte) 0xb4, (byte) 0x99, (byte) 0x9d, + (byte) 0x28, (byte) 0xd6, (byte) 0x32, (byte) 0x95, + (byte) 0x62, (byte) 0xd2, (byte) 0x7a, (byte) 0x4e, + (byte) 0xa4, (byte) 0xe2, (byte) 0x2e, (byte) 0x9f, + (byte) 0xf1, (byte) 0xbd, (byte) 0xd6, (byte) 0x5a}; + + byte[] bobIdentityPublic = {(byte) 0x05, (byte) 0xf1, (byte) 0xf4, (byte) 0x38, + (byte) 0x74, (byte) 0xf6, (byte) 0x96, (byte) 0x69, + (byte) 0x56, (byte) 0xc2, (byte) 0xdd, (byte) 0x47, + (byte) 0x3f, (byte) 0x8f, (byte) 0xa1, (byte) 0x5a, + (byte) 0xde, (byte) 0xb7, (byte) 0x1d, (byte) 0x1c, + (byte) 0xb9, (byte) 0x91, (byte) 0xb2, (byte) 0x34, + (byte) 0x16, (byte) 0x92, (byte) 0x32, (byte) 0x4c, + (byte) 0xef, (byte) 0xb1, (byte) 0xc5, (byte) 0xe6, + (byte) 0x26}; + + byte[] bobIdentityPrivate = {(byte) 0x48, (byte) 0x75, (byte) 0xcc, (byte) 0x69, + (byte) 0xdd, (byte) 0xf8, (byte) 0xea, (byte) 0x07, + (byte) 0x19, (byte) 0xec, (byte) 0x94, (byte) 0x7d, + (byte) 0x61, (byte) 0x08, (byte) 0x11, (byte) 0x35, + (byte) 0x86, (byte) 0x8d, (byte) 0x5f, (byte) 0xd8, + (byte) 0x01, (byte) 0xf0, (byte) 0x2c, (byte) 0x02, + (byte) 0x25, (byte) 0xe5, (byte) 0x16, (byte) 0xdf, + (byte) 0x21, (byte) 0x56, (byte) 0x60, (byte) 0x5e}; + + byte[] aliceBasePublic = {(byte) 0x05, (byte) 0x47, (byte) 0x2d, (byte) 0x1f, + (byte) 0xb1, (byte) 0xa9, (byte) 0x86, (byte) 0x2c, + (byte) 0x3a, (byte) 0xf6, (byte) 0xbe, (byte) 0xac, + (byte) 0xa8, (byte) 0x92, (byte) 0x02, (byte) 0x77, + (byte) 0xe2, (byte) 0xb2, (byte) 0x6f, (byte) 0x4a, + (byte) 0x79, (byte) 0x21, (byte) 0x3e, (byte) 0xc7, + (byte) 0xc9, (byte) 0x06, (byte) 0xae, (byte) 0xb3, + (byte) 0x5e, (byte) 0x03, (byte) 0xcf, (byte) 0x89, + (byte) 0x50}; + + byte[] aliceEphemeralPublic = {(byte) 0x05, (byte) 0x6c, (byte) 0x3e, (byte) 0x0d, + (byte) 0x1f, (byte) 0x52, (byte) 0x02, (byte) 0x83, + (byte) 0xef, (byte) 0xcc, (byte) 0x55, (byte) 0xfc, + (byte) 0xa5, (byte) 0xe6, (byte) 0x70, (byte) 0x75, + (byte) 0xb9, (byte) 0x04, (byte) 0x00, (byte) 0x7f, + (byte) 0x18, (byte) 0x81, (byte) 0xd1, (byte) 0x51, + (byte) 0xaf, (byte) 0x76, (byte) 0xdf, (byte) 0x18, + (byte) 0xc5, (byte) 0x1d, (byte) 0x29, (byte) 0xd3, + (byte) 0x4b}; + + byte[] aliceIdentityPublic = {(byte) 0x05, (byte) 0xb4, (byte) 0xa8, (byte) 0x45, + (byte) 0x56, (byte) 0x60, (byte) 0xad, (byte) 0xa6, + (byte) 0x5b, (byte) 0x40, (byte) 0x10, (byte) 0x07, + (byte) 0xf6, (byte) 0x15, (byte) 0xe6, (byte) 0x54, + (byte) 0x04, (byte) 0x17, (byte) 0x46, (byte) 0x43, + (byte) 0x2e, (byte) 0x33, (byte) 0x39, (byte) 0xc6, + (byte) 0x87, (byte) 0x51, (byte) 0x49, (byte) 0xbc, + (byte) 0xee, (byte) 0xfc, (byte) 0xb4, (byte) 0x2b, + (byte) 0x4a}; + + byte[] senderChain = {(byte)0xd2, (byte)0x2f, (byte)0xd5, (byte)0x6d, (byte)0x3f, + (byte)0xec, (byte)0x81, (byte)0x9c, (byte)0xf4, (byte)0xc3, + (byte)0xd5, (byte)0x0c, (byte)0x56, (byte)0xed, (byte)0xfb, + (byte)0x1c, (byte)0x28, (byte)0x0a, (byte)0x1b, (byte)0x31, + (byte)0x96, (byte)0x45, (byte)0x37, (byte)0xf1, (byte)0xd1, + (byte)0x61, (byte)0xe1, (byte)0xc9, (byte)0x31, (byte)0x48, + (byte)0xe3, (byte)0x6b}; + + IdentityKey bobIdentityKeyPublic = new IdentityKey(bobIdentityPublic, 0); + ECPrivateKey bobIdentityKeyPrivate = Curve.decodePrivatePoint(bobIdentityPrivate); + IdentityKeyPair bobIdentityKey = new IdentityKeyPair(bobIdentityKeyPublic, bobIdentityKeyPrivate); + ECPublicKey bobEphemeralPublicKey = Curve.decodePoint(bobPublic, 0); + ECPrivateKey bobEphemeralPrivateKey = Curve.decodePrivatePoint(bobPrivate); + ECKeyPair bobEphemeralKey = new ECKeyPair(bobEphemeralPublicKey, bobEphemeralPrivateKey); + ECKeyPair bobBaseKey = bobEphemeralKey; + + ECPublicKey aliceBasePublicKey = Curve.decodePoint(aliceBasePublic, 0); + ECPublicKey aliceEphemeralPublicKey = Curve.decodePoint(aliceEphemeralPublic, 0); + IdentityKey aliceIdentityPublicKey = new IdentityKey(aliceIdentityPublic, 0); + + SessionState session = new InMemorySessionState(); + + RatchetingSession.initializeSession(session, bobBaseKey, aliceBasePublicKey, + bobEphemeralKey, aliceEphemeralPublicKey, + bobIdentityKey, aliceIdentityPublicKey); + + assertTrue(session.getLocalIdentityKey().equals(bobIdentityKey.getPublicKey())); + assertTrue(session.getRemoteIdentityKey().equals(aliceIdentityPublicKey)); + assertTrue(Arrays.equals(session.getSenderChainKey().getKey(), senderChain)); + } + + public void testRatchetingSessionAsAlice() throws InvalidKeyException { + byte[] bobPublic = {(byte) 0x05, (byte) 0x2c, (byte) 0xb4, (byte) 0x97, (byte) 0x76, + (byte) 0xb8, (byte) 0x77, (byte) 0x02, (byte) 0x05, (byte) 0x74, + (byte) 0x5a, (byte) 0x3a, (byte) 0x6e, (byte) 0x24, (byte) 0xf5, + (byte) 0x79, (byte) 0xcd, (byte) 0xb4, (byte) 0xba, (byte) 0x7a, + (byte) 0x89, (byte) 0x04, (byte) 0x10, (byte) 0x05, (byte) 0x92, + (byte) 0x8e, (byte) 0xbb, (byte) 0xad, (byte) 0xc9, (byte) 0xc0, + (byte) 0x5a, (byte) 0xd4, (byte) 0x58}; + + byte[] bobIdentityPublic = {(byte) 0x05, (byte) 0xf1, (byte) 0xf4, (byte) 0x38, (byte) 0x74, + (byte) 0xf6, (byte) 0x96, (byte) 0x69, (byte) 0x56, (byte) 0xc2, + (byte) 0xdd, (byte) 0x47, (byte) 0x3f, (byte) 0x8f, (byte) 0xa1, + (byte) 0x5a, (byte) 0xde, (byte) 0xb7, (byte) 0x1d, (byte) 0x1c, + (byte) 0xb9, (byte) 0x91, (byte) 0xb2, (byte) 0x34, (byte) 0x16, + (byte) 0x92, (byte) 0x32, (byte) 0x4c, (byte) 0xef, (byte) 0xb1, + (byte) 0xc5, (byte) 0xe6, (byte) 0x26}; + + byte[] aliceBasePublic = {(byte) 0x05, (byte) 0x47, (byte) 0x2d, (byte) 0x1f, (byte) 0xb1, + (byte) 0xa9, (byte) 0x86, (byte) 0x2c, (byte) 0x3a, (byte) 0xf6, + (byte) 0xbe, (byte) 0xac, (byte) 0xa8, (byte) 0x92, (byte) 0x02, + (byte) 0x77, (byte) 0xe2, (byte) 0xb2, (byte) 0x6f, (byte) 0x4a, + (byte) 0x79, (byte) 0x21, (byte) 0x3e, (byte) 0xc7, (byte) 0xc9, + (byte) 0x06, (byte) 0xae, (byte) 0xb3, (byte) 0x5e, (byte) 0x03, + (byte) 0xcf, (byte) 0x89, (byte) 0x50}; + + byte[] aliceBasePrivate = {(byte) 0x11, (byte) 0xae, (byte) 0x7c, (byte) 0x64, (byte) 0xd1, + (byte) 0xe6, (byte) 0x1c, (byte) 0xd5, (byte) 0x96, (byte) 0xb7, + (byte) 0x6a, (byte) 0x0d, (byte) 0xb5, (byte) 0x01, (byte) 0x26, + (byte) 0x73, (byte) 0x39, (byte) 0x1c, (byte) 0xae, (byte) 0x66, + (byte) 0xed, (byte) 0xbf, (byte) 0xcf, (byte) 0x07, (byte) 0x3b, + (byte) 0x4d, (byte) 0xa8, (byte) 0x05, (byte) 0x16, (byte) 0xa4, + (byte) 0x74, (byte) 0x49}; + + byte[] aliceEphemeralPublic = {(byte) 0x05, (byte) 0x6c, (byte) 0x3e, (byte) 0x0d, (byte) 0x1f, + (byte) 0x52, (byte) 0x02, (byte) 0x83, (byte) 0xef, (byte) 0xcc, + (byte) 0x55, (byte) 0xfc, (byte) 0xa5, (byte) 0xe6, (byte) 0x70, + (byte) 0x75, (byte) 0xb9, (byte) 0x04, (byte) 0x00, (byte) 0x7f, + (byte) 0x18, (byte) 0x81, (byte) 0xd1, (byte) 0x51, (byte) 0xaf, + (byte) 0x76, (byte) 0xdf, (byte) 0x18, (byte) 0xc5, (byte) 0x1d, + (byte) 0x29, (byte) 0xd3, (byte) 0x4b}; + + byte[] aliceEphemeralPrivate = {(byte) 0xd1, (byte) 0xba, (byte) 0x38, (byte) 0xce, (byte) 0xa9, + (byte) 0x17, (byte) 0x43, (byte) 0xd3, (byte) 0x39, (byte) 0x39, + (byte) 0xc3, (byte) 0x3c, (byte) 0x84, (byte) 0x98, (byte) 0x65, + (byte) 0x09, (byte) 0x28, (byte) 0x01, (byte) 0x61, (byte) 0xb8, + (byte) 0xb6, (byte) 0x0f, (byte) 0xc7, (byte) 0x87, (byte) 0x0c, + (byte) 0x59, (byte) 0x9c, (byte) 0x1d, (byte) 0x46, (byte) 0x20, + (byte) 0x12, (byte) 0x48}; + + byte[] aliceIdentityPublic = {(byte) 0x05, (byte) 0xb4, (byte) 0xa8, (byte) 0x45, (byte) 0x56, + (byte) 0x60, (byte) 0xad, (byte) 0xa6, (byte) 0x5b, (byte) 0x40, + (byte) 0x10, (byte) 0x07, (byte) 0xf6, (byte) 0x15, (byte) 0xe6, + (byte) 0x54, (byte) 0x04, (byte) 0x17, (byte) 0x46, (byte) 0x43, + (byte) 0x2e, (byte) 0x33, (byte) 0x39, (byte) 0xc6, (byte) 0x87, + (byte) 0x51, (byte) 0x49, (byte) 0xbc, (byte) 0xee, (byte) 0xfc, + (byte) 0xb4, (byte) 0x2b, (byte) 0x4a}; + + byte[] aliceIdentityPrivate = {(byte) 0x90, (byte) 0x40, (byte) 0xf0, (byte) 0xd4, (byte) 0xe0, + (byte) 0x9c, (byte) 0xf3, (byte) 0x8f, (byte) 0x6d, (byte) 0xc7, + (byte) 0xc1, (byte) 0x37, (byte) 0x79, (byte) 0xc9, (byte) 0x08, + (byte) 0xc0, (byte) 0x15, (byte) 0xa1, (byte) 0xda, (byte) 0x4f, + (byte) 0xa7, (byte) 0x87, (byte) 0x37, (byte) 0xa0, (byte) 0x80, + (byte) 0xeb, (byte) 0x0a, (byte) 0x6f, (byte) 0x4f, (byte) 0x5f, + (byte) 0x8f, (byte) 0x58}; + + byte[] receiverChain = {(byte) 0xd2, (byte) 0x2f, (byte) 0xd5, (byte) 0x6d, (byte) 0x3f, + (byte) 0xec, (byte) 0x81, (byte) 0x9c, (byte) 0xf4, (byte) 0xc3, + (byte) 0xd5, (byte) 0x0c, (byte) 0x56, (byte) 0xed, (byte) 0xfb, + (byte) 0x1c, (byte) 0x28, (byte) 0x0a, (byte) 0x1b, (byte) 0x31, + (byte) 0x96, (byte) 0x45, (byte) 0x37, (byte) 0xf1, (byte) 0xd1, + (byte) 0x61, (byte) 0xe1, (byte) 0xc9, (byte) 0x31, (byte) 0x48, + (byte) 0xe3, (byte) 0x6b}; + + IdentityKey bobIdentityKey = new IdentityKey(bobIdentityPublic, 0); + ECPublicKey bobEphemeralPublicKey = Curve.decodePoint(bobPublic, 0); + ECPublicKey bobBasePublicKey = bobEphemeralPublicKey; + ECPublicKey aliceBasePublicKey = Curve.decodePoint(aliceBasePublic, 0); + ECPrivateKey aliceBasePrivateKey = Curve.decodePrivatePoint(aliceBasePrivate); + ECKeyPair aliceBaseKey = new ECKeyPair(aliceBasePublicKey, aliceBasePrivateKey); + ECPublicKey aliceEphemeralPublicKey = Curve.decodePoint(aliceEphemeralPublic, 0); + ECPrivateKey aliceEphemeralPrivateKey = Curve.decodePrivatePoint(aliceEphemeralPrivate); + ECKeyPair aliceEphemeralKey = new ECKeyPair(aliceEphemeralPublicKey, aliceEphemeralPrivateKey); + IdentityKey aliceIdentityPublicKey = new IdentityKey(aliceIdentityPublic, 0); + ECPrivateKey aliceIdentityPrivateKey = Curve.decodePrivatePoint(aliceIdentityPrivate); + IdentityKeyPair aliceIdentityKey = new IdentityKeyPair(aliceIdentityPublicKey, aliceIdentityPrivateKey); + + SessionState session = new InMemorySessionState(); + + RatchetingSession.initializeSession(session, aliceBaseKey, bobBasePublicKey, + aliceEphemeralKey, bobEphemeralPublicKey, + aliceIdentityKey, bobIdentityKey); + + assertTrue(session.getLocalIdentityKey().equals(aliceIdentityKey.getPublicKey())); + assertTrue(session.getRemoteIdentityKey().equals(bobIdentityKey)); + assertTrue(Arrays.equals(session.getReceiverChainKey(bobEphemeralPublicKey).getKey(), + receiverChain)); + + } +} diff --git a/libaxolotl/src/androidTest/java/org/whispersystems/test/ratchet/RootKeyTest.java b/libaxolotl/src/androidTest/java/org/whispersystems/test/ratchet/RootKeyTest.java new file mode 100644 index 000000000..313cd6b36 --- /dev/null +++ b/libaxolotl/src/androidTest/java/org/whispersystems/test/ratchet/RootKeyTest.java @@ -0,0 +1,83 @@ +package org.whispersystems.test.ratchet; + +import android.test.AndroidTestCase; + +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECKeyPair; +import org.whispersystems.libaxolotl.ecc.ECPrivateKey; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; +import org.whispersystems.libaxolotl.ratchet.ChainKey; +import org.whispersystems.libaxolotl.ratchet.RootKey; +import org.whispersystems.libaxolotl.util.Pair; + +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; + +public class RootKeyTest extends AndroidTestCase { + + public void testRootKeyDerivation() throws NoSuchAlgorithmException, InvalidKeyException { + byte[] rootKeySeed = {(byte) 0x7b, (byte) 0xa6, (byte) 0xde, (byte) 0xbc, (byte) 0x2b, + (byte) 0xc1, (byte) 0xbb, (byte) 0xf9, (byte) 0x1a, (byte) 0xbb, + (byte) 0xc1, (byte) 0x36, (byte) 0x74, (byte) 0x04, (byte) 0x17, + (byte) 0x6c, (byte) 0xa6, (byte) 0x23, (byte) 0x09, (byte) 0x5b, + (byte) 0x7e, (byte) 0xc6, (byte) 0x6b, (byte) 0x45, (byte) 0xf6, + (byte) 0x02, (byte) 0xd9, (byte) 0x35, (byte) 0x38, (byte) 0x94, + (byte) 0x2d, (byte) 0xcc}; + + byte[] alicePublic = {(byte) 0x05, (byte) 0xee, (byte) 0x4f, (byte) 0xa6, (byte) 0xcd, + (byte) 0xc0, (byte) 0x30, (byte) 0xdf, (byte) 0x49, (byte) 0xec, + (byte) 0xd0, (byte) 0xba, (byte) 0x6c, (byte) 0xfc, (byte) 0xff, + (byte) 0xb2, (byte) 0x33, (byte) 0xd3, (byte) 0x65, (byte) 0xa2, + (byte) 0x7f, (byte) 0xad, (byte) 0xbe, (byte) 0xff, (byte) 0x77, + (byte) 0xe9, (byte) 0x63, (byte) 0xfc, (byte) 0xb1, (byte) 0x62, + (byte) 0x22, (byte) 0xe1, (byte) 0x3a}; + + byte[] alicePrivate = {(byte) 0x21, (byte) 0x68, (byte) 0x22, (byte) 0xec, (byte) 0x67, + (byte) 0xeb, (byte) 0x38, (byte) 0x04, (byte) 0x9e, (byte) 0xba, + (byte) 0xe7, (byte) 0xb9, (byte) 0x39, (byte) 0xba, (byte) 0xea, + (byte) 0xeb, (byte) 0xb1, (byte) 0x51, (byte) 0xbb, (byte) 0xb3, + (byte) 0x2d, (byte) 0xb8, (byte) 0x0f, (byte) 0xd3, (byte) 0x89, + (byte) 0x24, (byte) 0x5a, (byte) 0xc3, (byte) 0x7a, (byte) 0x94, + (byte) 0x8e, (byte) 0x50}; + + byte[] bobPublic = {(byte) 0x05, (byte) 0xab, (byte) 0xb8, (byte) 0xeb, (byte) 0x29, + (byte) 0xcc, (byte) 0x80, (byte) 0xb4, (byte) 0x71, (byte) 0x09, + (byte) 0xa2, (byte) 0x26, (byte) 0x5a, (byte) 0xbe, (byte) 0x97, + (byte) 0x98, (byte) 0x48, (byte) 0x54, (byte) 0x06, (byte) 0xe3, + (byte) 0x2d, (byte) 0xa2, (byte) 0x68, (byte) 0x93, (byte) 0x4a, + (byte) 0x95, (byte) 0x55, (byte) 0xe8, (byte) 0x47, (byte) 0x57, + (byte) 0x70, (byte) 0x8a, (byte) 0x30}; + + byte[] nextRoot = {(byte) 0xb1, (byte) 0x14, (byte) 0xf5, (byte) 0xde, (byte) 0x28, + (byte) 0x01, (byte) 0x19, (byte) 0x85, (byte) 0xe6, (byte) 0xeb, + (byte) 0xa2, (byte) 0x5d, (byte) 0x50, (byte) 0xe7, (byte) 0xec, + (byte) 0x41, (byte) 0xa9, (byte) 0xb0, (byte) 0x2f, (byte) 0x56, + (byte) 0x93, (byte) 0xc5, (byte) 0xc7, (byte) 0x88, (byte) 0xa6, + (byte) 0x3a, (byte) 0x06, (byte) 0xd2, (byte) 0x12, (byte) 0xa2, + (byte) 0xf7, (byte) 0x31}; + + byte[] nextChain = {(byte) 0x9d, (byte) 0x7d, (byte) 0x24, (byte) 0x69, (byte) 0xbc, + (byte) 0x9a, (byte) 0xe5, (byte) 0x3e, (byte) 0xe9, (byte) 0x80, + (byte) 0x5a, (byte) 0xa3, (byte) 0x26, (byte) 0x4d, (byte) 0x24, + (byte) 0x99, (byte) 0xa3, (byte) 0xac, (byte) 0xe8, (byte) 0x0f, + (byte) 0x4c, (byte) 0xca, (byte) 0xe2, (byte) 0xda, (byte) 0x13, + (byte) 0x43, (byte) 0x0c, (byte) 0x5c, (byte) 0x55, (byte) 0xb5, + (byte) 0xca, (byte) 0x5f}; + + ECPublicKey alicePublicKey = Curve.decodePoint(alicePublic, 0); + ECPrivateKey alicePrivateKey = Curve.decodePrivatePoint(alicePrivate); + ECKeyPair aliceKeyPair = new ECKeyPair(alicePublicKey, alicePrivateKey); + + ECPublicKey bobPublicKey = Curve.decodePoint(bobPublic, 0); + RootKey rootKey = new RootKey(rootKeySeed); + + Pair rootKeyChainKeyPair = rootKey.createChain(bobPublicKey, aliceKeyPair); + RootKey nextRootKey = rootKeyChainKeyPair.first(); + ChainKey nextChainKey = rootKeyChainKeyPair.second(); + + assertTrue(Arrays.equals(rootKey.getKeyBytes(), rootKeySeed)); + assertTrue(Arrays.equals(nextRootKey.getKeyBytes(), nextRoot)); + assertTrue(Arrays.equals(nextChainKey.getKey(), nextChain)); + } +} diff --git a/libaxolotl/src/main/AndroidManifest.xml b/libaxolotl/src/main/AndroidManifest.xml new file mode 100644 index 000000000..28d281688 --- /dev/null +++ b/libaxolotl/src/main/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/library/src/org/whispersystems/textsecure/crypto/DuplicateMessageException.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/DuplicateMessageException.java similarity index 73% rename from library/src/org/whispersystems/textsecure/crypto/DuplicateMessageException.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/DuplicateMessageException.java index 0d795f3fc..913c01212 100644 --- a/library/src/org/whispersystems/textsecure/crypto/DuplicateMessageException.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/DuplicateMessageException.java @@ -1,4 +1,4 @@ -package org.whispersystems.textsecure.crypto; +package org.whispersystems.libaxolotl; public class DuplicateMessageException extends Exception { public DuplicateMessageException(String s) { diff --git a/libaxolotl/src/main/java/org/whispersystems/libaxolotl/IdentityKey.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/IdentityKey.java new file mode 100644 index 000000000..35af3394a --- /dev/null +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/IdentityKey.java @@ -0,0 +1,66 @@ +/** + * Copyright (C) 2014 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.whispersystems.libaxolotl; + + +import org.whispersystems.libaxolotl.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; +import org.whispersystems.libaxolotl.util.Hex; + +/** + * A class for representing an identity key. + * + * @author Moxie Marlinspike + */ + +public class IdentityKey { + + private final ECPublicKey publicKey; + + public IdentityKey(ECPublicKey publicKey) { + this.publicKey = publicKey; + } + + public IdentityKey(byte[] bytes, int offset) throws InvalidKeyException { + this.publicKey = Curve.decodePoint(bytes, offset); + } + + public ECPublicKey getPublicKey() { + return publicKey; + } + + public byte[] serialize() { + return publicKey.serialize(); + } + + public String getFingerprint() { + return Hex.toString(publicKey.serialize()); + } + + @Override + public boolean equals(Object other) { + if (other == null) return false; + if (!(other instanceof IdentityKey)) return false; + + return publicKey.equals(((IdentityKey) other).getPublicKey()); + } + + @Override + public int hashCode() { + return publicKey.hashCode(); + } +} diff --git a/library/src/org/whispersystems/textsecure/crypto/IdentityKeyPair.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/IdentityKeyPair.java similarity index 91% rename from library/src/org/whispersystems/textsecure/crypto/IdentityKeyPair.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/IdentityKeyPair.java index 390fbe208..220be57a6 100644 --- a/library/src/org/whispersystems/textsecure/crypto/IdentityKeyPair.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/IdentityKeyPair.java @@ -14,9 +14,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package org.whispersystems.textsecure.crypto; +package org.whispersystems.libaxolotl; -import org.whispersystems.textsecure.crypto.ecc.ECPrivateKey; +import org.whispersystems.libaxolotl.ecc.ECPrivateKey; /** * Holder for public and private identity key pair. diff --git a/library/src/org/whispersystems/textsecure/crypto/InvalidKeyException.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/InvalidKeyException.java similarity index 76% rename from library/src/org/whispersystems/textsecure/crypto/InvalidKeyException.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/InvalidKeyException.java index 144021dc1..bb70df168 100644 --- a/library/src/org/whispersystems/textsecure/crypto/InvalidKeyException.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/InvalidKeyException.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2011 Whisper Systems + * Copyright (C) 2014 Open Whisper Systems * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -14,27 +14,21 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package org.whispersystems.textsecure.crypto; +package org.whispersystems.libaxolotl; public class InvalidKeyException extends Exception { - public InvalidKeyException() { - // TODO Auto-generated constructor stub - } + public InvalidKeyException() {} public InvalidKeyException(String detailMessage) { super(detailMessage); - // TODO Auto-generated constructor stub } public InvalidKeyException(Throwable throwable) { super(throwable); - // TODO Auto-generated constructor stub } public InvalidKeyException(String detailMessage, Throwable throwable) { super(detailMessage, throwable); - // TODO Auto-generated constructor stub } - } diff --git a/library/src/org/whispersystems/textsecure/crypto/InvalidMacException.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/InvalidMacException.java similarity index 67% rename from library/src/org/whispersystems/textsecure/crypto/InvalidMacException.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/InvalidMacException.java index f886ddaa9..0afc6996e 100644 --- a/library/src/org/whispersystems/textsecure/crypto/InvalidMacException.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/InvalidMacException.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2011 Whisper Systems + * Copyright (C) 2014 Open Whisper Systems * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -14,27 +14,15 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package org.whispersystems.textsecure.crypto; +package org.whispersystems.libaxolotl; public class InvalidMacException extends Exception { - public InvalidMacException() { - // TODO Auto-generated constructor stub - } - public InvalidMacException(String detailMessage) { super(detailMessage); - // TODO Auto-generated constructor stub } public InvalidMacException(Throwable throwable) { super(throwable); - // TODO Auto-generated constructor stub } - - public InvalidMacException(String detailMessage, Throwable throwable) { - super(detailMessage, throwable); - // TODO Auto-generated constructor stub - } - } diff --git a/library/src/org/whispersystems/textsecure/crypto/InvalidMessageException.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/InvalidMessageException.java similarity index 77% rename from library/src/org/whispersystems/textsecure/crypto/InvalidMessageException.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/InvalidMessageException.java index a978d6020..063eb594a 100644 --- a/library/src/org/whispersystems/textsecure/crypto/InvalidMessageException.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/InvalidMessageException.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2011 Whisper Systems + * Copyright (C) 2014 Open Whisper Systems * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -14,27 +14,27 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package org.whispersystems.textsecure.crypto; +package org.whispersystems.libaxolotl; + +import java.util.List; public class InvalidMessageException extends Exception { - public InvalidMessageException() { - // TODO Auto-generated constructor stub - } + public InvalidMessageException() {} public InvalidMessageException(String detailMessage) { super(detailMessage); - // TODO Auto-generated constructor stub } public InvalidMessageException(Throwable throwable) { super(throwable); - // TODO Auto-generated constructor stub } public InvalidMessageException(String detailMessage, Throwable throwable) { super(detailMessage, throwable); - // TODO Auto-generated constructor stub } + public InvalidMessageException(String detailMessage, List exceptions) { + super(detailMessage, exceptions.get(0)); + } } diff --git a/library/src/org/whispersystems/textsecure/crypto/SerializableKey.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/InvalidVersionException.java similarity index 73% rename from library/src/org/whispersystems/textsecure/crypto/SerializableKey.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/InvalidVersionException.java index 4799be688..a13244436 100644 --- a/library/src/org/whispersystems/textsecure/crypto/SerializableKey.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/InvalidVersionException.java @@ -1,6 +1,6 @@ -/** - * Copyright (C) 2011 Whisper Systems - * +/** + * Copyright (C) 2014 Open Whisper Systems + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -10,12 +10,14 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package org.whispersystems.textsecure.crypto; +package org.whispersystems.libaxolotl; -public interface SerializableKey { - public byte[] serialize(); +public class InvalidVersionException extends Exception { + public InvalidVersionException(String detailMessage) { + super(detailMessage); + } } diff --git a/library/src/org/whispersystems/textsecure/crypto/LegacyMessageException.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/LegacyMessageException.java similarity index 72% rename from library/src/org/whispersystems/textsecure/crypto/LegacyMessageException.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/LegacyMessageException.java index c396e04d1..dadde7540 100644 --- a/library/src/org/whispersystems/textsecure/crypto/LegacyMessageException.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/LegacyMessageException.java @@ -1,4 +1,4 @@ -package org.whispersystems.textsecure.crypto; +package org.whispersystems.libaxolotl; public class LegacyMessageException extends Exception { public LegacyMessageException(String s) { diff --git a/library/src/org/whispersystems/textsecure/crypto/SessionCipher.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/SessionCipher.java similarity index 69% rename from library/src/org/whispersystems/textsecure/crypto/SessionCipher.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/SessionCipher.java index bf861339a..7b8907a53 100644 --- a/library/src/org/whispersystems/textsecure/crypto/SessionCipher.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/SessionCipher.java @@ -14,29 +14,23 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package org.whispersystems.textsecure.crypto; +package org.whispersystems.libaxolotl; - -import android.content.Context; -import android.util.Log; -import android.util.Pair; - -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECKeyPair; -import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; -import org.whispersystems.textsecure.crypto.protocol.CiphertextMessage; -import org.whispersystems.textsecure.crypto.protocol.PreKeyWhisperMessage; -import org.whispersystems.textsecure.crypto.protocol.WhisperMessage; -import org.whispersystems.textsecure.crypto.ratchet.ChainKey; -import org.whispersystems.textsecure.crypto.ratchet.MessageKeys; -import org.whispersystems.textsecure.crypto.ratchet.RootKey; -import org.whispersystems.textsecure.storage.RecipientDevice; -import org.whispersystems.textsecure.storage.SessionRecordV2; -import org.whispersystems.textsecure.storage.SessionState; -import org.whispersystems.textsecure.util.Conversions; +import org.whispersystems.libaxolotl.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECKeyPair; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; +import org.whispersystems.libaxolotl.protocol.CiphertextMessage; +import org.whispersystems.libaxolotl.protocol.PreKeyWhisperMessage; +import org.whispersystems.libaxolotl.protocol.WhisperMessage; +import org.whispersystems.libaxolotl.ratchet.ChainKey; +import org.whispersystems.libaxolotl.ratchet.MessageKeys; +import org.whispersystems.libaxolotl.ratchet.RootKey; +import org.whispersystems.libaxolotl.util.ByteUtil; +import org.whispersystems.libaxolotl.util.Pair; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; +import java.util.LinkedList; import java.util.List; import javax.crypto.BadPaddingException; @@ -50,36 +44,19 @@ public class SessionCipher { private static final Object SESSION_LOCK = new Object(); - private final Context context; - private final MasterSecret masterSecret; - private final RecipientDevice recipient; + private final SessionStore sessionStore; - public static SessionCipher createFor(Context context, - MasterSecret masterSecret, - RecipientDevice recipient) - { - if (SessionRecordV2.hasSession(context, masterSecret, recipient)) { - return new SessionCipher(context, masterSecret, recipient); - } else { - throw new AssertionError("Attempt to initialize cipher for non-existing session."); - } - } - - - private SessionCipher(Context context, MasterSecret masterSecret, RecipientDevice recipient) { - this.recipient = recipient; - this.masterSecret = masterSecret; - this.context = context; + public SessionCipher(SessionStore sessionStore) { + this.sessionStore = sessionStore; } public CiphertextMessage encrypt(byte[] paddedMessage) { synchronized (SESSION_LOCK) { - SessionRecordV2 sessionRecord = getSessionRecord(); - SessionState sessionState = sessionRecord.getSessionState(); - ChainKey chainKey = sessionState.getSenderChainKey(); - MessageKeys messageKeys = chainKey.getMessageKeys(); - ECPublicKey senderEphemeral = sessionState.getSenderEphemeral(); - int previousCounter = sessionState.getPreviousCounter(); + SessionState sessionState = sessionStore.getSessionState(); + ChainKey chainKey = sessionState.getSenderChainKey(); + MessageKeys messageKeys = chainKey.getMessageKeys(); + ECPublicKey senderEphemeral = sessionState.getSenderEphemeral(); + int previousCounter = sessionState.getPreviousCounter(); byte[] ciphertextBody = getCiphertext(messageKeys, paddedMessage); CiphertextMessage ciphertextMessage = new WhisperMessage(messageKeys.getMacKey(), @@ -90,15 +67,14 @@ public class SessionCipher { Pair pendingPreKey = sessionState.getPendingPreKey(); int localRegistrationId = sessionState.getLocalRegistrationId(); - ciphertextMessage = new PreKeyWhisperMessage(localRegistrationId, pendingPreKey.first, - pendingPreKey.second, + ciphertextMessage = new PreKeyWhisperMessage(localRegistrationId, pendingPreKey.first(), + pendingPreKey.second(), sessionState.getLocalIdentityKey(), (WhisperMessage) ciphertextMessage); } sessionState.setSenderChainKey(chainKey.getNextChainKey()); - sessionRecord.save(); - + sessionStore.save(); return ciphertextMessage; } } @@ -107,32 +83,31 @@ public class SessionCipher { throws InvalidMessageException, DuplicateMessageException, LegacyMessageException { synchronized (SESSION_LOCK) { - SessionRecordV2 sessionRecord = getSessionRecord(); - SessionState sessionState = sessionRecord.getSessionState(); - List previousStates = sessionRecord.getPreviousSessions(); + SessionState sessionState = sessionStore.getSessionState(); + List previousStates = sessionStore.getPreviousSessionStates(); + List exceptions = new LinkedList(); try { byte[] plaintext = decrypt(sessionState, decodedMessage); - sessionRecord.save(); + sessionStore.save(); return plaintext; } catch (InvalidMessageException e) { - Log.w("SessionCipherV2", e); + exceptions.add(e); } for (SessionState previousState : previousStates) { try { - Log.w("SessionCipherV2", "Attempting decrypt on previous state..."); byte[] plaintext = decrypt(previousState, decodedMessage); - sessionRecord.save(); + sessionStore.save(); return plaintext; } catch (InvalidMessageException e) { - Log.w("SessionCipherV2", e); + exceptions.add(e); } } - throw new InvalidMessageException("No valid sessions."); + throw new InvalidMessageException("No valid sessions.", exceptions); } } @@ -162,8 +137,7 @@ public class SessionCipher { public int getRemoteRegistrationId() { synchronized (SESSION_LOCK) { - SessionRecordV2 sessionRecord = getSessionRecord(); - return sessionRecord.getSessionState().getRemoteRegistrationId(); + return sessionStore.getSessionState().getRemoteRegistrationId(); } } @@ -174,18 +148,18 @@ public class SessionCipher { if (sessionState.hasReceiverChain(theirEphemeral)) { return sessionState.getReceiverChainKey(theirEphemeral); } else { - RootKey rootKey = sessionState.getRootKey(); - ECKeyPair ourEphemeral = sessionState.getSenderEphemeralPair(); + RootKey rootKey = sessionState.getRootKey(); + ECKeyPair ourEphemeral = sessionState.getSenderEphemeralPair(); Pair receiverChain = rootKey.createChain(theirEphemeral, ourEphemeral); ECKeyPair ourNewEphemeral = Curve.generateKeyPair(true); - Pair senderChain = receiverChain.first.createChain(theirEphemeral, ourNewEphemeral); + Pair senderChain = receiverChain.first().createChain(theirEphemeral, ourNewEphemeral); - sessionState.setRootKey(senderChain.first); - sessionState.addReceiverChain(theirEphemeral, receiverChain.second); + sessionState.setRootKey(senderChain.first()); + sessionState.addReceiverChain(theirEphemeral, receiverChain.second()); sessionState.setPreviousCounter(sessionState.getSenderChainKey().getIndex()-1); - sessionState.setSenderChain(ourNewEphemeral, senderChain.second); + sessionState.setSenderChain(ourNewEphemeral, senderChain.second()); - return receiverChain.second; + return receiverChain.second(); } } catch (InvalidKeyException e) { throw new InvalidMessageException(e); @@ -252,7 +226,7 @@ public class SessionCipher { Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding"); byte[] ivBytes = new byte[16]; - Conversions.intToByteArray(ivBytes, 0, counter); + ByteUtil.intToByteArray(ivBytes, 0, counter); IvParameterSpec iv = new IvParameterSpec(ivBytes); cipher.init(mode, key, iv); @@ -268,8 +242,4 @@ public class SessionCipher { throw new AssertionError(e); } } - - private SessionRecordV2 getSessionRecord() { - return new SessionRecordV2(context, masterSecret, recipient); - } } \ No newline at end of file diff --git a/libaxolotl/src/main/java/org/whispersystems/libaxolotl/SessionState.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/SessionState.java new file mode 100644 index 000000000..60deab98a --- /dev/null +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/SessionState.java @@ -0,0 +1,54 @@ +package org.whispersystems.libaxolotl; + +import org.whispersystems.libaxolotl.ecc.ECKeyPair; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; +import org.whispersystems.libaxolotl.ratchet.ChainKey; +import org.whispersystems.libaxolotl.ratchet.MessageKeys; +import org.whispersystems.libaxolotl.ratchet.RootKey; +import org.whispersystems.libaxolotl.util.Pair; + +public interface SessionState { + public void setNeedsRefresh(boolean needsRefresh); + public boolean getNeedsRefresh(); + public void setSessionVersion(int version); + public int getSessionVersion(); + public void setRemoteIdentityKey(IdentityKey identityKey); + public void setLocalIdentityKey(IdentityKey identityKey); + public IdentityKey getRemoteIdentityKey(); + public IdentityKey getLocalIdentityKey(); + public int getPreviousCounter(); + public void setPreviousCounter(int previousCounter); + public RootKey getRootKey(); + public void setRootKey(RootKey rootKey); + public ECPublicKey getSenderEphemeral(); + public ECKeyPair getSenderEphemeralPair(); + public boolean hasReceiverChain(ECPublicKey senderEphemeral); + public boolean hasSenderChain(); + public ChainKey getReceiverChainKey(ECPublicKey senderEphemeral); + public void addReceiverChain(ECPublicKey senderEphemeral, ChainKey chainKey); + public void setSenderChain(ECKeyPair senderEphemeralPair, ChainKey chainKey); + public ChainKey getSenderChainKey(); + public void setSenderChainKey(ChainKey nextChainKey); + public boolean hasMessageKeys(ECPublicKey senderEphemeral, int counter); + public MessageKeys removeMessageKeys(ECPublicKey senderEphemeral, int counter); + public void setMessageKeys(ECPublicKey senderEphemeral, MessageKeys messageKeys); + public void setReceiverChainKey(ECPublicKey senderEphemeral, ChainKey chainKey); + public void setPendingKeyExchange(int sequence, + ECKeyPair ourBaseKey, + ECKeyPair ourEphemeralKey, + IdentityKeyPair ourIdentityKey); + public int getPendingKeyExchangeSequence(); + public ECKeyPair getPendingKeyExchangeBaseKey() throws InvalidKeyException; + public ECKeyPair getPendingKeyExchangeEphemeralKey() throws InvalidKeyException; + public IdentityKeyPair getPendingKeyExchangeIdentityKey() throws InvalidKeyException; + public boolean hasPendingKeyExchange(); + public void setPendingPreKey(int preKeyId, ECPublicKey baseKey); + public boolean hasPendingPreKey(); + public Pair getPendingPreKey(); + public void clearPendingPreKey(); + public void setRemoteRegistrationId(int registrationId); + public int getRemoteRegistrationId(); + public void setLocalRegistrationId(int registrationId); + public int getLocalRegistrationId(); + public byte[] serialize(); +} diff --git a/libaxolotl/src/main/java/org/whispersystems/libaxolotl/SessionStore.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/SessionStore.java new file mode 100644 index 000000000..123ae449c --- /dev/null +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/SessionStore.java @@ -0,0 +1,12 @@ +package org.whispersystems.libaxolotl; + +import java.util.List; + +public interface SessionStore { + + public SessionState getSessionState(); + public List getPreviousSessionStates(); + public void save(); + + +} diff --git a/library/src/org/whispersystems/textsecure/crypto/ecc/Curve.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/Curve.java similarity index 90% rename from library/src/org/whispersystems/textsecure/crypto/ecc/Curve.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/Curve.java index 5ae56716e..c69c3b826 100644 --- a/library/src/org/whispersystems/textsecure/crypto/ecc/Curve.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/Curve.java @@ -14,10 +14,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package org.whispersystems.textsecure.crypto.ecc; +package org.whispersystems.libaxolotl.ecc; -import org.whispersystems.textsecure.crypto.InvalidKeyException; -import org.whispersystems.textsecure.crypto.protocol.CiphertextMessage; +import org.whispersystems.libaxolotl.InvalidKeyException; public class Curve { diff --git a/library/src/org/whispersystems/textsecure/crypto/ecc/Curve25519.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/Curve25519.java similarity index 95% rename from library/src/org/whispersystems/textsecure/crypto/ecc/Curve25519.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/Curve25519.java index 94bd71b67..fdefab570 100644 --- a/library/src/org/whispersystems/textsecure/crypto/ecc/Curve25519.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/Curve25519.java @@ -14,9 +14,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package org.whispersystems.textsecure.crypto.ecc; +package org.whispersystems.libaxolotl.ecc; -import org.whispersystems.textsecure.crypto.InvalidKeyException; +import org.whispersystems.libaxolotl.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; diff --git a/library/src/org/whispersystems/textsecure/crypto/ecc/DjbECPrivateKey.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/DjbECPrivateKey.java similarity index 95% rename from library/src/org/whispersystems/textsecure/crypto/ecc/DjbECPrivateKey.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/DjbECPrivateKey.java index fbf37a223..ecb55b4ee 100644 --- a/library/src/org/whispersystems/textsecure/crypto/ecc/DjbECPrivateKey.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/DjbECPrivateKey.java @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package org.whispersystems.textsecure.crypto.ecc; +package org.whispersystems.libaxolotl.ecc; public class DjbECPrivateKey implements ECPrivateKey { diff --git a/library/src/org/whispersystems/textsecure/crypto/ecc/DjbECPublicKey.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/DjbECPublicKey.java similarity index 92% rename from library/src/org/whispersystems/textsecure/crypto/ecc/DjbECPublicKey.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/DjbECPublicKey.java index bd6020741..9f66d4393 100644 --- a/library/src/org/whispersystems/textsecure/crypto/ecc/DjbECPublicKey.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/DjbECPublicKey.java @@ -15,9 +15,9 @@ * along with this program. If not, see . */ -package org.whispersystems.textsecure.crypto.ecc; +package org.whispersystems.libaxolotl.ecc; -import org.whispersystems.textsecure.util.Util; +import org.whispersystems.libaxolotl.util.ByteUtil; import java.math.BigInteger; import java.util.Arrays; @@ -33,7 +33,7 @@ public class DjbECPublicKey implements ECPublicKey { @Override public byte[] serialize() { byte[] type = {Curve.DJB_TYPE}; - return Util.combine(type, publicKey); + return ByteUtil.combine(type, publicKey); } @Override diff --git a/library/src/org/whispersystems/textsecure/crypto/ecc/ECKeyPair.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/ECKeyPair.java similarity index 95% rename from library/src/org/whispersystems/textsecure/crypto/ecc/ECKeyPair.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/ECKeyPair.java index a592080ea..bcaec927d 100644 --- a/library/src/org/whispersystems/textsecure/crypto/ecc/ECKeyPair.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/ECKeyPair.java @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package org.whispersystems.textsecure.crypto.ecc; +package org.whispersystems.libaxolotl.ecc; public class ECKeyPair { diff --git a/library/src/org/whispersystems/textsecure/crypto/ecc/ECPrivateKey.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/ECPrivateKey.java similarity index 94% rename from library/src/org/whispersystems/textsecure/crypto/ecc/ECPrivateKey.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/ECPrivateKey.java index 4892d0e65..922057de7 100644 --- a/library/src/org/whispersystems/textsecure/crypto/ecc/ECPrivateKey.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/ECPrivateKey.java @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package org.whispersystems.textsecure.crypto.ecc; +package org.whispersystems.libaxolotl.ecc; public interface ECPrivateKey { public byte[] serialize(); diff --git a/library/src/org/whispersystems/textsecure/crypto/ecc/ECPublicKey.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/ECPublicKey.java similarity index 94% rename from library/src/org/whispersystems/textsecure/crypto/ecc/ECPublicKey.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/ECPublicKey.java index 42a9ce86d..125768073 100644 --- a/library/src/org/whispersystems/textsecure/crypto/ecc/ECPublicKey.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/ECPublicKey.java @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package org.whispersystems.textsecure.crypto.ecc; +package org.whispersystems.libaxolotl.ecc; public interface ECPublicKey extends Comparable { diff --git a/library/src/org/whispersystems/textsecure/crypto/kdf/DerivedSecrets.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/kdf/DerivedSecrets.java similarity index 95% rename from library/src/org/whispersystems/textsecure/crypto/kdf/DerivedSecrets.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/kdf/DerivedSecrets.java index 294b1b27c..93786947e 100644 --- a/library/src/org/whispersystems/textsecure/crypto/kdf/DerivedSecrets.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/kdf/DerivedSecrets.java @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package org.whispersystems.textsecure.crypto.kdf; +package org.whispersystems.libaxolotl.kdf; import javax.crypto.spec.SecretKeySpec; diff --git a/library/src/org/whispersystems/textsecure/crypto/kdf/HKDF.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/kdf/HKDF.java similarity index 97% rename from library/src/org/whispersystems/textsecure/crypto/kdf/HKDF.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/kdf/HKDF.java index cbad84e54..2370efdd4 100644 --- a/library/src/org/whispersystems/textsecure/crypto/kdf/HKDF.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/kdf/HKDF.java @@ -15,13 +15,11 @@ * along with this program. If not, see . */ -package org.whispersystems.textsecure.crypto.kdf; +package org.whispersystems.libaxolotl.kdf; import java.io.ByteArrayOutputStream; -import java.math.BigInteger; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; -import java.util.List; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; diff --git a/libaxolotl/src/main/java/org/whispersystems/libaxolotl/protocol/CiphertextMessage.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/protocol/CiphertextMessage.java new file mode 100644 index 000000000..b3213126b --- /dev/null +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/protocol/CiphertextMessage.java @@ -0,0 +1,33 @@ +/** + * Copyright (C) 2014 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.whispersystems.libaxolotl.protocol; + +public interface CiphertextMessage { + + public static final int UNSUPPORTED_VERSION = 1; + public static final int CURRENT_VERSION = 2; + + public static final int WHISPER_TYPE = 2; + public static final int PREKEY_TYPE = 3; + + // This should be the worst case (worse than V2). So not always accurate, but good enough for padding. + public static final int ENCRYPTED_MESSAGE_OVERHEAD = 53; + + public byte[] serialize(); + public int getType(); + +} \ No newline at end of file diff --git a/library/src/org/whispersystems/textsecure/crypto/protocol/PreKeyWhisperMessage.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/protocol/PreKeyWhisperMessage.java similarity index 71% rename from library/src/org/whispersystems/textsecure/crypto/protocol/PreKeyWhisperMessage.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/protocol/PreKeyWhisperMessage.java index 5845dc044..801babf53 100644 --- a/library/src/org/whispersystems/textsecure/crypto/protocol/PreKeyWhisperMessage.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/protocol/PreKeyWhisperMessage.java @@ -1,17 +1,33 @@ -package org.whispersystems.textsecure.crypto.protocol; +/** + * Copyright (C) 2014 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.whispersystems.libaxolotl.protocol; import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; -import org.whispersystems.textsecure.crypto.IdentityKey; -import org.whispersystems.textsecure.crypto.InvalidKeyException; -import org.whispersystems.textsecure.crypto.InvalidMessageException; -import org.whispersystems.textsecure.crypto.InvalidVersionException; -import org.whispersystems.textsecure.crypto.LegacyMessageException; -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; -import org.whispersystems.textsecure.util.Conversions; -import org.whispersystems.textsecure.util.Util; +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.InvalidMessageException; +import org.whispersystems.libaxolotl.InvalidVersionException; +import org.whispersystems.libaxolotl.LegacyMessageException; +import org.whispersystems.libaxolotl.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; +import org.whispersystems.libaxolotl.util.ByteUtil; + public class PreKeyWhisperMessage implements CiphertextMessage { @@ -27,7 +43,7 @@ public class PreKeyWhisperMessage implements CiphertextMessage { throws InvalidMessageException, InvalidVersionException { try { - this.version = Conversions.highBitsToInt(serialized[0]); + this.version = ByteUtil.highBitsToInt(serialized[0]); if (this.version > CiphertextMessage.CURRENT_VERSION) { throw new InvalidVersionException("Unknown version: " + this.version); @@ -70,7 +86,7 @@ public class PreKeyWhisperMessage implements CiphertextMessage { this.identityKey = identityKey; this.message = message; - byte[] versionBytes = {Conversions.intsToByteHighAndLow(CURRENT_VERSION, this.version)}; + byte[] versionBytes = {ByteUtil.intsToByteHighAndLow(CURRENT_VERSION, this.version)}; byte[] messageBytes = WhisperProtos.PreKeyWhisperMessage.newBuilder() .setPreKeyId(preKeyId) .setBaseKey(ByteString.copyFrom(baseKey.serialize())) @@ -79,7 +95,7 @@ public class PreKeyWhisperMessage implements CiphertextMessage { .setRegistrationId(registrationId) .build().toByteArray(); - this.serialized = Util.combine(versionBytes, messageBytes); + this.serialized = ByteUtil.combine(versionBytes, messageBytes); } public IdentityKey getIdentityKey() { diff --git a/library/src/org/whispersystems/textsecure/crypto/protocol/WhisperMessage.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/protocol/WhisperMessage.java similarity index 65% rename from library/src/org/whispersystems/textsecure/crypto/protocol/WhisperMessage.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/protocol/WhisperMessage.java index 534397ac8..53a9629c8 100644 --- a/library/src/org/whispersystems/textsecure/crypto/protocol/WhisperMessage.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/protocol/WhisperMessage.java @@ -1,15 +1,30 @@ -package org.whispersystems.textsecure.crypto.protocol; +/** + * Copyright (C) 2014 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.whispersystems.libaxolotl.protocol; import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; -import org.whispersystems.textsecure.crypto.InvalidKeyException; -import org.whispersystems.textsecure.crypto.InvalidMessageException; -import org.whispersystems.textsecure.crypto.LegacyMessageException; -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; -import org.whispersystems.textsecure.util.Conversions; -import org.whispersystems.textsecure.util.Util; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.InvalidMessageException; +import org.whispersystems.libaxolotl.LegacyMessageException; +import org.whispersystems.libaxolotl.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; +import org.whispersystems.libaxolotl.util.ByteUtil; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -30,17 +45,17 @@ public class WhisperMessage implements CiphertextMessage { public WhisperMessage(byte[] serialized) throws InvalidMessageException, LegacyMessageException { try { - byte[][] messageParts = Util.split(serialized, 1, serialized.length - 1 - MAC_LENGTH, MAC_LENGTH); + byte[][] messageParts = ByteUtil.split(serialized, 1, serialized.length - 1 - MAC_LENGTH, MAC_LENGTH); byte version = messageParts[0][0]; byte[] message = messageParts[1]; byte[] mac = messageParts[2]; - if (Conversions.highBitsToInt(version) <= CiphertextMessage.UNSUPPORTED_VERSION) { - throw new LegacyMessageException("Legacy message: " + Conversions.highBitsToInt(version)); + if (ByteUtil.highBitsToInt(version) <= CiphertextMessage.UNSUPPORTED_VERSION) { + throw new LegacyMessageException("Legacy message: " + ByteUtil.highBitsToInt(version)); } - if (Conversions.highBitsToInt(version) != CURRENT_VERSION) { - throw new InvalidMessageException("Unknown version: " + Conversions.highBitsToInt(version)); + if (ByteUtil.highBitsToInt(version) != CURRENT_VERSION) { + throw new InvalidMessageException("Unknown version: " + ByteUtil.highBitsToInt(version)); } WhisperProtos.WhisperMessage whisperMessage = WhisperProtos.WhisperMessage.parseFrom(message); @@ -69,16 +84,16 @@ public class WhisperMessage implements CiphertextMessage { public WhisperMessage(SecretKeySpec macKey, ECPublicKey senderEphemeral, int counter, int previousCounter, byte[] ciphertext) { - byte[] version = {Conversions.intsToByteHighAndLow(CURRENT_VERSION, CURRENT_VERSION)}; + byte[] version = {ByteUtil.intsToByteHighAndLow(CURRENT_VERSION, CURRENT_VERSION)}; byte[] message = WhisperProtos.WhisperMessage.newBuilder() .setEphemeralKey(ByteString.copyFrom(senderEphemeral.serialize())) .setCounter(counter) .setPreviousCounter(previousCounter) .setCiphertext(ByteString.copyFrom(ciphertext)) .build().toByteArray(); - byte[] mac = getMac(macKey, Util.combine(version, message)); + byte[] mac = getMac(macKey, ByteUtil.combine(version, message)); - this.serialized = Util.combine(version, message, mac); + this.serialized = ByteUtil.combine(version, message, mac); this.senderEphemeral = senderEphemeral; this.counter = counter; this.previousCounter = previousCounter; @@ -100,7 +115,7 @@ public class WhisperMessage implements CiphertextMessage { public void verifyMac(SecretKeySpec macKey) throws InvalidMessageException { - byte[][] parts = Util.split(serialized, serialized.length - MAC_LENGTH, MAC_LENGTH); + byte[][] parts = ByteUtil.split(serialized, serialized.length - MAC_LENGTH, MAC_LENGTH); byte[] ourMac = getMac(macKey, parts[0]); byte[] theirMac = parts[1]; @@ -115,7 +130,7 @@ public class WhisperMessage implements CiphertextMessage { mac.init(macKey); byte[] fullMac = mac.doFinal(serialized); - return Util.trim(fullMac, MAC_LENGTH); + return ByteUtil.trim(fullMac, MAC_LENGTH); } catch (NoSuchAlgorithmException e) { throw new AssertionError(e); } catch (java.security.InvalidKeyException e) { @@ -135,7 +150,7 @@ public class WhisperMessage implements CiphertextMessage { public static boolean isLegacy(byte[] message) { return message != null && message.length >= 1 && - Conversions.highBitsToInt(message[0]) <= CiphertextMessage.UNSUPPORTED_VERSION; + ByteUtil.highBitsToInt(message[0]) <= CiphertextMessage.UNSUPPORTED_VERSION; } } diff --git a/library/src/org/whispersystems/textsecure/crypto/protocol/WhisperProtos.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/protocol/WhisperProtos.java similarity index 82% rename from library/src/org/whispersystems/textsecure/crypto/protocol/WhisperProtos.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/protocol/WhisperProtos.java index 4af21a369..f971faddc 100644 --- a/library/src/org/whispersystems/textsecure/crypto/protocol/WhisperProtos.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/protocol/WhisperProtos.java @@ -1,7 +1,7 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! // source: WhisperTextProtocol.proto -package org.whispersystems.textsecure.crypto.protocol; +package org.whispersystems.libaxolotl.protocol; public final class WhisperProtos { private WhisperProtos() {} @@ -47,12 +47,12 @@ public final class WhisperProtos { public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_WhisperMessage_descriptor; + return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_WhisperMessage_descriptor; } protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_WhisperMessage_fieldAccessorTable; + return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_WhisperMessage_fieldAccessorTable; } private int bitField0_; @@ -163,41 +163,41 @@ public final class WhisperProtos { return super.writeReplace(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage parseFrom( com.google.protobuf.ByteString data) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data).buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage parseFrom( com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data, extensionRegistry) .buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseFrom(byte[] data) + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data).buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage parseFrom( byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data, extensionRegistry) .buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseFrom(java.io.InputStream input) + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage parseFrom(java.io.InputStream input) throws java.io.IOException { return newBuilder().mergeFrom(input).buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage parseFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return newBuilder().mergeFrom(input, extensionRegistry) .buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseDelimitedFrom(java.io.InputStream input) + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException { Builder builder = newBuilder(); if (builder.mergeDelimitedFrom(input)) { @@ -206,7 +206,7 @@ public final class WhisperProtos { return null; } } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseDelimitedFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage parseDelimitedFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { @@ -217,12 +217,12 @@ public final class WhisperProtos { return null; } } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage parseFrom( com.google.protobuf.CodedInputStream input) throws java.io.IOException { return newBuilder().mergeFrom(input).buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage parseFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { @@ -232,7 +232,7 @@ public final class WhisperProtos { public static Builder newBuilder() { return Builder.create(); } public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder(org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage prototype) { + public static Builder newBuilder(org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage prototype) { return newBuilder().mergeFrom(prototype); } public Builder toBuilder() { return newBuilder(this); } @@ -245,18 +245,18 @@ public final class WhisperProtos { } public static final class Builder extends com.google.protobuf.GeneratedMessage.Builder - implements org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessageOrBuilder { + implements org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessageOrBuilder { public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_WhisperMessage_descriptor; + return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_WhisperMessage_descriptor; } protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_WhisperMessage_fieldAccessorTable; + return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_WhisperMessage_fieldAccessorTable; } - // Construct using org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage.newBuilder() + // Construct using org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage.newBuilder() private Builder() { maybeForceBuilderInitialization(); } @@ -292,24 +292,24 @@ public final class WhisperProtos { public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage.getDescriptor(); + return org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage.getDescriptor(); } - public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage getDefaultInstanceForType() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage.getDefaultInstance(); + public org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage getDefaultInstanceForType() { + return org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage.getDefaultInstance(); } - public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage build() { - org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage result = buildPartial(); + public org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage build() { + org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException(result); } return result; } - private org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage buildParsed() + private org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage buildParsed() throws com.google.protobuf.InvalidProtocolBufferException { - org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage result = buildPartial(); + org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException( result).asInvalidProtocolBufferException(); @@ -317,8 +317,8 @@ public final class WhisperProtos { return result; } - public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage buildPartial() { - org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage result = new org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage(this); + public org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage buildPartial() { + org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage result = new org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage(this); int from_bitField0_ = bitField0_; int to_bitField0_ = 0; if (((from_bitField0_ & 0x00000001) == 0x00000001)) { @@ -343,16 +343,16 @@ public final class WhisperProtos { } public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage) { - return mergeFrom((org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage)other); + if (other instanceof org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage) { + return mergeFrom((org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage)other); } else { super.mergeFrom(other); return this; } } - public Builder mergeFrom(org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage other) { - if (other == org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage.getDefaultInstance()) return this; + public Builder mergeFrom(org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage other) { + if (other == org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage.getDefaultInstance()) return this; if (other.hasEphemeralKey()) { setEphemeralKey(other.getEphemeralKey()); } @@ -566,12 +566,12 @@ public final class WhisperProtos { public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_PreKeyWhisperMessage_descriptor; + return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_PreKeyWhisperMessage_descriptor; } protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_PreKeyWhisperMessage_fieldAccessorTable; + return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_PreKeyWhisperMessage_fieldAccessorTable; } private int bitField0_; @@ -700,41 +700,41 @@ public final class WhisperProtos { return super.writeReplace(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom( com.google.protobuf.ByteString data) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data).buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom( com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data, extensionRegistry) .buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom(byte[] data) + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data).buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom( byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data, extensionRegistry) .buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom(java.io.InputStream input) + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom(java.io.InputStream input) throws java.io.IOException { return newBuilder().mergeFrom(input).buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return newBuilder().mergeFrom(input, extensionRegistry) .buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseDelimitedFrom(java.io.InputStream input) + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException { Builder builder = newBuilder(); if (builder.mergeDelimitedFrom(input)) { @@ -743,7 +743,7 @@ public final class WhisperProtos { return null; } } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseDelimitedFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage parseDelimitedFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { @@ -754,12 +754,12 @@ public final class WhisperProtos { return null; } } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom( com.google.protobuf.CodedInputStream input) throws java.io.IOException { return newBuilder().mergeFrom(input).buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { @@ -769,7 +769,7 @@ public final class WhisperProtos { public static Builder newBuilder() { return Builder.create(); } public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder(org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage prototype) { + public static Builder newBuilder(org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage prototype) { return newBuilder().mergeFrom(prototype); } public Builder toBuilder() { return newBuilder(this); } @@ -782,18 +782,18 @@ public final class WhisperProtos { } public static final class Builder extends com.google.protobuf.GeneratedMessage.Builder - implements org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessageOrBuilder { + implements org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessageOrBuilder { public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_PreKeyWhisperMessage_descriptor; + return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_PreKeyWhisperMessage_descriptor; } protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_PreKeyWhisperMessage_fieldAccessorTable; + return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_PreKeyWhisperMessage_fieldAccessorTable; } - // Construct using org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage.newBuilder() + // Construct using org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage.newBuilder() private Builder() { maybeForceBuilderInitialization(); } @@ -831,24 +831,24 @@ public final class WhisperProtos { public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage.getDescriptor(); + return org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage.getDescriptor(); } - public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage getDefaultInstanceForType() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage.getDefaultInstance(); + public org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage getDefaultInstanceForType() { + return org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage.getDefaultInstance(); } - public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage build() { - org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage result = buildPartial(); + public org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage build() { + org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException(result); } return result; } - private org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage buildParsed() + private org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage buildParsed() throws com.google.protobuf.InvalidProtocolBufferException { - org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage result = buildPartial(); + org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException( result).asInvalidProtocolBufferException(); @@ -856,8 +856,8 @@ public final class WhisperProtos { return result; } - public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage buildPartial() { - org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage result = new org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage(this); + public org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage buildPartial() { + org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage result = new org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage(this); int from_bitField0_ = bitField0_; int to_bitField0_ = 0; if (((from_bitField0_ & 0x00000001) == 0x00000001)) { @@ -886,16 +886,16 @@ public final class WhisperProtos { } public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage) { - return mergeFrom((org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage)other); + if (other instanceof org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage) { + return mergeFrom((org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage)other); } else { super.mergeFrom(other); return this; } } - public Builder mergeFrom(org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage other) { - if (other == org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage.getDefaultInstance()) return this; + public Builder mergeFrom(org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage other) { + if (other == org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage.getDefaultInstance()) return this; if (other.hasRegistrationId()) { setRegistrationId(other.getRegistrationId()); } @@ -1137,12 +1137,12 @@ public final class WhisperProtos { public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_KeyExchangeMessage_descriptor; + return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_KeyExchangeMessage_descriptor; } protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_KeyExchangeMessage_fieldAccessorTable; + return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_KeyExchangeMessage_fieldAccessorTable; } private int bitField0_; @@ -1253,41 +1253,41 @@ public final class WhisperProtos { return super.writeReplace(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage parseFrom( com.google.protobuf.ByteString data) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data).buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage parseFrom( com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data, extensionRegistry) .buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseFrom(byte[] data) + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data).buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage parseFrom( byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data, extensionRegistry) .buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseFrom(java.io.InputStream input) + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage parseFrom(java.io.InputStream input) throws java.io.IOException { return newBuilder().mergeFrom(input).buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage parseFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return newBuilder().mergeFrom(input, extensionRegistry) .buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseDelimitedFrom(java.io.InputStream input) + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException { Builder builder = newBuilder(); if (builder.mergeDelimitedFrom(input)) { @@ -1296,7 +1296,7 @@ public final class WhisperProtos { return null; } } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseDelimitedFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage parseDelimitedFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { @@ -1307,12 +1307,12 @@ public final class WhisperProtos { return null; } } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage parseFrom( com.google.protobuf.CodedInputStream input) throws java.io.IOException { return newBuilder().mergeFrom(input).buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage parseFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { @@ -1322,7 +1322,7 @@ public final class WhisperProtos { public static Builder newBuilder() { return Builder.create(); } public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder(org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage prototype) { + public static Builder newBuilder(org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage prototype) { return newBuilder().mergeFrom(prototype); } public Builder toBuilder() { return newBuilder(this); } @@ -1335,18 +1335,18 @@ public final class WhisperProtos { } public static final class Builder extends com.google.protobuf.GeneratedMessage.Builder - implements org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessageOrBuilder { + implements org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessageOrBuilder { public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_KeyExchangeMessage_descriptor; + return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_KeyExchangeMessage_descriptor; } protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_KeyExchangeMessage_fieldAccessorTable; + return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_KeyExchangeMessage_fieldAccessorTable; } - // Construct using org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage.newBuilder() + // Construct using org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage.newBuilder() private Builder() { maybeForceBuilderInitialization(); } @@ -1382,24 +1382,24 @@ public final class WhisperProtos { public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage.getDescriptor(); + return org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage.getDescriptor(); } - public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage getDefaultInstanceForType() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage.getDefaultInstance(); + public org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage getDefaultInstanceForType() { + return org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage.getDefaultInstance(); } - public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage build() { - org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage result = buildPartial(); + public org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage build() { + org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException(result); } return result; } - private org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage buildParsed() + private org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage buildParsed() throws com.google.protobuf.InvalidProtocolBufferException { - org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage result = buildPartial(); + org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException( result).asInvalidProtocolBufferException(); @@ -1407,8 +1407,8 @@ public final class WhisperProtos { return result; } - public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage buildPartial() { - org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage result = new org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage(this); + public org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage buildPartial() { + org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage result = new org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage(this); int from_bitField0_ = bitField0_; int to_bitField0_ = 0; if (((from_bitField0_ & 0x00000001) == 0x00000001)) { @@ -1433,16 +1433,16 @@ public final class WhisperProtos { } public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage) { - return mergeFrom((org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage)other); + if (other instanceof org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage) { + return mergeFrom((org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage)other); } else { super.mergeFrom(other); return this; } } - public Builder mergeFrom(org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage other) { - if (other == org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage.getDefaultInstance()) return this; + public Builder mergeFrom(org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage other) { + if (other == org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage.getDefaultInstance()) return this; if (other.hasId()) { setId(other.getId()); } @@ -1648,9 +1648,9 @@ public final class WhisperProtos { "d\030\001 \001(\r\022\017\n\007baseKey\030\002 \001(\014\022\023\n\013identityKey\030" + "\003 \001(\014\022\017\n\007message\030\004 \001(\014\"\\\n\022KeyExchangeMes" + "sage\022\n\n\002id\030\001 \001(\r\022\017\n\007baseKey\030\002 \001(\014\022\024\n\014eph" + - "emeralKey\030\003 \001(\014\022\023\n\013identityKey\030\004 \001(\014B>\n-" + - "org.whispersystems.textsecure.crypto.pro", - "tocolB\rWhisperProtos" + "emeralKey\030\003 \001(\014\022\023\n\013identityKey\030\004 \001(\014B7\n&" + + "org.whispersystems.libaxolotl.protocolB\r", + "WhisperProtos" }; com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { @@ -1663,24 +1663,24 @@ public final class WhisperProtos { com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_textsecure_WhisperMessage_descriptor, new java.lang.String[] { "EphemeralKey", "Counter", "PreviousCounter", "Ciphertext", }, - org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage.class, - org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage.Builder.class); + org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage.class, + org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage.Builder.class); internal_static_textsecure_PreKeyWhisperMessage_descriptor = getDescriptor().getMessageTypes().get(1); internal_static_textsecure_PreKeyWhisperMessage_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_textsecure_PreKeyWhisperMessage_descriptor, new java.lang.String[] { "RegistrationId", "PreKeyId", "BaseKey", "IdentityKey", "Message", }, - org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage.class, - org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage.Builder.class); + org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage.class, + org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage.Builder.class); internal_static_textsecure_KeyExchangeMessage_descriptor = getDescriptor().getMessageTypes().get(2); internal_static_textsecure_KeyExchangeMessage_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_textsecure_KeyExchangeMessage_descriptor, new java.lang.String[] { "Id", "BaseKey", "EphemeralKey", "IdentityKey", }, - org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage.class, - org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage.Builder.class); + org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage.class, + org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage.Builder.class); return null; } }; diff --git a/library/src/org/whispersystems/textsecure/crypto/ratchet/ChainKey.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/ChainKey.java similarity index 58% rename from library/src/org/whispersystems/textsecure/crypto/ratchet/ChainKey.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/ChainKey.java index c3c8b26ff..3f4daa710 100644 --- a/library/src/org/whispersystems/textsecure/crypto/ratchet/ChainKey.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/ChainKey.java @@ -1,7 +1,24 @@ -package org.whispersystems.textsecure.crypto.ratchet; +/** + * Copyright (C) 2014 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.whispersystems.libaxolotl.ratchet; -import org.whispersystems.textsecure.crypto.kdf.DerivedSecrets; -import org.whispersystems.textsecure.crypto.kdf.HKDF; + +import org.whispersystems.libaxolotl.kdf.DerivedSecrets; +import org.whispersystems.libaxolotl.kdf.HKDF; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; @@ -49,9 +66,7 @@ public class ChainKey { mac.init(new SecretKeySpec(key, "HmacSHA256")); return mac.doFinal(seed); - } catch (NoSuchAlgorithmException e) { - throw new AssertionError(e); - } catch (InvalidKeyException e) { + } catch (NoSuchAlgorithmException | InvalidKeyException e) { throw new AssertionError(e); } } diff --git a/library/src/org/whispersystems/textsecure/crypto/InvalidVersionException.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/MessageKeys.java similarity index 51% rename from library/src/org/whispersystems/textsecure/crypto/InvalidVersionException.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/MessageKeys.java index 6194b1c3c..e4aed3df7 100644 --- a/library/src/org/whispersystems/textsecure/crypto/InvalidVersionException.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/MessageKeys.java @@ -1,6 +1,6 @@ -/** - * Copyright (C) 2011 Whisper Systems - * +/** + * Copyright (C) 2014 Open Whisper Systems + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -10,31 +10,35 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package org.whispersystems.textsecure.crypto; +package org.whispersystems.libaxolotl.ratchet; -public class InvalidVersionException extends Exception { +import javax.crypto.spec.SecretKeySpec; - public InvalidVersionException() { - // TODO Auto-generated constructor stub +public class MessageKeys { + + private final SecretKeySpec cipherKey; + private final SecretKeySpec macKey; + private final int counter; + + public MessageKeys(SecretKeySpec cipherKey, SecretKeySpec macKey, int counter) { + this.cipherKey = cipherKey; + this.macKey = macKey; + this.counter = counter; } - public InvalidVersionException(String detailMessage) { - super(detailMessage); - // TODO Auto-generated constructor stub + public SecretKeySpec getCipherKey() { + return cipherKey; } - public InvalidVersionException(Throwable throwable) { - super(throwable); - // TODO Auto-generated constructor stub + public SecretKeySpec getMacKey() { + return macKey; } - public InvalidVersionException(String detailMessage, Throwable throwable) { - super(detailMessage, throwable); - // TODO Auto-generated constructor stub + public int getCounter() { + return counter; } - } diff --git a/library/src/org/whispersystems/textsecure/crypto/ratchet/RatchetingSession.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/RatchetingSession.java similarity index 74% rename from library/src/org/whispersystems/textsecure/crypto/ratchet/RatchetingSession.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/RatchetingSession.java index c2f34fffa..9a7a5e20f 100644 --- a/library/src/org/whispersystems/textsecure/crypto/ratchet/RatchetingSession.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/RatchetingSession.java @@ -1,16 +1,34 @@ -package org.whispersystems.textsecure.crypto.ratchet; +/** + * Copyright (C) 2014 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.whispersystems.libaxolotl.ratchet; -import android.util.Pair; +import android.util.Log; -import org.whispersystems.textsecure.crypto.IdentityKey; -import org.whispersystems.textsecure.crypto.IdentityKeyPair; -import org.whispersystems.textsecure.crypto.InvalidKeyException; -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECKeyPair; -import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; -import org.whispersystems.textsecure.crypto.kdf.DerivedSecrets; -import org.whispersystems.textsecure.crypto.kdf.HKDF; -import org.whispersystems.textsecure.storage.SessionState; +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.libaxolotl.IdentityKeyPair; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.SessionState; +import org.whispersystems.libaxolotl.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECKeyPair; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; +import org.whispersystems.libaxolotl.kdf.DerivedSecrets; +import org.whispersystems.libaxolotl.kdf.HKDF; +import org.whispersystems.libaxolotl.util.Hex; +import org.whispersystems.libaxolotl.util.Pair; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -47,11 +65,11 @@ public class RatchetingSession { ECKeyPair sendingKey = Curve.generateKeyPair(true); Pair receivingChain = calculate3DHE(true, ourBaseKey, theirBaseKey, ourIdentityKey, theirIdentityKey); - Pair sendingChain = receivingChain.first.createChain(theirEphemeralKey, sendingKey); + Pair sendingChain = receivingChain.first().createChain(theirEphemeralKey, sendingKey); - sessionState.addReceiverChain(theirEphemeralKey, receivingChain.second); - sessionState.setSenderChain(sendingKey, sendingChain.second); - sessionState.setRootKey(sendingChain.first); + sessionState.addReceiverChain(theirEphemeralKey, receivingChain.second()); + sessionState.setSenderChain(sendingKey, sendingChain.second()); + sessionState.setRootKey(sendingChain.first()); } private static void initializeSessionAsBob(SessionState sessionState, @@ -67,8 +85,8 @@ public class RatchetingSession { Pair sendingChain = calculate3DHE(false, ourBaseKey, theirBaseKey, ourIdentityKey, theirIdentityKey); - sessionState.setSenderChain(ourEphemeralKey, sendingChain.second); - sessionState.setRootKey(sendingChain.first); + sessionState.setSenderChain(ourEphemeralKey, sendingChain.second()); + sessionState.setRootKey(sendingChain.first()); } private static Pair calculate3DHE(boolean isAlice, diff --git a/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/RootKey.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/RootKey.java new file mode 100644 index 000000000..9d59f133d --- /dev/null +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/RootKey.java @@ -0,0 +1,50 @@ +/** + * Copyright (C) 2014 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.whispersystems.libaxolotl.ratchet; + +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECKeyPair; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; +import org.whispersystems.libaxolotl.kdf.DerivedSecrets; +import org.whispersystems.libaxolotl.kdf.HKDF; +import org.whispersystems.libaxolotl.util.Pair; + +public class RootKey { + + private final byte[] key; + + public RootKey(byte[] key) { + this.key = key; + } + + public byte[] getKeyBytes() { + return key; + } + + public Pair createChain(ECPublicKey theirEphemeral, ECKeyPair ourEphemeral) + throws InvalidKeyException + { + HKDF kdf = new HKDF(); + byte[] sharedSecret = Curve.calculateAgreement(theirEphemeral, ourEphemeral.getPrivateKey()); + DerivedSecrets keys = kdf.deriveSecrets(sharedSecret, key, "WhisperRatchet".getBytes()); + RootKey newRootKey = new RootKey(keys.getCipherKey().getEncoded()); + ChainKey newChainKey = new ChainKey(keys.getMacKey().getEncoded(), 0); + + return new Pair<>(newRootKey, newChainKey); + } +} diff --git a/libaxolotl/src/main/java/org/whispersystems/libaxolotl/util/ByteUtil.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/util/ByteUtil.java new file mode 100644 index 000000000..e22b584d0 --- /dev/null +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/util/ByteUtil.java @@ -0,0 +1,241 @@ +/** + * Copyright (C) 2014 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.whispersystems.libaxolotl.util; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.text.ParseException; + +public class ByteUtil { + + public static byte[] combine(byte[]... elements) { + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + for (byte[] element : elements) { + baos.write(element); + } + + return baos.toByteArray(); + } catch (IOException e) { + throw new AssertionError(e); + } + } + + public static byte[][] split(byte[] input, int firstLength, int secondLength) { + byte[][] parts = new byte[2][]; + + parts[0] = new byte[firstLength]; + System.arraycopy(input, 0, parts[0], 0, firstLength); + + parts[1] = new byte[secondLength]; + System.arraycopy(input, firstLength, parts[1], 0, secondLength); + + return parts; + } + + public static byte[][] split(byte[] input, int firstLength, int secondLength, int thirdLength) + throws ParseException + { + if (input == null || firstLength < 0 || secondLength < 0 || thirdLength < 0 || + input.length < firstLength + secondLength + thirdLength) + { + throw new ParseException("Input too small: " + (input == null ? null : Hex.toString(input)), 0); + } + + byte[][] parts = new byte[3][]; + + parts[0] = new byte[firstLength]; + System.arraycopy(input, 0, parts[0], 0, firstLength); + + parts[1] = new byte[secondLength]; + System.arraycopy(input, firstLength, parts[1], 0, secondLength); + + parts[2] = new byte[thirdLength]; + System.arraycopy(input, firstLength + secondLength, parts[2], 0, thirdLength); + + return parts; + } + + public static byte[] trim(byte[] input, int length) { + byte[] result = new byte[length]; + System.arraycopy(input, 0, result, 0, result.length); + + return result; + } + + public static byte intsToByteHighAndLow(int highValue, int lowValue) { + return (byte)((highValue << 4 | lowValue) & 0xFF); + } + + public static int highBitsToInt(byte value) { + return (value & 0xFF) >> 4; + } + + public static int lowBitsToInt(byte value) { + return (value & 0xF); + } + + public static int highBitsToMedium(int value) { + return (value >> 12); + } + + public static int lowBitsToMedium(int value) { + return (value & 0xFFF); + } + + public static byte[] shortToByteArray(int value) { + byte[] bytes = new byte[2]; + shortToByteArray(bytes, 0, value); + return bytes; + } + + public static int shortToByteArray(byte[] bytes, int offset, int value) { + bytes[offset+1] = (byte)value; + bytes[offset] = (byte)(value >> 8); + return 2; + } + + public static int shortToLittleEndianByteArray(byte[] bytes, int offset, int value) { + bytes[offset] = (byte)value; + bytes[offset+1] = (byte)(value >> 8); + return 2; + } + + public static byte[] mediumToByteArray(int value) { + byte[] bytes = new byte[3]; + mediumToByteArray(bytes, 0, value); + return bytes; + } + + public static int mediumToByteArray(byte[] bytes, int offset, int value) { + bytes[offset + 2] = (byte)value; + bytes[offset + 1] = (byte)(value >> 8); + bytes[offset] = (byte)(value >> 16); + return 3; + } + + public static byte[] intToByteArray(int value) { + byte[] bytes = new byte[4]; + intToByteArray(bytes, 0, value); + return bytes; + } + + public static int intToByteArray(byte[] bytes, int offset, int value) { + bytes[offset + 3] = (byte)value; + bytes[offset + 2] = (byte)(value >> 8); + bytes[offset + 1] = (byte)(value >> 16); + bytes[offset] = (byte)(value >> 24); + return 4; + } + + public static int intToLittleEndianByteArray(byte[] bytes, int offset, int value) { + bytes[offset] = (byte)value; + bytes[offset+1] = (byte)(value >> 8); + bytes[offset+2] = (byte)(value >> 16); + bytes[offset+3] = (byte)(value >> 24); + return 4; + } + + public static byte[] longToByteArray(long l) { + byte[] bytes = new byte[8]; + longToByteArray(bytes, 0, l); + return bytes; + } + + public static int longToByteArray(byte[] bytes, int offset, long value) { + bytes[offset + 7] = (byte)value; + bytes[offset + 6] = (byte)(value >> 8); + bytes[offset + 5] = (byte)(value >> 16); + bytes[offset + 4] = (byte)(value >> 24); + bytes[offset + 3] = (byte)(value >> 32); + bytes[offset + 2] = (byte)(value >> 40); + bytes[offset + 1] = (byte)(value >> 48); + bytes[offset] = (byte)(value >> 56); + return 8; + } + + public static int longTo4ByteArray(byte[] bytes, int offset, long value) { + bytes[offset + 3] = (byte)value; + bytes[offset + 2] = (byte)(value >> 8); + bytes[offset + 1] = (byte)(value >> 16); + bytes[offset + 0] = (byte)(value >> 24); + return 4; + } + + public static int byteArrayToShort(byte[] bytes) { + return byteArrayToShort(bytes, 0); + } + + public static int byteArrayToShort(byte[] bytes, int offset) { + return + (bytes[offset] & 0xff) << 8 | (bytes[offset + 1] & 0xff); + } + + // The SSL patented 3-byte Value. + public static int byteArrayToMedium(byte[] bytes, int offset) { + return + (bytes[offset] & 0xff) << 16 | + (bytes[offset + 1] & 0xff) << 8 | + (bytes[offset + 2] & 0xff); + } + + public static int byteArrayToInt(byte[] bytes) { + return byteArrayToInt(bytes, 0); + } + + public static int byteArrayToInt(byte[] bytes, int offset) { + return + (bytes[offset] & 0xff) << 24 | + (bytes[offset + 1] & 0xff) << 16 | + (bytes[offset + 2] & 0xff) << 8 | + (bytes[offset + 3] & 0xff); + } + + public static int byteArrayToIntLittleEndian(byte[] bytes, int offset) { + return + (bytes[offset + 3] & 0xff) << 24 | + (bytes[offset + 2] & 0xff) << 16 | + (bytes[offset + 1] & 0xff) << 8 | + (bytes[offset] & 0xff); + } + + public static long byteArrayToLong(byte[] bytes) { + return byteArrayToLong(bytes, 0); + } + + public static long byteArray4ToLong(byte[] bytes, int offset) { + return + ((bytes[offset + 0] & 0xffL) << 24) | + ((bytes[offset + 1] & 0xffL) << 16) | + ((bytes[offset + 2] & 0xffL) << 8) | + ((bytes[offset + 3] & 0xffL)); + } + + public static long byteArrayToLong(byte[] bytes, int offset) { + return + ((bytes[offset] & 0xffL) << 56) | + ((bytes[offset + 1] & 0xffL) << 48) | + ((bytes[offset + 2] & 0xffL) << 40) | + ((bytes[offset + 3] & 0xffL) << 32) | + ((bytes[offset + 4] & 0xffL) << 24) | + ((bytes[offset + 5] & 0xffL) << 16) | + ((bytes[offset + 6] & 0xffL) << 8) | + ((bytes[offset + 7] & 0xffL)); + } + +} diff --git a/libaxolotl/src/main/java/org/whispersystems/libaxolotl/util/Hex.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/util/Hex.java new file mode 100644 index 000000000..0d71e342a --- /dev/null +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/util/Hex.java @@ -0,0 +1,78 @@ +/** + * Copyright (C) 2014 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.whispersystems.libaxolotl.util; + +import java.io.IOException; + +/** + * Utility for generating hex dumps. + */ +public class Hex { + + private final static char[] HEX_DIGITS = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' + }; + + public static String toString(byte[] bytes) { + return toString(bytes, 0, bytes.length); + } + + public static String toString(byte[] bytes, int offset, int length) { + StringBuffer buf = new StringBuffer(); + for (int i = 0; i < length; i++) { + buf.append("(byte)0x"); + appendHexChar(buf, bytes[offset + i]); + buf.append(", "); + } + return buf.toString(); + } + + public static String toStringCondensed(byte[] bytes) { + StringBuffer buf = new StringBuffer(); + for (int i=0;i> 1]; + + for (int i = 0, j = 0; j < len; i++) { + int f = Character.digit(data[j], 16) << 4; + j++; + f = f | Character.digit(data[j], 16); + j++; + out[i] = (byte) (f & 0xFF); + } + + return out; + } + + private static void appendHexChar(StringBuffer buf, int b) { + buf.append(HEX_DIGITS[(b >> 4) & 0xf]); + buf.append(HEX_DIGITS[b & 0xf]); + } + +} diff --git a/libaxolotl/src/main/java/org/whispersystems/libaxolotl/util/Pair.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/util/Pair.java new file mode 100644 index 000000000..0476d9326 --- /dev/null +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/util/Pair.java @@ -0,0 +1,51 @@ +/** + * Copyright (C) 2014 Open WhisperSystems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.whispersystems.libaxolotl.util; + +public class Pair { + private final T1 v1; + private final T2 v2; + + public Pair(T1 v1, T2 v2) { + this.v1 = v1; + this.v2 = v2; + } + + public T1 first(){ + return v1; + } + + public T2 second(){ + return v2; + } + + public boolean equals(Object o) { + return o instanceof Pair && + equal(((Pair) o).first(), first()) && + equal(((Pair) o).second(), second()); + } + + public int hashCode() { + return first().hashCode() ^ second().hashCode(); + } + + private boolean equal(Object first, Object second) { + if (first == null && second == null) return true; + if (first == null || second == null) return false; + return first.equals(second); + } +} diff --git a/library/build.gradle b/library/build.gradle index 61b3c590d..131cb7ed9 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -23,6 +23,8 @@ dependencies { compile 'com.madgag:sc-light-jdk15on:1.47.0.2' compile 'com.googlecode.libphonenumber:libphonenumber:6.1' compile 'org.whispersystems:gson:2.2.4' + + compile project(':libaxolotl') } android { @@ -45,6 +47,12 @@ android { } } +tasks.whenTaskAdded { task -> + if (task.name.equals("lint")) { + task.enabled = false + } +} + version '0.1' group 'org.whispersystems.textsecure' archivesBaseName = 'textsecure-library' diff --git a/library/src/org/whispersystems/textsecure/crypto/AttachmentCipher.java b/library/src/org/whispersystems/textsecure/crypto/AttachmentCipher.java index 04c3ada6b..9ad4f3e98 100644 --- a/library/src/org/whispersystems/textsecure/crypto/AttachmentCipher.java +++ b/library/src/org/whispersystems/textsecure/crypto/AttachmentCipher.java @@ -18,6 +18,8 @@ package org.whispersystems.textsecure.crypto; import android.util.Log; +import org.whispersystems.libaxolotl.InvalidMacException; +import org.whispersystems.libaxolotl.InvalidMessageException; import org.whispersystems.textsecure.util.Hex; import org.whispersystems.textsecure.util.Util; diff --git a/library/src/org/whispersystems/textsecure/crypto/AttachmentCipherInputStream.java b/library/src/org/whispersystems/textsecure/crypto/AttachmentCipherInputStream.java index 1be3eded0..c28554656 100644 --- a/library/src/org/whispersystems/textsecure/crypto/AttachmentCipherInputStream.java +++ b/library/src/org/whispersystems/textsecure/crypto/AttachmentCipherInputStream.java @@ -18,6 +18,8 @@ package org.whispersystems.textsecure.crypto; import android.util.Log; +import org.whispersystems.libaxolotl.InvalidMacException; +import org.whispersystems.libaxolotl.InvalidMessageException; import org.whispersystems.textsecure.util.Util; import java.io.File; diff --git a/library/src/org/whispersystems/textsecure/crypto/IdentityKey.java b/library/src/org/whispersystems/textsecure/crypto/IdentityKey.java deleted file mode 100644 index 875bd3bfb..000000000 --- a/library/src/org/whispersystems/textsecure/crypto/IdentityKey.java +++ /dev/null @@ -1,113 +0,0 @@ -/** - * Copyright (C) 2011 Whisper Systems - * Copyright (C) 2013 Open Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.whispersystems.textsecure.crypto; - -import android.os.Parcel; -import android.os.Parcelable; - -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; -import org.whispersystems.textsecure.util.Hex; - -/** - * A class for representing an identity key. - * - * @author Moxie Marlinspike - */ - -public class IdentityKey implements Parcelable, SerializableKey { - - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public IdentityKey createFromParcel(Parcel in) { - try { - return new IdentityKey(in); - } catch (InvalidKeyException e) { - throw new AssertionError(e); - } - } - - public IdentityKey[] newArray(int size) { - return new IdentityKey[size]; - } - }; - - public static final int NIST_SIZE = 1 + ECPublicKey.KEY_SIZE; - - private ECPublicKey publicKey; - - public IdentityKey(ECPublicKey publicKey) { - this.publicKey = publicKey; - } - - public IdentityKey(Parcel in) throws InvalidKeyException { - int length = in.readInt(); - byte[] serialized = new byte[length]; - - in.readByteArray(serialized); - initializeFromSerialized(serialized, 0); - } - - public IdentityKey(byte[] bytes, int offset) throws InvalidKeyException { - initializeFromSerialized(bytes, offset); - } - - public ECPublicKey getPublicKey() { - return publicKey; - } - - private void initializeFromSerialized(byte[] bytes, int offset) throws InvalidKeyException { - if ((bytes[offset] & 0xff) == 1) { - this.publicKey = Curve.decodePoint(bytes, offset +1); - } else { - this.publicKey = Curve.decodePoint(bytes, offset); - } - } - - public byte[] serialize() { - return publicKey.serialize(); - } - - public String getFingerprint() { - return Hex.toString(publicKey.serialize()); - } - - @Override - public boolean equals(Object other) { - if (other == null) return false; - if (!(other instanceof IdentityKey)) return false; - - return publicKey.equals(((IdentityKey) other).getPublicKey()); - } - - @Override - public int hashCode() { - return publicKey.hashCode(); - } - - public int describeContents() { - // TODO Auto-generated method stub - return 0; - } - - public void writeToParcel(Parcel dest, int flags) { - byte[] serialized = this.serialize(); - dest.writeInt(serialized.length); - dest.writeByteArray(serialized); - } - -} diff --git a/library/src/org/whispersystems/textsecure/crypto/IdentityKeyParcelable.java b/library/src/org/whispersystems/textsecure/crypto/IdentityKeyParcelable.java new file mode 100644 index 000000000..c646609bc --- /dev/null +++ b/library/src/org/whispersystems/textsecure/crypto/IdentityKeyParcelable.java @@ -0,0 +1,69 @@ +/** + * Copyright (C) 2014 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.whispersystems.textsecure.crypto; + +import android.os.Parcel; +import android.os.Parcelable; + +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.libaxolotl.InvalidKeyException; + +public class IdentityKeyParcelable implements Parcelable { + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public IdentityKeyParcelable createFromParcel(Parcel in) { + try { + return new IdentityKeyParcelable(in); + } catch (InvalidKeyException e) { + throw new AssertionError(e); + } + } + + public IdentityKeyParcelable[] newArray(int size) { + return new IdentityKeyParcelable[size]; + } + }; + + private final IdentityKey identityKey; + + public IdentityKeyParcelable(IdentityKey identityKey) { + this.identityKey = identityKey; + } + + public IdentityKeyParcelable(Parcel in) throws InvalidKeyException { + int serializedLength = in.readInt(); + byte[] serialized = new byte[serializedLength]; + + in.readByteArray(serialized); + this.identityKey = new IdentityKey(serialized, 0); + } + + public IdentityKey get() { + return identityKey; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(identityKey.serialize().length); + dest.writeByteArray(identityKey.serialize()); + } +} diff --git a/library/src/org/whispersystems/textsecure/crypto/MasterCipher.java b/library/src/org/whispersystems/textsecure/crypto/MasterCipher.java index 78b3918e5..80d682754 100644 --- a/library/src/org/whispersystems/textsecure/crypto/MasterCipher.java +++ b/library/src/org/whispersystems/textsecure/crypto/MasterCipher.java @@ -19,8 +19,9 @@ package org.whispersystems.textsecure.crypto; import android.util.Log; -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECPrivateKey; +import org.whispersystems.libaxolotl.InvalidMessageException; +import org.whispersystems.libaxolotl.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECPrivateKey; import org.whispersystems.textsecure.util.Base64; import org.whispersystems.textsecure.util.Hex; @@ -84,12 +85,12 @@ public class MasterCipher { } public ECPrivateKey decryptKey(byte[] key) - throws org.whispersystems.textsecure.crypto.InvalidKeyException + throws org.whispersystems.libaxolotl.InvalidKeyException { try { return Curve.decodePrivatePoint(decryptBytes(key)); } catch (InvalidMessageException ime) { - throw new org.whispersystems.textsecure.crypto.InvalidKeyException(ime); + throw new org.whispersystems.libaxolotl.InvalidKeyException(ime); } } diff --git a/library/src/org/whispersystems/textsecure/crypto/PreKeyUtil.java b/library/src/org/whispersystems/textsecure/crypto/PreKeyUtil.java index e137b97c0..7574d4db7 100644 --- a/library/src/org/whispersystems/textsecure/crypto/PreKeyUtil.java +++ b/library/src/org/whispersystems/textsecure/crypto/PreKeyUtil.java @@ -22,8 +22,8 @@ import android.util.Log; import com.google.thoughtcrimegson.Gson; -import org.whispersystems.textsecure.crypto.ecc.Curve25519; -import org.whispersystems.textsecure.crypto.ecc.ECKeyPair; +import org.whispersystems.libaxolotl.ecc.Curve25519; +import org.whispersystems.libaxolotl.ecc.ECKeyPair; import org.whispersystems.textsecure.storage.InvalidKeyIdException; import org.whispersystems.textsecure.storage.PreKeyRecord; import org.whispersystems.textsecure.util.Medium; diff --git a/library/src/org/whispersystems/textsecure/crypto/PublicKey.java b/library/src/org/whispersystems/textsecure/crypto/PublicKey.java index 293b18d32..2540877de 100644 --- a/library/src/org/whispersystems/textsecure/crypto/PublicKey.java +++ b/library/src/org/whispersystems/textsecure/crypto/PublicKey.java @@ -19,8 +19,9 @@ package org.whispersystems.textsecure.crypto; import android.util.Log; -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; import org.whispersystems.textsecure.util.Conversions; import org.whispersystems.textsecure.util.Hex; import org.whispersystems.textsecure.util.Util; diff --git a/library/src/org/whispersystems/textsecure/crypto/SessionCipherFactory.java b/library/src/org/whispersystems/textsecure/crypto/SessionCipherFactory.java new file mode 100644 index 000000000..e3a5dacad --- /dev/null +++ b/library/src/org/whispersystems/textsecure/crypto/SessionCipherFactory.java @@ -0,0 +1,39 @@ +/** + * Copyright (C) 2013 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.whispersystems.textsecure.crypto; + + +import android.content.Context; + +import org.whispersystems.libaxolotl.SessionCipher; +import org.whispersystems.textsecure.storage.RecipientDevice; +import org.whispersystems.textsecure.storage.SessionRecordV2; + +public class SessionCipherFactory { + + public static SessionCipher getInstance(Context context, + MasterSecret masterSecret, + RecipientDevice recipient) + { + if (SessionRecordV2.hasSession(context, masterSecret, recipient)) { + SessionRecordV2 record = new SessionRecordV2(context, masterSecret, recipient); + return new SessionCipher(record); + } else { + throw new AssertionError("Attempt to initialize cipher for non-existing session."); + } + } +} \ No newline at end of file diff --git a/library/src/org/whispersystems/textsecure/crypto/kdf/NKDF.java b/library/src/org/whispersystems/textsecure/crypto/kdf/NKDF.java deleted file mode 100644 index 1ae591374..000000000 --- a/library/src/org/whispersystems/textsecure/crypto/kdf/NKDF.java +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Copyright (C) 2013 Open Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package org.whispersystems.textsecure.crypto.kdf; - -import android.util.Log; - -import org.whispersystems.textsecure.util.Conversions; - -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -import javax.crypto.spec.SecretKeySpec; - -public class NKDF { - - public static final int LEGACY_CIPHER_KEY_LENGTH = 16; - public static final int LEGACY_MAC_KEY_LENGTH = 20; - - public DerivedSecrets deriveSecrets(byte[] sharedSecret, boolean isLowEnd) - { - SecretKeySpec cipherKey = deriveCipherSecret(isLowEnd, sharedSecret); - SecretKeySpec macKey = deriveMacSecret(cipherKey); - - return new DerivedSecrets(cipherKey, macKey); - } - - private SecretKeySpec deriveCipherSecret(boolean isLowEnd, byte[] sharedSecret) { - byte[] derivedBytes = deriveBytes(sharedSecret, LEGACY_CIPHER_KEY_LENGTH * 2); - byte[] cipherSecret = new byte[LEGACY_CIPHER_KEY_LENGTH]; - - if (isLowEnd) { - System.arraycopy(derivedBytes, LEGACY_CIPHER_KEY_LENGTH, cipherSecret, 0, LEGACY_CIPHER_KEY_LENGTH); - } else { - System.arraycopy(derivedBytes, 0, cipherSecret, 0, LEGACY_CIPHER_KEY_LENGTH); - } - - return new SecretKeySpec(cipherSecret, "AES"); - } - - private SecretKeySpec deriveMacSecret(SecretKeySpec key) { - try { - MessageDigest md = MessageDigest.getInstance("SHA-1"); - byte[] secret = md.digest(key.getEncoded()); - - return new SecretKeySpec(secret, "HmacSHA1"); - } catch (NoSuchAlgorithmException e) { - throw new IllegalArgumentException("SHA-1 Not Supported!",e); - } - } - - private byte[] deriveBytes(byte[] seed, int bytesNeeded) { - MessageDigest md; - - try { - md = MessageDigest.getInstance("SHA-256"); - } catch (NoSuchAlgorithmException e) { - Log.w("NKDF", e); - throw new IllegalArgumentException("SHA-256 Not Supported!"); - } - - int rounds = bytesNeeded / md.getDigestLength(); - - for (int i=1;i<=rounds;i++) { - byte[] roundBytes = Conversions.intToByteArray(i); - md.update(roundBytes); - md.update(seed); - } - - return md.digest(); - } -} diff --git a/library/src/org/whispersystems/textsecure/crypto/protocol/CiphertextMessage.java b/library/src/org/whispersystems/textsecure/crypto/protocol/CiphertextMessage.java deleted file mode 100644 index 7bed17ad0..000000000 --- a/library/src/org/whispersystems/textsecure/crypto/protocol/CiphertextMessage.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.whispersystems.textsecure.crypto.protocol; - -public interface CiphertextMessage { - - public static final int UNSUPPORTED_VERSION = 1; - public static final int CURRENT_VERSION = 2; - - public static final int WHISPER_TYPE = 2; - public static final int PREKEY_TYPE = 3; - - // This should be the worst case (worse than V2). So not always accurate, but good enough for padding. - public static final int ENCRYPTED_MESSAGE_OVERHEAD = 53; - - public byte[] serialize(); - public int getType(); - -} \ No newline at end of file diff --git a/library/src/org/whispersystems/textsecure/crypto/ratchet/MessageKeys.java b/library/src/org/whispersystems/textsecure/crypto/ratchet/MessageKeys.java deleted file mode 100644 index 1ab6208de..000000000 --- a/library/src/org/whispersystems/textsecure/crypto/ratchet/MessageKeys.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.whispersystems.textsecure.crypto.ratchet; - -import javax.crypto.spec.SecretKeySpec; - -public class MessageKeys { - - private final SecretKeySpec cipherKey; - private final SecretKeySpec macKey; - private final int counter; - - public MessageKeys(SecretKeySpec cipherKey, SecretKeySpec macKey, int counter) { - this.cipherKey = cipherKey; - this.macKey = macKey; - this.counter = counter; - } - - public SecretKeySpec getCipherKey() { - return cipherKey; - } - - public SecretKeySpec getMacKey() { - return macKey; - } - - public int getCounter() { - return counter; - } -} diff --git a/library/src/org/whispersystems/textsecure/crypto/ratchet/RootKey.java b/library/src/org/whispersystems/textsecure/crypto/ratchet/RootKey.java deleted file mode 100644 index 5ba19bc13..000000000 --- a/library/src/org/whispersystems/textsecure/crypto/ratchet/RootKey.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.whispersystems.textsecure.crypto.ratchet; - -import android.util.Pair; - -import org.whispersystems.textsecure.crypto.InvalidKeyException; -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECKeyPair; -import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; -import org.whispersystems.textsecure.crypto.kdf.DerivedSecrets; -import org.whispersystems.textsecure.crypto.kdf.HKDF; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; - -public class RootKey { - - private final byte[] key; - - public RootKey(byte[] key) { - this.key = key; - } - - public byte[] getKeyBytes() { - return key; - } - - public Pair createChain(ECPublicKey theirEphemeral, ECKeyPair ourEphemeral) - throws InvalidKeyException - { - HKDF kdf = new HKDF(); - byte[] sharedSecret = Curve.calculateAgreement(theirEphemeral, ourEphemeral.getPrivateKey()); - DerivedSecrets keys = kdf.deriveSecrets(sharedSecret, key, "WhisperRatchet".getBytes()); - RootKey newRootKey = new RootKey(keys.getCipherKey().getEncoded()); - ChainKey newChainKey = new ChainKey(keys.getMacKey().getEncoded(), 0); - - return new Pair(newRootKey, newChainKey); - } -} diff --git a/library/src/org/whispersystems/textsecure/push/IncomingEncryptedPushMessage.java b/library/src/org/whispersystems/textsecure/push/IncomingEncryptedPushMessage.java index 45d173a64..3e34128ca 100644 --- a/library/src/org/whispersystems/textsecure/push/IncomingEncryptedPushMessage.java +++ b/library/src/org/whispersystems/textsecure/push/IncomingEncryptedPushMessage.java @@ -2,7 +2,7 @@ package org.whispersystems.textsecure.push; import android.util.Log; -import org.whispersystems.textsecure.crypto.InvalidVersionException; +import org.whispersystems.libaxolotl.InvalidVersionException; import org.whispersystems.textsecure.util.Base64; import org.whispersystems.textsecure.push.PushMessageProtos.IncomingPushMessageSignal; import org.whispersystems.textsecure.util.Hex; diff --git a/library/src/org/whispersystems/textsecure/push/PreKeyEntity.java b/library/src/org/whispersystems/textsecure/push/PreKeyEntity.java index fd0559509..1955dc322 100644 --- a/library/src/org/whispersystems/textsecure/push/PreKeyEntity.java +++ b/library/src/org/whispersystems/textsecure/push/PreKeyEntity.java @@ -10,10 +10,10 @@ import com.google.thoughtcrimegson.JsonSerializationContext; import com.google.thoughtcrimegson.JsonSerializer; import com.google.thoughtcrimegson.annotations.Expose; -import org.whispersystems.textsecure.crypto.IdentityKey; -import org.whispersystems.textsecure.crypto.InvalidKeyException; -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; import org.whispersystems.textsecure.util.Base64; import java.io.IOException; diff --git a/library/src/org/whispersystems/textsecure/push/PushServiceSocket.java b/library/src/org/whispersystems/textsecure/push/PushServiceSocket.java index f9c88e763..9304d8d1f 100644 --- a/library/src/org/whispersystems/textsecure/push/PushServiceSocket.java +++ b/library/src/org/whispersystems/textsecure/push/PushServiceSocket.java @@ -23,7 +23,7 @@ import com.google.thoughtcrimegson.Gson; import com.google.thoughtcrimegson.JsonParseException; import org.apache.http.conn.ssl.StrictHostnameVerifier; -import org.whispersystems.textsecure.crypto.IdentityKey; +import org.whispersystems.libaxolotl.IdentityKey; import org.whispersystems.textsecure.storage.PreKeyRecord; import org.whispersystems.textsecure.util.Base64; import org.whispersystems.textsecure.util.BlacklistingTrustManager; diff --git a/library/src/org/whispersystems/textsecure/storage/PreKeyRecord.java b/library/src/org/whispersystems/textsecure/storage/PreKeyRecord.java index 2018e2d92..edf52ce16 100644 --- a/library/src/org/whispersystems/textsecure/storage/PreKeyRecord.java +++ b/library/src/org/whispersystems/textsecure/storage/PreKeyRecord.java @@ -5,14 +5,14 @@ import android.util.Log; import com.google.protobuf.ByteString; -import org.whispersystems.textsecure.crypto.InvalidKeyException; -import org.whispersystems.textsecure.crypto.InvalidMessageException; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.InvalidMessageException; +import org.whispersystems.libaxolotl.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECKeyPair; +import org.whispersystems.libaxolotl.ecc.ECPrivateKey; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; import org.whispersystems.textsecure.crypto.MasterCipher; import org.whispersystems.textsecure.crypto.MasterSecret; -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECKeyPair; -import org.whispersystems.textsecure.crypto.ecc.ECPrivateKey; -import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; import java.io.FileInputStream; import java.io.FileNotFoundException; diff --git a/library/src/org/whispersystems/textsecure/storage/Record.java b/library/src/org/whispersystems/textsecure/storage/Record.java index 35f941b71..88f9439bb 100644 --- a/library/src/org/whispersystems/textsecure/storage/Record.java +++ b/library/src/org/whispersystems/textsecure/storage/Record.java @@ -30,7 +30,7 @@ import java.nio.channels.FileChannel; public abstract class Record { - protected static final String SESSIONS_DIRECTORY = "sessions"; + public static final String SESSIONS_DIRECTORY = "sessions"; protected static final String SESSIONS_DIRECTORY_V2 = "sessions-v2"; public static final String PREKEY_DIRECTORY = "prekeys"; @@ -48,7 +48,7 @@ public abstract class Record { delete(this.context, this.directory, this.address); } - protected static void delete(Context context, String directory, String address) { + public static void delete(Context context, String directory, String address) { getAddressFile(context, directory, address).delete(); } diff --git a/library/src/org/whispersystems/textsecure/storage/Session.java b/library/src/org/whispersystems/textsecure/storage/Session.java index 5bf5bb261..c47015484 100644 --- a/library/src/org/whispersystems/textsecure/storage/Session.java +++ b/library/src/org/whispersystems/textsecure/storage/Session.java @@ -3,8 +3,11 @@ package org.whispersystems.textsecure.storage; import android.content.Context; import android.util.Log; -import org.whispersystems.textsecure.crypto.IdentityKey; +import org.whispersystems.libaxolotl.IdentityKey; import org.whispersystems.textsecure.crypto.MasterSecret; +import org.whispersystems.textsecure.storage.legacy.LocalKeyRecord; +import org.whispersystems.textsecure.storage.legacy.RemoteKeyRecord; +import org.whispersystems.textsecure.storage.legacy.SessionRecordV1; /** * Helper class for generating key pairs and calculating ECDH agreements. diff --git a/library/src/org/whispersystems/textsecure/storage/SessionKey.java b/library/src/org/whispersystems/textsecure/storage/SessionKey.java deleted file mode 100644 index 05b24e7db..000000000 --- a/library/src/org/whispersystems/textsecure/storage/SessionKey.java +++ /dev/null @@ -1,115 +0,0 @@ -/** - * Copyright (C) 2011 Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.whispersystems.textsecure.storage; - -import org.whispersystems.textsecure.crypto.InvalidMessageException; -import org.whispersystems.textsecure.crypto.MasterCipher; -import org.whispersystems.textsecure.crypto.MasterSecret; -import org.whispersystems.textsecure.crypto.kdf.NKDF; -import org.whispersystems.textsecure.util.Conversions; -import org.whispersystems.textsecure.util.Util; - -import javax.crypto.spec.SecretKeySpec; - -/** - * Represents the currently negotiated session key for a given - * local key id and remote key id. This is stored encrypted on - * disk. - * - * @author Moxie Marlinspike - */ - -public class SessionKey { - - private int mode; - private int localKeyId; - private int remoteKeyId; - private SecretKeySpec cipherKey; - private SecretKeySpec macKey; - private MasterCipher masterCipher; - - public SessionKey(int mode, int localKeyId, int remoteKeyId, - SecretKeySpec cipherKey, SecretKeySpec macKey, - MasterSecret masterSecret) - { - this.mode = mode; - this.localKeyId = localKeyId; - this.remoteKeyId = remoteKeyId; - this.cipherKey = cipherKey; - this.macKey = macKey; - this.masterCipher = new MasterCipher(masterSecret); - } - - public SessionKey(byte[] bytes, MasterSecret masterSecret) throws InvalidMessageException { - this.masterCipher = new MasterCipher(masterSecret); - deserialize(bytes); - } - - public byte[] serialize() { - byte[] localKeyIdBytes = Conversions.mediumToByteArray(localKeyId); - byte[] remoteKeyIdBytes = Conversions.mediumToByteArray(remoteKeyId); - byte[] cipherKeyBytes = cipherKey.getEncoded(); - byte[] macKeyBytes = macKey.getEncoded(); - byte[] modeBytes = {(byte)mode}; - byte[] combined = Util.combine(localKeyIdBytes, remoteKeyIdBytes, - cipherKeyBytes, macKeyBytes, modeBytes); - - return masterCipher.encryptBytes(combined); - } - - private void deserialize(byte[] bytes) throws InvalidMessageException { - byte[] decrypted = masterCipher.decryptBytes(bytes); - - this.localKeyId = Conversions.byteArrayToMedium(decrypted, 0); - this.remoteKeyId = Conversions.byteArrayToMedium(decrypted, 3); - - byte[] keyBytes = new byte[NKDF.LEGACY_CIPHER_KEY_LENGTH]; - System.arraycopy(decrypted, 6, keyBytes, 0, keyBytes.length); - - byte[] macBytes = new byte[NKDF.LEGACY_MAC_KEY_LENGTH]; - System.arraycopy(decrypted, 6 + keyBytes.length, macBytes, 0, macBytes.length); - - if (decrypted.length < 6 + NKDF.LEGACY_CIPHER_KEY_LENGTH + NKDF.LEGACY_MAC_KEY_LENGTH + 1) { - throw new InvalidMessageException("No mode included"); - } - - this.mode = decrypted[6 + keyBytes.length + macBytes.length]; - - this.cipherKey = new SecretKeySpec(keyBytes, "AES"); - this.macKey = new SecretKeySpec(macBytes, "HmacSHA1"); - } - - public int getLocalKeyId() { - return this.localKeyId; - } - - public int getRemoteKeyId() { - return this.remoteKeyId; - } - - public SecretKeySpec getCipherKey() { - return this.cipherKey; - } - - public SecretKeySpec getMacKey() { - return this.macKey; - } - - public int getMode() { - return mode; - } -} diff --git a/library/src/org/whispersystems/textsecure/storage/SessionRecordV2.java b/library/src/org/whispersystems/textsecure/storage/SessionRecordV2.java index 46fec98a6..05d141833 100644 --- a/library/src/org/whispersystems/textsecure/storage/SessionRecordV2.java +++ b/library/src/org/whispersystems/textsecure/storage/SessionRecordV2.java @@ -19,7 +19,9 @@ package org.whispersystems.textsecure.storage; import android.content.Context; import android.util.Log; -import org.whispersystems.textsecure.crypto.InvalidMessageException; +import org.whispersystems.libaxolotl.InvalidMessageException; +import org.whispersystems.libaxolotl.SessionState; +import org.whispersystems.libaxolotl.SessionStore; import org.whispersystems.textsecure.crypto.MasterCipher; import org.whispersystems.textsecure.crypto.MasterSecret; @@ -41,7 +43,7 @@ import static org.whispersystems.textsecure.storage.StorageProtos.SessionStructu * @author Moxie Marlinspike */ -public class SessionRecordV2 extends Record { +public class SessionRecordV2 extends Record implements SessionStore { private static final Object FILE_LOCK = new Object(); @@ -51,8 +53,8 @@ public class SessionRecordV2 extends Record { private final MasterSecret masterSecret; - private SessionState sessionState = new SessionState(SessionStructure.newBuilder().build()); - private List previousStates = new LinkedList(); + private TextSecureSessionState sessionState = new TextSecureSessionState(SessionStructure.newBuilder().build()); + private List previousStates = new LinkedList(); public SessionRecordV2(Context context, MasterSecret masterSecret, RecipientDevice peer) { this(context, masterSecret, peer.getRecipientId(), peer.getDeviceId()); @@ -68,12 +70,12 @@ public class SessionRecordV2 extends Record { return recipientId + (deviceId == RecipientDevice.DEFAULT_DEVICE_ID ? "" : "." + deviceId); } - public SessionState getSessionState() { + public TextSecureSessionState getSessionState() { return sessionState; } - public List getPreviousSessions() { + public List getPreviousSessionStates() { return previousStates; } @@ -139,13 +141,13 @@ public class SessionRecordV2 extends Record { } public void clear() { - this.sessionState = new SessionState(SessionStructure.newBuilder().build()); + this.sessionState = new TextSecureSessionState(SessionStructure.newBuilder().build()); this.previousStates = new LinkedList(); } public void archiveCurrentState() { this.previousStates.add(sessionState); - this.sessionState = new SessionState(SessionStructure.newBuilder().build()); + this.sessionState = new TextSecureSessionState(SessionStructure.newBuilder().build()); } public void save() { @@ -154,7 +156,7 @@ public class SessionRecordV2 extends Record { List previousStructures = new LinkedList(); for (SessionState previousState : previousStates) { - previousStructures.add(previousState.getStructure()); + previousStructures.add(((TextSecureSessionState)previousState).getStructure()); } RecordStructure record = RecordStructure.newBuilder() @@ -194,16 +196,16 @@ public class SessionRecordV2 extends Record { if (versionMarker == SINGLE_STATE_VERSION) { byte[] plaintextBytes = cipher.decryptBytes(encryptedBlob); SessionStructure sessionStructure = SessionStructure.parseFrom(plaintextBytes); - this.sessionState = new SessionState(sessionStructure); + this.sessionState = new TextSecureSessionState(sessionStructure); } else if (versionMarker == ARCHIVE_STATES_VERSION) { byte[] plaintextBytes = cipher.decryptBytes(encryptedBlob); RecordStructure recordStructure = RecordStructure.parseFrom(plaintextBytes); - this.sessionState = new SessionState(recordStructure.getCurrentSession()); + this.sessionState = new TextSecureSessionState(recordStructure.getCurrentSession()); this.previousStates = new LinkedList(); for (SessionStructure sessionStructure : recordStructure.getPreviousSessionsList()) { - this.previousStates.add(new SessionState(sessionStructure)); + this.previousStates.add(new TextSecureSessionState(sessionStructure)); } } else { throw new AssertionError("Unknown version: " + versionMarker); @@ -217,8 +219,9 @@ public class SessionRecordV2 extends Record { } catch (IOException ioe) { Log.w("SessionRecordV2", ioe); // XXX - } catch (InvalidMessageException e) { - Log.w("SessionRecordV2", e); + } catch (InvalidMessageException ime) { + Log.w("SessionRecordV2", ime); + // XXX } } } diff --git a/library/src/org/whispersystems/textsecure/storage/SessionState.java b/library/src/org/whispersystems/textsecure/storage/TextSecureSessionState.java similarity index 90% rename from library/src/org/whispersystems/textsecure/storage/SessionState.java rename to library/src/org/whispersystems/textsecure/storage/TextSecureSessionState.java index 9ddc009d6..f5a317bba 100644 --- a/library/src/org/whispersystems/textsecure/storage/SessionState.java +++ b/library/src/org/whispersystems/textsecure/storage/TextSecureSessionState.java @@ -1,20 +1,37 @@ +/** + * Copyright (C) 2014 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.whispersystems.textsecure.storage; import android.util.Log; -import android.util.Pair; import com.google.protobuf.ByteString; -import org.whispersystems.textsecure.crypto.IdentityKey; -import org.whispersystems.textsecure.crypto.IdentityKeyPair; -import org.whispersystems.textsecure.crypto.InvalidKeyException; -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECKeyPair; -import org.whispersystems.textsecure.crypto.ecc.ECPrivateKey; -import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; -import org.whispersystems.textsecure.crypto.ratchet.ChainKey; -import org.whispersystems.textsecure.crypto.ratchet.MessageKeys; -import org.whispersystems.textsecure.crypto.ratchet.RootKey; +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.libaxolotl.IdentityKeyPair; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.SessionState; +import org.whispersystems.libaxolotl.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECKeyPair; +import org.whispersystems.libaxolotl.ecc.ECPrivateKey; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; +import org.whispersystems.libaxolotl.ratchet.ChainKey; +import org.whispersystems.libaxolotl.ratchet.MessageKeys; +import org.whispersystems.libaxolotl.ratchet.RootKey; +import org.whispersystems.libaxolotl.util.Pair; import org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain; import org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange; import org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey; @@ -27,11 +44,11 @@ import javax.crypto.spec.SecretKeySpec; import static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure; -public class SessionState { +public class TextSecureSessionState implements SessionState { private SessionStructure sessionStructure; - public SessionState(SessionStructure sessionStructure) { + public TextSecureSessionState(SessionStructure sessionStructure) { this.sessionStructure = sessionStructure; } @@ -160,7 +177,7 @@ public class SessionState { public ChainKey getReceiverChainKey(ECPublicKey senderEphemeral) { Pair receiverChainAndIndex = getReceiverChain(senderEphemeral); - Chain receiverChain = receiverChainAndIndex.first; + Chain receiverChain = receiverChainAndIndex.first(); if (receiverChain == null) { return null; @@ -225,7 +242,7 @@ public class SessionState { public boolean hasMessageKeys(ECPublicKey senderEphemeral, int counter) { Pair chainAndIndex = getReceiverChain(senderEphemeral); - Chain chain = chainAndIndex.first; + Chain chain = chainAndIndex.first(); if (chain == null) { return false; @@ -244,7 +261,7 @@ public class SessionState { public MessageKeys removeMessageKeys(ECPublicKey senderEphemeral, int counter) { Pair chainAndIndex = getReceiverChain(senderEphemeral); - Chain chain = chainAndIndex.first; + Chain chain = chainAndIndex.first(); if (chain == null) { return null; @@ -272,7 +289,7 @@ public class SessionState { .build(); this.sessionStructure = this.sessionStructure.toBuilder() - .setReceiverChains(chainAndIndex.second, updatedChain) + .setReceiverChains(chainAndIndex.second(), updatedChain) .build(); return result; @@ -280,7 +297,7 @@ public class SessionState { public void setMessageKeys(ECPublicKey senderEphemeral, MessageKeys messageKeys) { Pair chainAndIndex = getReceiverChain(senderEphemeral); - Chain chain = chainAndIndex.first; + Chain chain = chainAndIndex.first(); Chain.MessageKey messageKeyStructure = Chain.MessageKey.newBuilder() .setCipherKey(ByteString.copyFrom(messageKeys.getCipherKey().getEncoded())) .setMacKey(ByteString.copyFrom(messageKeys.getMacKey().getEncoded())) @@ -292,13 +309,13 @@ public class SessionState { .build(); this.sessionStructure = this.sessionStructure.toBuilder() - .setReceiverChains(chainAndIndex.second, updatedChain) + .setReceiverChains(chainAndIndex.second(), updatedChain) .build(); } public void setReceiverChainKey(ECPublicKey senderEphemeral, ChainKey chainKey) { Pair chainAndIndex = getReceiverChain(senderEphemeral); - Chain chain = chainAndIndex.first; + Chain chain = chainAndIndex.first(); Chain.ChainKey chainKeyStructure = Chain.ChainKey.newBuilder() .setKey(ByteString.copyFrom(chainKey.getKey())) @@ -308,7 +325,7 @@ public class SessionState { Chain updatedChain = chain.toBuilder().setChainKey(chainKeyStructure).build(); this.sessionStructure = this.sessionStructure.toBuilder() - .setReceiverChains(chainAndIndex.second, updatedChain) + .setReceiverChains(chainAndIndex.second(), updatedChain) .build(); } diff --git a/library/src/org/whispersystems/textsecure/storage/LocalKeyRecord.java b/library/src/org/whispersystems/textsecure/storage/legacy/LocalKeyRecord.java similarity index 86% rename from library/src/org/whispersystems/textsecure/storage/LocalKeyRecord.java rename to library/src/org/whispersystems/textsecure/storage/legacy/LocalKeyRecord.java index a3d4714ba..cea52de04 100644 --- a/library/src/org/whispersystems/textsecure/storage/LocalKeyRecord.java +++ b/library/src/org/whispersystems/textsecure/storage/legacy/LocalKeyRecord.java @@ -15,10 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package org.whispersystems.textsecure.storage; +package org.whispersystems.textsecure.storage.legacy; import android.content.Context; +import org.whispersystems.textsecure.storage.CanonicalRecipient; +import org.whispersystems.textsecure.storage.Record; + public class LocalKeyRecord { public static void delete(Context context, CanonicalRecipient recipient) { diff --git a/library/src/org/whispersystems/textsecure/storage/RemoteKeyRecord.java b/library/src/org/whispersystems/textsecure/storage/legacy/RemoteKeyRecord.java similarity index 73% rename from library/src/org/whispersystems/textsecure/storage/RemoteKeyRecord.java rename to library/src/org/whispersystems/textsecure/storage/legacy/RemoteKeyRecord.java index 1cc5ff5a5..89563d392 100644 --- a/library/src/org/whispersystems/textsecure/storage/RemoteKeyRecord.java +++ b/library/src/org/whispersystems/textsecure/storage/legacy/RemoteKeyRecord.java @@ -14,21 +14,12 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package org.whispersystems.textsecure.storage; +package org.whispersystems.textsecure.storage.legacy; import android.content.Context; -import android.util.Log; -import org.whispersystems.textsecure.crypto.InvalidKeyException; -import org.whispersystems.textsecure.crypto.PublicKey; -import org.whispersystems.textsecure.util.Hex; -import org.whispersystems.textsecure.util.Medium; - -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.nio.channels.FileChannel; +import org.whispersystems.textsecure.storage.CanonicalRecipient; +import org.whispersystems.textsecure.storage.Record; /** * Represents the current and last public key belonging to the "remote" diff --git a/library/src/org/whispersystems/textsecure/storage/SessionRecordV1.java b/library/src/org/whispersystems/textsecure/storage/legacy/SessionRecordV1.java similarity index 65% rename from library/src/org/whispersystems/textsecure/storage/SessionRecordV1.java rename to library/src/org/whispersystems/textsecure/storage/legacy/SessionRecordV1.java index 7edca3e7f..c85c9c1ee 100644 --- a/library/src/org/whispersystems/textsecure/storage/SessionRecordV1.java +++ b/library/src/org/whispersystems/textsecure/storage/legacy/SessionRecordV1.java @@ -1,7 +1,10 @@ -package org.whispersystems.textsecure.storage; +package org.whispersystems.textsecure.storage.legacy; import android.content.Context; +import org.whispersystems.textsecure.storage.CanonicalRecipient; +import org.whispersystems.textsecure.storage.Record; + /** * A disk record representing a current session. * diff --git a/settings.gradle b/settings.gradle index d8f14a134..7caf8cfc8 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':library' +include ':library', ':libaxolotl' diff --git a/src/org/thoughtcrime/securesms/ConversationActivity.java b/src/org/thoughtcrime/securesms/ConversationActivity.java index d73f4d43d..9d8541ee5 100644 --- a/src/org/thoughtcrime/securesms/ConversationActivity.java +++ b/src/org/thoughtcrime/securesms/ConversationActivity.java @@ -102,7 +102,7 @@ import org.thoughtcrime.securesms.util.EncryptedCharacterCalculator; import org.thoughtcrime.securesms.util.GroupUtil; import org.thoughtcrime.securesms.util.MemoryCleaner; import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.whispersystems.textsecure.crypto.InvalidMessageException; +import org.whispersystems.libaxolotl.InvalidMessageException; import org.whispersystems.textsecure.crypto.MasterCipher; import org.whispersystems.textsecure.crypto.MasterSecret; import org.whispersystems.textsecure.storage.RecipientDevice; diff --git a/src/org/thoughtcrime/securesms/KeyScanningActivity.java b/src/org/thoughtcrime/securesms/KeyScanningActivity.java index 020a62f29..fe29b0579 100644 --- a/src/org/thoughtcrime/securesms/KeyScanningActivity.java +++ b/src/org/thoughtcrime/securesms/KeyScanningActivity.java @@ -20,7 +20,7 @@ import android.content.Intent; import android.os.Bundle; import android.widget.Toast; -import org.whispersystems.textsecure.crypto.SerializableKey; +import org.whispersystems.libaxolotl.IdentityKey; import org.whispersystems.textsecure.util.Base64; import org.thoughtcrime.securesms.util.Dialogs; import org.thoughtcrime.securesms.util.DynamicTheme; @@ -112,8 +112,8 @@ public abstract class KeyScanningActivity extends PassphraseRequiredSherlockActi protected abstract String getNotVerifiedTitle(); protected abstract String getNotVerifiedMessage(); - protected abstract SerializableKey getIdentityKeyToCompare(); - protected abstract SerializableKey getIdentityKeyToDisplay(); + protected abstract IdentityKey getIdentityKeyToCompare(); + protected abstract IdentityKey getIdentityKeyToDisplay(); protected abstract String getVerifiedTitle(); protected abstract String getVerifiedMessage(); diff --git a/src/org/thoughtcrime/securesms/ReceiveKeyActivity.java b/src/org/thoughtcrime/securesms/ReceiveKeyActivity.java index d53e988c2..ce6b07ba0 100644 --- a/src/org/thoughtcrime/securesms/ReceiveKeyActivity.java +++ b/src/org/thoughtcrime/securesms/ReceiveKeyActivity.java @@ -34,20 +34,21 @@ import org.thoughtcrime.securesms.crypto.DecryptingQueue; import org.thoughtcrime.securesms.crypto.KeyExchangeProcessor; import org.thoughtcrime.securesms.crypto.KeyExchangeProcessorV2; import org.thoughtcrime.securesms.crypto.protocol.KeyExchangeMessage; -import org.whispersystems.textsecure.crypto.LegacyMessageException; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.service.SendReceiveService; import org.thoughtcrime.securesms.sms.SmsTransportDetails; import org.thoughtcrime.securesms.util.MemoryCleaner; import org.thoughtcrime.securesms.util.Util; -import org.whispersystems.textsecure.crypto.IdentityKey; -import org.whispersystems.textsecure.crypto.InvalidKeyException; -import org.whispersystems.textsecure.crypto.InvalidMessageException; -import org.whispersystems.textsecure.crypto.InvalidVersionException; +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.InvalidMessageException; +import org.whispersystems.libaxolotl.InvalidVersionException; +import org.whispersystems.libaxolotl.LegacyMessageException; +import org.whispersystems.libaxolotl.protocol.CiphertextMessage; +import org.whispersystems.libaxolotl.protocol.PreKeyWhisperMessage; +import org.whispersystems.textsecure.crypto.IdentityKeyParcelable; import org.whispersystems.textsecure.crypto.MasterSecret; -import org.whispersystems.textsecure.crypto.protocol.CiphertextMessage; -import org.whispersystems.textsecure.crypto.protocol.PreKeyWhisperMessage; import org.whispersystems.textsecure.push.IncomingPushMessage; import org.whispersystems.textsecure.storage.InvalidKeyIdException; import org.whispersystems.textsecure.storage.RecipientDevice; @@ -136,7 +137,7 @@ public class ReceiveKeyActivity extends Activity { Intent intent = new Intent(ReceiveKeyActivity.this, VerifyIdentityActivity.class); intent.putExtra("recipient", recipient); intent.putExtra("master_secret", masterSecret); - intent.putExtra("remote_identity", remoteIdentity); + intent.putExtra("remote_identity", new IdentityKeyParcelable(remoteIdentity)); startActivity(intent); } }, getString(R.string.ReceiveKeyActivity_the_signature_on_this_key_exchange_is_different).length() +1, diff --git a/src/org/thoughtcrime/securesms/VerifyIdentityActivity.java b/src/org/thoughtcrime/securesms/VerifyIdentityActivity.java index ef89115d9..66eaa5db3 100644 --- a/src/org/thoughtcrime/securesms/VerifyIdentityActivity.java +++ b/src/org/thoughtcrime/securesms/VerifyIdentityActivity.java @@ -26,7 +26,8 @@ import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.DynamicLanguage; import org.thoughtcrime.securesms.util.DynamicTheme; import org.thoughtcrime.securesms.util.MemoryCleaner; -import org.whispersystems.textsecure.crypto.IdentityKey; +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.textsecure.crypto.IdentityKeyParcelable; import org.whispersystems.textsecure.crypto.MasterSecret; import org.whispersystems.textsecure.storage.Session; @@ -83,7 +84,12 @@ public class VerifyIdentityActivity extends KeyScanningActivity { } private void initializeRemoteIdentityKey() { - IdentityKey identityKey = getIntent().getParcelableExtra("remote_identity"); + IdentityKeyParcelable identityKeyParcelable = getIntent().getParcelableExtra("remote_identity"); + IdentityKey identityKey = null; + + if (identityKeyParcelable != null) { + identityKey = identityKeyParcelable.get(); + } if (identityKey == null) { identityKey = Session.getRemoteIdentityKey(this, masterSecret, recipient); diff --git a/src/org/thoughtcrime/securesms/ViewIdentityActivity.java b/src/org/thoughtcrime/securesms/ViewIdentityActivity.java index 4db357f14..a919f1190 100644 --- a/src/org/thoughtcrime/securesms/ViewIdentityActivity.java +++ b/src/org/thoughtcrime/securesms/ViewIdentityActivity.java @@ -19,7 +19,8 @@ package org.thoughtcrime.securesms; import android.os.Bundle; import android.widget.TextView; -import org.whispersystems.textsecure.crypto.IdentityKey; +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.textsecure.crypto.IdentityKeyParcelable; /** * Activity for displaying an identity key. @@ -28,6 +29,9 @@ import org.whispersystems.textsecure.crypto.IdentityKey; */ public class ViewIdentityActivity extends KeyScanningActivity { + public static final String IDENTITY_KEY = "identity_key"; + public static final String TITLE = "title"; + private TextView identityFingerprint; private IdentityKey identityKey; @@ -54,12 +58,18 @@ public class ViewIdentityActivity extends KeyScanningActivity { } private void initializeResources() { - this.identityKey = (IdentityKey)getIntent().getParcelableExtra("identity_key"); + IdentityKeyParcelable identityKeyParcelable = getIntent().getParcelableExtra(IDENTITY_KEY); + + if (identityKeyParcelable == null) { + throw new AssertionError("No identity key!"); + } + + this.identityKey = identityKeyParcelable.get(); this.identityFingerprint = (TextView)findViewById(R.id.identity_fingerprint); - String title = getIntent().getStringExtra("title"); + String title = getIntent().getStringExtra(TITLE); if (title != null) { - getSupportActionBar().setTitle(getIntent().getStringExtra("title")); + getSupportActionBar().setTitle(getIntent().getStringExtra(TITLE)); } } diff --git a/src/org/thoughtcrime/securesms/ViewLocalIdentityActivity.java b/src/org/thoughtcrime/securesms/ViewLocalIdentityActivity.java index 4a0cf56e4..87a39bc7f 100644 --- a/src/org/thoughtcrime/securesms/ViewLocalIdentityActivity.java +++ b/src/org/thoughtcrime/securesms/ViewLocalIdentityActivity.java @@ -17,20 +17,14 @@ */ package org.thoughtcrime.securesms; -import android.app.AlertDialog; -import android.app.ProgressDialog; -import android.content.DialogInterface; -import android.os.AsyncTask; import android.os.Bundle; -import android.widget.Toast; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuInflater; import com.actionbarsherlock.view.MenuItem; import org.thoughtcrime.securesms.crypto.IdentityKeyUtil; -import org.thoughtcrime.securesms.util.Dialogs; -import org.whispersystems.textsecure.crypto.MasterSecret; +import org.whispersystems.textsecure.crypto.IdentityKeyParcelable; /** * Activity that displays the local identity key and offers the option to regenerate it. @@ -39,13 +33,11 @@ import org.whispersystems.textsecure.crypto.MasterSecret; */ public class ViewLocalIdentityActivity extends ViewIdentityActivity { - private MasterSecret masterSecret; - public void onCreate(Bundle bundle) { - this.masterSecret = getIntent().getParcelableExtra("master_secret"); - - getIntent().putExtra("identity_key", IdentityKeyUtil.getIdentityKey(this)); - getIntent().putExtra("title", getString(R.string.ViewIdentityActivity_my_identity_fingerprint)); + getIntent().putExtra(ViewIdentityActivity.IDENTITY_KEY, + new IdentityKeyParcelable(IdentityKeyUtil.getIdentityKey(this))); + getIntent().putExtra(ViewIdentityActivity.TITLE, + getString(R.string.ViewIdentityActivity_my_identity_fingerprint)); super.onCreate(bundle); } @@ -64,62 +56,9 @@ public class ViewLocalIdentityActivity extends ViewIdentityActivity { super.onOptionsItemSelected(item); switch (item.getItemId()) { -// case R.id.menu_regenerate_key: promptToRegenerateIdentityKey(); return true; - case android.R.id.home: finish(); return true; + case android.R.id.home:finish(); return true; } return false; } - - private void promptToRegenerateIdentityKey() { - AlertDialog.Builder dialog = new AlertDialog.Builder(this); - dialog.setIcon(Dialogs.resolveIcon(this, R.attr.dialog_alert_icon)); - dialog.setTitle(getString(R.string.ViewLocalIdentityActivity_reset_identity_key)); - dialog.setMessage(getString(R.string.ViewLocalIdentityActivity_by_regenerating_your_identity_key_your_existing_contacts_will_receive_warnings)); - dialog.setNegativeButton(getString(R.string.ViewLocalIdentityActivity_cancel), null); - dialog.setPositiveButton(getString(R.string.ViewLocalIdentityActivity_continue), - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - regenerateIdentityKey(); - } - }); - dialog.show(); - } - - private void regenerateIdentityKey() { - new AsyncTask() { - private ProgressDialog progressDialog; - - @Override - protected void onPreExecute() { - progressDialog = ProgressDialog.show(ViewLocalIdentityActivity.this, - getString(R.string.ViewLocalIdentityActivity_regenerating), - getString(R.string.ViewLocalIdentityActivity_regenerating_identity_key), - true, false); - } - - @Override - public Void doInBackground(Void... params) { - IdentityKeyUtil.generateIdentityKeys(ViewLocalIdentityActivity.this, masterSecret); - return null; - } - - @Override - protected void onPostExecute(Void result) { - if (progressDialog != null) - progressDialog.dismiss(); - - Toast.makeText(ViewLocalIdentityActivity.this, - getString(R.string.ViewLocalIdentityActivity_regenerated), - Toast.LENGTH_LONG).show(); - - getIntent().putExtra("identity_key", - IdentityKeyUtil.getIdentityKey(ViewLocalIdentityActivity.this)); - initialize(); - } - - }.execute(); - } - } diff --git a/src/org/thoughtcrime/securesms/contacts/ContactAccessor.java b/src/org/thoughtcrime/securesms/contacts/ContactAccessor.java index 03b5addd1..1d20354de 100644 --- a/src/org/thoughtcrime/securesms/contacts/ContactAccessor.java +++ b/src/org/thoughtcrime/securesms/contacts/ContactAccessor.java @@ -17,7 +17,6 @@ package org.thoughtcrime.securesms.contacts; import android.content.ContentResolver; -import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.MergeCursor; @@ -25,7 +24,6 @@ import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; import android.provider.ContactsContract; -import android.provider.ContactsContract.CommonDataKinds.Im; import android.provider.ContactsContract.CommonDataKinds.Phone; import android.provider.ContactsContract.Contacts; import android.provider.ContactsContract.Data; @@ -33,15 +31,9 @@ import android.provider.ContactsContract.PhoneLookup; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; import android.telephony.PhoneNumberUtils; -import android.util.Log; -import org.whispersystems.textsecure.crypto.IdentityKey; -import org.whispersystems.textsecure.crypto.InvalidKeyException; import org.whispersystems.textsecure.directory.Directory; -import org.whispersystems.textsecure.util.Base64; -import java.io.IOException; -import java.lang.Long; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedList; @@ -248,49 +240,6 @@ public class ContactAccessor { return Phone.getTypeLabel(mContext.getResources(), type, label); } - public void insertIdentityKey(Context context, List rawContactIds, IdentityKey identityKey) { - for (long rawContactId : rawContactIds) { - Log.w("ContactAccessorNewApi", "Inserting data for raw contact id: " + rawContactId); - ContentValues contentValues = new ContentValues(); - contentValues.put(Data.RAW_CONTACT_ID, rawContactId); - contentValues.put(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE); - contentValues.put(Im.PROTOCOL, Im.PROTOCOL_CUSTOM); - contentValues.put(Im.CUSTOM_PROTOCOL, "TextSecure-IdentityKey"); - contentValues.put(Im.DATA, Base64.encodeBytes(identityKey.serialize())); - - context.getContentResolver().insert(Data.CONTENT_URI, contentValues); - } - } - - public IdentityKey importIdentityKey(Context context, Uri uri) { - long contactId = getContactIdFromLookupUri(context, uri); - String selection = Im.CONTACT_ID + " = ? AND " + Im.PROTOCOL + " = ? AND " + Im.CUSTOM_PROTOCOL + " = ?"; - String[] selectionArgs = new String[] {contactId+"", Im.PROTOCOL_CUSTOM+"", "TextSecure-IdentityKey"}; - - Cursor cursor = context.getContentResolver().query(Data.CONTENT_URI, null, selection, selectionArgs, null); - - try { - if (cursor != null && cursor.moveToFirst()) { - String data = cursor.getString(cursor.getColumnIndexOrThrow(Im.DATA)); - - if (data != null) - return new IdentityKey(Base64.decode(data), 0); - - } - } catch (InvalidKeyException e) { - Log.w("ContactAccessorNewApi", e); - return null; - } catch (IOException e) { - Log.w("ContactAccessorNewApi", e); - return null; - } finally { - if (cursor != null) - cursor.close(); - } - - return null; - } - private long getContactIdFromLookupUri(Context context, Uri uri) { Cursor cursor = null; diff --git a/src/org/thoughtcrime/securesms/crypto/AsymmetricMasterCipher.java b/src/org/thoughtcrime/securesms/crypto/AsymmetricMasterCipher.java index 2e0d05b86..a60cf7388 100644 --- a/src/org/thoughtcrime/securesms/crypto/AsymmetricMasterCipher.java +++ b/src/org/thoughtcrime/securesms/crypto/AsymmetricMasterCipher.java @@ -17,15 +17,15 @@ */ package org.thoughtcrime.securesms.crypto; -import org.whispersystems.textsecure.crypto.InvalidKeyException; -import org.whispersystems.textsecure.crypto.InvalidMessageException; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.InvalidMessageException; +import org.whispersystems.libaxolotl.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECKeyPair; +import org.whispersystems.libaxolotl.ecc.ECPrivateKey; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; import org.whispersystems.textsecure.crypto.MasterCipher; import org.whispersystems.textsecure.crypto.MasterSecret; import org.whispersystems.textsecure.crypto.PublicKey; -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECKeyPair; -import org.whispersystems.textsecure.crypto.ecc.ECPrivateKey; -import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; import org.whispersystems.textsecure.util.Base64; import org.whispersystems.textsecure.util.Conversions; import org.whispersystems.textsecure.util.Util; diff --git a/src/org/thoughtcrime/securesms/crypto/AsymmetricMasterSecret.java b/src/org/thoughtcrime/securesms/crypto/AsymmetricMasterSecret.java index 1f620be74..bc82032e3 100644 --- a/src/org/thoughtcrime/securesms/crypto/AsymmetricMasterSecret.java +++ b/src/org/thoughtcrime/securesms/crypto/AsymmetricMasterSecret.java @@ -17,9 +17,8 @@ */ package org.thoughtcrime.securesms.crypto; -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECPrivateKey; -import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; +import org.whispersystems.libaxolotl.ecc.ECPrivateKey; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; /** * When a user first initializes TextSecure, a few secrets @@ -40,7 +39,7 @@ import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; public class AsymmetricMasterSecret { - private final ECPublicKey djbPublicKey; + private final ECPublicKey djbPublicKey; private final ECPrivateKey djbPrivateKey; diff --git a/src/org/thoughtcrime/securesms/crypto/DecryptingQueue.java b/src/org/thoughtcrime/securesms/crypto/DecryptingQueue.java index 36955d91e..6af3ed5e6 100644 --- a/src/org/thoughtcrime/securesms/crypto/DecryptingQueue.java +++ b/src/org/thoughtcrime/securesms/crypto/DecryptingQueue.java @@ -23,7 +23,6 @@ import android.database.Cursor; import android.util.Log; import org.thoughtcrime.securesms.crypto.protocol.KeyExchangeMessage; -import org.whispersystems.textsecure.crypto.LegacyMessageException; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.EncryptingSmsDatabase; import org.thoughtcrime.securesms.database.MmsDatabase; @@ -41,13 +40,15 @@ import org.thoughtcrime.securesms.service.PushReceiver; import org.thoughtcrime.securesms.service.SendReceiveService; import org.thoughtcrime.securesms.sms.SmsTransportDetails; import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.whispersystems.textsecure.crypto.DuplicateMessageException; -import org.whispersystems.textsecure.crypto.InvalidKeyException; -import org.whispersystems.textsecure.crypto.InvalidMessageException; -import org.whispersystems.textsecure.crypto.InvalidVersionException; +import org.whispersystems.libaxolotl.DuplicateMessageException; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.InvalidMessageException; +import org.whispersystems.libaxolotl.InvalidVersionException; +import org.whispersystems.libaxolotl.LegacyMessageException; +import org.whispersystems.libaxolotl.SessionCipher; +import org.whispersystems.libaxolotl.protocol.WhisperMessage; import org.whispersystems.textsecure.crypto.MasterSecret; -import org.whispersystems.textsecure.crypto.SessionCipher; -import org.whispersystems.textsecure.crypto.protocol.WhisperMessage; +import org.whispersystems.textsecure.crypto.SessionCipherFactory; import org.whispersystems.textsecure.push.IncomingPushMessage; import org.whispersystems.textsecure.storage.RecipientDevice; import org.whispersystems.textsecure.storage.Session; @@ -205,7 +206,7 @@ public class DecryptingQueue { return; } - SessionCipher sessionCipher = SessionCipher.createFor(context, masterSecret, recipientDevice); + SessionCipher sessionCipher = SessionCipherFactory.getInstance(context, masterSecret, recipientDevice); byte[] plaintextBody = sessionCipher.decrypt(message.getBody()); message = message.withBody(plaintextBody); @@ -290,7 +291,7 @@ public class DecryptingQueue { Log.w("DecryptingQueue", "Decrypting: " + Hex.toString(ciphertextPduBytes)); TextTransport transportDetails = new TextTransport(); - SessionCipher sessionCipher = SessionCipher.createFor(context, masterSecret, recipientDevice); + SessionCipher sessionCipher = SessionCipherFactory.getInstance(context, masterSecret, recipientDevice); byte[] decodedCiphertext = transportDetails.getDecodedMessage(ciphertextPduBytes); try { @@ -385,7 +386,7 @@ public class DecryptingQueue { return; } - SessionCipher sessionCipher = SessionCipher.createFor(context, masterSecret, recipientDevice); + SessionCipher sessionCipher = SessionCipherFactory.getInstance(context, masterSecret, recipientDevice); byte[] paddedPlaintext = sessionCipher.decrypt(decodedCiphertext); plaintextBody = new String(transportDetails.getStrippedPaddingMessageBody(paddedPlaintext)); diff --git a/src/org/thoughtcrime/securesms/crypto/IdentityKeyUtil.java b/src/org/thoughtcrime/securesms/crypto/IdentityKeyUtil.java index 9c5832ae8..482873d1b 100644 --- a/src/org/thoughtcrime/securesms/crypto/IdentityKeyUtil.java +++ b/src/org/thoughtcrime/securesms/crypto/IdentityKeyUtil.java @@ -22,14 +22,14 @@ import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.util.Log; -import org.whispersystems.textsecure.crypto.IdentityKey; -import org.whispersystems.textsecure.crypto.IdentityKeyPair; -import org.whispersystems.textsecure.crypto.InvalidKeyException; +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.libaxolotl.IdentityKeyPair; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECKeyPair; +import org.whispersystems.libaxolotl.ecc.ECPrivateKey; import org.whispersystems.textsecure.crypto.MasterCipher; import org.whispersystems.textsecure.crypto.MasterSecret; -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECKeyPair; -import org.whispersystems.textsecure.crypto.ecc.ECPrivateKey; import org.whispersystems.textsecure.util.Base64; import java.io.IOException; diff --git a/src/org/thoughtcrime/securesms/crypto/KeyExchangeInitiator.java b/src/org/thoughtcrime/securesms/crypto/KeyExchangeInitiator.java index 6921f05e6..979f19c04 100644 --- a/src/org/thoughtcrime/securesms/crypto/KeyExchangeInitiator.java +++ b/src/org/thoughtcrime/securesms/crypto/KeyExchangeInitiator.java @@ -27,10 +27,10 @@ import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.sms.MessageSender; import org.thoughtcrime.securesms.sms.OutgoingKeyExchangeMessage; import org.thoughtcrime.securesms.util.Dialogs; -import org.whispersystems.textsecure.crypto.IdentityKeyPair; +import org.whispersystems.libaxolotl.IdentityKeyPair; +import org.whispersystems.libaxolotl.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECKeyPair; import org.whispersystems.textsecure.crypto.MasterSecret; -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECKeyPair; import org.whispersystems.textsecure.storage.RecipientDevice; import org.whispersystems.textsecure.storage.SessionRecordV2; diff --git a/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessor.java b/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessor.java index ba1d23dd9..165e95726 100644 --- a/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessor.java +++ b/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessor.java @@ -21,10 +21,8 @@ import android.content.Context; import android.content.Intent; import org.thoughtcrime.securesms.crypto.protocol.KeyExchangeMessage; -import org.thoughtcrime.securesms.recipients.Recipient; -import org.thoughtcrime.securesms.recipients.RecipientFactory; import org.thoughtcrime.securesms.service.KeyCachingService; -import org.whispersystems.textsecure.crypto.InvalidMessageException; +import org.whispersystems.libaxolotl.InvalidMessageException; import org.whispersystems.textsecure.crypto.MasterSecret; import org.whispersystems.textsecure.storage.RecipientDevice; diff --git a/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessorV2.java b/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessorV2.java index e8bae0820..36477fa17 100644 --- a/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessorV2.java +++ b/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessorV2.java @@ -12,16 +12,16 @@ import org.thoughtcrime.securesms.service.PreKeyService; import org.thoughtcrime.securesms.sms.MessageSender; import org.thoughtcrime.securesms.sms.OutgoingKeyExchangeMessage; import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.whispersystems.textsecure.crypto.IdentityKey; -import org.whispersystems.textsecure.crypto.IdentityKeyPair; -import org.whispersystems.textsecure.crypto.InvalidKeyException; -import org.whispersystems.textsecure.crypto.InvalidMessageException; +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.libaxolotl.IdentityKeyPair; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.InvalidMessageException; +import org.whispersystems.libaxolotl.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECKeyPair; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; +import org.whispersystems.libaxolotl.protocol.PreKeyWhisperMessage; +import org.whispersystems.libaxolotl.ratchet.RatchetingSession; import org.whispersystems.textsecure.crypto.MasterSecret; -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECKeyPair; -import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; -import org.whispersystems.textsecure.crypto.protocol.PreKeyWhisperMessage; -import org.whispersystems.textsecure.crypto.ratchet.RatchetingSession; import org.whispersystems.textsecure.push.PreKeyEntity; import org.whispersystems.textsecure.storage.InvalidKeyIdException; import org.whispersystems.textsecure.storage.PreKeyRecord; diff --git a/src/org/thoughtcrime/securesms/crypto/MasterSecretUtil.java b/src/org/thoughtcrime/securesms/crypto/MasterSecretUtil.java index 231588a07..02c1032fa 100644 --- a/src/org/thoughtcrime/securesms/crypto/MasterSecretUtil.java +++ b/src/org/thoughtcrime/securesms/crypto/MasterSecretUtil.java @@ -21,13 +21,13 @@ import android.content.Context; import android.content.SharedPreferences; import android.util.Log; -import org.whispersystems.textsecure.crypto.InvalidKeyException; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECKeyPair; +import org.whispersystems.libaxolotl.ecc.ECPrivateKey; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; import org.whispersystems.textsecure.crypto.MasterCipher; import org.whispersystems.textsecure.crypto.MasterSecret; -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECKeyPair; -import org.whispersystems.textsecure.crypto.ecc.ECPrivateKey; -import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; import org.whispersystems.textsecure.util.Base64; import org.whispersystems.textsecure.util.Util; @@ -129,8 +129,8 @@ public class MasterSecretUtil { byte[] djbPublicBytes = retrieve(context, ASYMMETRIC_LOCAL_PUBLIC_DJB); byte[] djbPrivateBytes = retrieve(context, ASYMMETRIC_LOCAL_PRIVATE_DJB); - ECPublicKey djbPublicKey = null; - ECPrivateKey djbPrivateKey = null; + ECPublicKey djbPublicKey = null; + ECPrivateKey djbPrivateKey = null; if (djbPublicBytes != null) { djbPublicKey = Curve.decodePoint(djbPublicBytes, 0); diff --git a/src/org/thoughtcrime/securesms/crypto/protocol/KeyExchangeMessage.java b/src/org/thoughtcrime/securesms/crypto/protocol/KeyExchangeMessage.java index df3cdb474..beef2064e 100644 --- a/src/org/thoughtcrime/securesms/crypto/protocol/KeyExchangeMessage.java +++ b/src/org/thoughtcrime/securesms/crypto/protocol/KeyExchangeMessage.java @@ -17,12 +17,12 @@ */ package org.thoughtcrime.securesms.crypto.protocol; -import org.whispersystems.textsecure.crypto.IdentityKey; -import org.whispersystems.textsecure.crypto.InvalidKeyException; -import org.whispersystems.textsecure.crypto.InvalidMessageException; -import org.whispersystems.textsecure.crypto.InvalidVersionException; -import org.whispersystems.textsecure.crypto.LegacyMessageException; +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.InvalidMessageException; +import org.whispersystems.libaxolotl.InvalidVersionException; +import org.whispersystems.libaxolotl.LegacyMessageException; public abstract class KeyExchangeMessage { public abstract IdentityKey getIdentityKey(); diff --git a/src/org/thoughtcrime/securesms/crypto/protocol/KeyExchangeMessageV2.java b/src/org/thoughtcrime/securesms/crypto/protocol/KeyExchangeMessageV2.java index 32f67b911..c8b74459f 100644 --- a/src/org/thoughtcrime/securesms/crypto/protocol/KeyExchangeMessageV2.java +++ b/src/org/thoughtcrime/securesms/crypto/protocol/KeyExchangeMessageV2.java @@ -3,15 +3,15 @@ package org.thoughtcrime.securesms.crypto.protocol; import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; -import org.whispersystems.textsecure.crypto.IdentityKey; -import org.whispersystems.textsecure.crypto.InvalidKeyException; -import org.whispersystems.textsecure.crypto.InvalidMessageException; -import org.whispersystems.textsecure.crypto.InvalidVersionException; -import org.whispersystems.textsecure.crypto.LegacyMessageException; -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; -import org.whispersystems.textsecure.crypto.protocol.CiphertextMessage; -import org.whispersystems.textsecure.crypto.protocol.WhisperProtos; +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.InvalidMessageException; +import org.whispersystems.libaxolotl.InvalidVersionException; +import org.whispersystems.libaxolotl.LegacyMessageException; +import org.whispersystems.libaxolotl.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; +import org.whispersystems.libaxolotl.protocol.CiphertextMessage; +import org.whispersystems.libaxolotl.protocol.WhisperProtos; import org.whispersystems.textsecure.util.Base64; import org.whispersystems.textsecure.util.Conversions; import org.whispersystems.textsecure.util.Util; diff --git a/src/org/thoughtcrime/securesms/database/DatabaseFactory.java b/src/org/thoughtcrime/securesms/database/DatabaseFactory.java index b142ba098..411487a08 100644 --- a/src/org/thoughtcrime/securesms/database/DatabaseFactory.java +++ b/src/org/thoughtcrime/securesms/database/DatabaseFactory.java @@ -28,11 +28,11 @@ import org.thoughtcrime.securesms.DatabaseUpgradeActivity; import org.thoughtcrime.securesms.crypto.DecryptingPartInputStream; import org.thoughtcrime.securesms.crypto.DecryptingQueue; import org.thoughtcrime.securesms.crypto.MasterSecretUtil; -import org.whispersystems.textsecure.crypto.IdentityKey; -import org.whispersystems.textsecure.crypto.InvalidMessageException; +import org.thoughtcrime.securesms.notifications.MessageNotifier; +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.libaxolotl.InvalidMessageException; import org.whispersystems.textsecure.crypto.MasterCipher; import org.whispersystems.textsecure.crypto.MasterSecret; -import org.thoughtcrime.securesms.notifications.MessageNotifier; import org.whispersystems.textsecure.storage.Session; import org.whispersystems.textsecure.util.Base64; import org.whispersystems.textsecure.util.Util; diff --git a/src/org/thoughtcrime/securesms/database/DraftDatabase.java b/src/org/thoughtcrime/securesms/database/DraftDatabase.java index 487e03a07..5c2fd1c8c 100644 --- a/src/org/thoughtcrime/securesms/database/DraftDatabase.java +++ b/src/org/thoughtcrime/securesms/database/DraftDatabase.java @@ -7,7 +7,7 @@ import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.util.Log; -import org.whispersystems.textsecure.crypto.InvalidMessageException; +import org.whispersystems.libaxolotl.InvalidMessageException; import org.whispersystems.textsecure.crypto.MasterCipher; import java.util.LinkedList; diff --git a/src/org/thoughtcrime/securesms/database/EncryptingSmsDatabase.java b/src/org/thoughtcrime/securesms/database/EncryptingSmsDatabase.java index db263c0f0..53971238b 100644 --- a/src/org/thoughtcrime/securesms/database/EncryptingSmsDatabase.java +++ b/src/org/thoughtcrime/securesms/database/EncryptingSmsDatabase.java @@ -28,7 +28,7 @@ import org.thoughtcrime.securesms.database.model.DisplayRecord; import org.thoughtcrime.securesms.sms.IncomingTextMessage; import org.thoughtcrime.securesms.sms.OutgoingTextMessage; import org.thoughtcrime.securesms.util.LRUCache; -import org.whispersystems.textsecure.crypto.InvalidMessageException; +import org.whispersystems.libaxolotl.InvalidMessageException; import org.whispersystems.textsecure.crypto.MasterCipher; import org.whispersystems.textsecure.crypto.MasterSecret; diff --git a/src/org/thoughtcrime/securesms/database/IdentityDatabase.java b/src/org/thoughtcrime/securesms/database/IdentityDatabase.java index ce980c626..1d47226cd 100644 --- a/src/org/thoughtcrime/securesms/database/IdentityDatabase.java +++ b/src/org/thoughtcrime/securesms/database/IdentityDatabase.java @@ -24,14 +24,12 @@ import android.database.sqlite.SQLiteOpenHelper; import android.net.Uri; import android.util.Log; -import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientFactory; import org.thoughtcrime.securesms.recipients.Recipients; -import org.whispersystems.textsecure.crypto.IdentityKey; -import org.whispersystems.textsecure.crypto.InvalidKeyException; +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.libaxolotl.InvalidKeyException; import org.whispersystems.textsecure.crypto.MasterCipher; import org.whispersystems.textsecure.crypto.MasterSecret; -import org.whispersystems.textsecure.crypto.ecc.Curve; import org.whispersystems.textsecure.util.Base64; import java.io.IOException; diff --git a/src/org/thoughtcrime/securesms/database/MmsDatabase.java b/src/org/thoughtcrime/securesms/database/MmsDatabase.java index fed8abb75..955d7b971 100644 --- a/src/org/thoughtcrime/securesms/database/MmsDatabase.java +++ b/src/org/thoughtcrime/securesms/database/MmsDatabase.java @@ -32,7 +32,7 @@ import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage; import org.thoughtcrime.securesms.mms.OutgoingMediaMessage; import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.whispersystems.textsecure.crypto.InvalidMessageException; +import org.whispersystems.libaxolotl.InvalidMessageException; import org.whispersystems.textsecure.crypto.MasterCipher; import org.whispersystems.textsecure.crypto.MasterSecret; import org.thoughtcrime.securesms.database.model.DisplayRecord; diff --git a/src/org/thoughtcrime/securesms/database/ThreadDatabase.java b/src/org/thoughtcrime/securesms/database/ThreadDatabase.java index 8d5a1ac78..ff48730dc 100644 --- a/src/org/thoughtcrime/securesms/database/ThreadDatabase.java +++ b/src/org/thoughtcrime/securesms/database/ThreadDatabase.java @@ -29,7 +29,7 @@ import org.thoughtcrime.securesms.database.model.ThreadRecord; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientFactory; import org.thoughtcrime.securesms.recipients.Recipients; -import org.whispersystems.textsecure.crypto.InvalidMessageException; +import org.whispersystems.libaxolotl.InvalidMessageException; import org.whispersystems.textsecure.crypto.MasterCipher; import org.whispersystems.textsecure.util.Util; diff --git a/src/org/thoughtcrime/securesms/gcm/GcmBroadcastReceiver.java b/src/org/thoughtcrime/securesms/gcm/GcmBroadcastReceiver.java index 14c372d86..0dc21c554 100644 --- a/src/org/thoughtcrime/securesms/gcm/GcmBroadcastReceiver.java +++ b/src/org/thoughtcrime/securesms/gcm/GcmBroadcastReceiver.java @@ -9,7 +9,7 @@ import com.google.android.gms.gcm.GoogleCloudMessaging; import org.thoughtcrime.securesms.service.SendReceiveService; import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.whispersystems.textsecure.crypto.InvalidVersionException; +import org.whispersystems.libaxolotl.InvalidVersionException; import org.whispersystems.textsecure.directory.Directory; import org.whispersystems.textsecure.directory.NotInDirectoryException; import org.whispersystems.textsecure.push.ContactTokenDetails; diff --git a/src/org/thoughtcrime/securesms/service/AvatarDownloader.java b/src/org/thoughtcrime/securesms/service/AvatarDownloader.java index 666ba6e3c..050bcc3bd 100644 --- a/src/org/thoughtcrime/securesms/service/AvatarDownloader.java +++ b/src/org/thoughtcrime/securesms/service/AvatarDownloader.java @@ -15,8 +15,8 @@ import org.thoughtcrime.securesms.recipients.RecipientFormattingException; import org.thoughtcrime.securesms.util.BitmapDecodingException; import org.thoughtcrime.securesms.util.BitmapUtil; import org.thoughtcrime.securesms.util.GroupUtil; +import org.whispersystems.libaxolotl.InvalidMessageException; import org.whispersystems.textsecure.crypto.AttachmentCipherInputStream; -import org.whispersystems.textsecure.crypto.InvalidMessageException; import org.whispersystems.textsecure.crypto.MasterSecret; import org.whispersystems.textsecure.push.PushServiceSocket; diff --git a/src/org/thoughtcrime/securesms/service/PreKeyService.java b/src/org/thoughtcrime/securesms/service/PreKeyService.java index b21174e84..11998c721 100644 --- a/src/org/thoughtcrime/securesms/service/PreKeyService.java +++ b/src/org/thoughtcrime/securesms/service/PreKeyService.java @@ -9,10 +9,9 @@ import android.util.Log; import org.thoughtcrime.securesms.crypto.IdentityKeyUtil; import org.thoughtcrime.securesms.push.PushServiceSocketFactory; import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.whispersystems.textsecure.crypto.IdentityKey; +import org.whispersystems.libaxolotl.IdentityKey; import org.whispersystems.textsecure.crypto.MasterSecret; import org.whispersystems.textsecure.crypto.PreKeyUtil; -import org.whispersystems.textsecure.crypto.ecc.Curve; import org.whispersystems.textsecure.push.PushServiceSocket; import org.whispersystems.textsecure.storage.PreKeyRecord; diff --git a/src/org/thoughtcrime/securesms/service/PushDownloader.java b/src/org/thoughtcrime/securesms/service/PushDownloader.java index 1aa49878d..967c80bdf 100644 --- a/src/org/thoughtcrime/securesms/service/PushDownloader.java +++ b/src/org/thoughtcrime/securesms/service/PushDownloader.java @@ -12,8 +12,8 @@ import org.thoughtcrime.securesms.database.EncryptingPartDatabase; import org.thoughtcrime.securesms.database.PartDatabase; import org.thoughtcrime.securesms.push.PushServiceSocketFactory; import org.thoughtcrime.securesms.util.Util; +import org.whispersystems.libaxolotl.InvalidMessageException; import org.whispersystems.textsecure.crypto.AttachmentCipherInputStream; -import org.whispersystems.textsecure.crypto.InvalidMessageException; import org.whispersystems.textsecure.crypto.MasterCipher; import org.whispersystems.textsecure.crypto.MasterSecret; import org.whispersystems.textsecure.push.NotFoundException; diff --git a/src/org/thoughtcrime/securesms/service/PushReceiver.java b/src/org/thoughtcrime/securesms/service/PushReceiver.java index c38d1a949..aa7d4c262 100644 --- a/src/org/thoughtcrime/securesms/service/PushReceiver.java +++ b/src/org/thoughtcrime/securesms/service/PushReceiver.java @@ -25,11 +25,11 @@ import org.thoughtcrime.securesms.sms.IncomingKeyExchangeMessage; import org.thoughtcrime.securesms.sms.IncomingPreKeyBundleMessage; import org.thoughtcrime.securesms.sms.IncomingTextMessage; import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.whispersystems.textsecure.crypto.InvalidKeyException; -import org.whispersystems.textsecure.crypto.InvalidMessageException; -import org.whispersystems.textsecure.crypto.InvalidVersionException; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.InvalidMessageException; +import org.whispersystems.libaxolotl.InvalidVersionException; +import org.whispersystems.libaxolotl.protocol.PreKeyWhisperMessage; import org.whispersystems.textsecure.crypto.MasterSecret; -import org.whispersystems.textsecure.crypto.protocol.PreKeyWhisperMessage; import org.whispersystems.textsecure.push.IncomingPushMessage; import org.whispersystems.textsecure.push.PushMessageProtos.PushMessageContent; import org.whispersystems.textsecure.storage.InvalidKeyIdException; diff --git a/src/org/thoughtcrime/securesms/service/RegistrationService.java b/src/org/thoughtcrime/securesms/service/RegistrationService.java index ef59d4825..f0de43cd6 100644 --- a/src/org/thoughtcrime/securesms/service/RegistrationService.java +++ b/src/org/thoughtcrime/securesms/service/RegistrationService.java @@ -17,7 +17,7 @@ import org.thoughtcrime.securesms.crypto.IdentityKeyUtil; import org.thoughtcrime.securesms.push.PushServiceSocketFactory; import org.thoughtcrime.securesms.util.DirectoryHelper; import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.whispersystems.textsecure.crypto.IdentityKey; +import org.whispersystems.libaxolotl.IdentityKey; import org.whispersystems.textsecure.crypto.MasterSecret; import org.whispersystems.textsecure.crypto.PreKeyUtil; import org.whispersystems.textsecure.push.ExpectationFailedException; diff --git a/src/org/thoughtcrime/securesms/service/SmsReceiver.java b/src/org/thoughtcrime/securesms/service/SmsReceiver.java index 4d1676998..8b5cda76c 100644 --- a/src/org/thoughtcrime/securesms/service/SmsReceiver.java +++ b/src/org/thoughtcrime/securesms/service/SmsReceiver.java @@ -26,7 +26,6 @@ import org.thoughtcrime.securesms.crypto.KeyExchangeProcessor; import org.thoughtcrime.securesms.crypto.KeyExchangeProcessorV2; import org.thoughtcrime.securesms.crypto.MasterSecretUtil; import org.thoughtcrime.securesms.crypto.protocol.KeyExchangeMessage; -import org.whispersystems.textsecure.crypto.LegacyMessageException; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.EncryptingSmsDatabase; import org.thoughtcrime.securesms.database.SmsDatabase; @@ -42,12 +41,13 @@ import org.thoughtcrime.securesms.sms.IncomingTextMessage; import org.thoughtcrime.securesms.sms.MultipartSmsMessageHandler; import org.thoughtcrime.securesms.sms.SmsTransportDetails; import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.whispersystems.textsecure.crypto.InvalidKeyException; -import org.whispersystems.textsecure.crypto.InvalidMessageException; -import org.whispersystems.textsecure.crypto.InvalidVersionException; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.InvalidMessageException; +import org.whispersystems.libaxolotl.InvalidVersionException; +import org.whispersystems.libaxolotl.LegacyMessageException; +import org.whispersystems.libaxolotl.protocol.PreKeyWhisperMessage; +import org.whispersystems.libaxolotl.protocol.WhisperMessage; import org.whispersystems.textsecure.crypto.MasterSecret; -import org.whispersystems.textsecure.crypto.protocol.PreKeyWhisperMessage; -import org.whispersystems.textsecure.crypto.protocol.WhisperMessage; import org.whispersystems.textsecure.storage.InvalidKeyIdException; import org.whispersystems.textsecure.storage.RecipientDevice; diff --git a/src/org/thoughtcrime/securesms/sms/IncomingIdentityUpdateMessage.java b/src/org/thoughtcrime/securesms/sms/IncomingIdentityUpdateMessage.java index 36cdb5729..7bbdcc38f 100644 --- a/src/org/thoughtcrime/securesms/sms/IncomingIdentityUpdateMessage.java +++ b/src/org/thoughtcrime/securesms/sms/IncomingIdentityUpdateMessage.java @@ -1,6 +1,6 @@ package org.thoughtcrime.securesms.sms; -import org.whispersystems.textsecure.crypto.IdentityKey; +import org.whispersystems.libaxolotl.IdentityKey; import org.whispersystems.textsecure.util.Base64; public class IncomingIdentityUpdateMessage extends IncomingKeyExchangeMessage { diff --git a/src/org/thoughtcrime/securesms/sms/SmsTransportDetails.java b/src/org/thoughtcrime/securesms/sms/SmsTransportDetails.java index 150b164d9..d40235b07 100644 --- a/src/org/thoughtcrime/securesms/sms/SmsTransportDetails.java +++ b/src/org/thoughtcrime/securesms/sms/SmsTransportDetails.java @@ -19,8 +19,8 @@ package org.thoughtcrime.securesms.sms; import android.util.Log; import org.thoughtcrime.securesms.protocol.WirePrefix; +import org.whispersystems.libaxolotl.protocol.CiphertextMessage; import org.whispersystems.textsecure.crypto.TransportDetails; -import org.whispersystems.textsecure.crypto.protocol.CiphertextMessage; import org.whispersystems.textsecure.util.Base64; import java.io.IOException; diff --git a/src/org/thoughtcrime/securesms/transport/MmsTransport.java b/src/org/thoughtcrime/securesms/transport/MmsTransport.java index 0683bedfe..0b272cf24 100644 --- a/src/org/thoughtcrime/securesms/transport/MmsTransport.java +++ b/src/org/thoughtcrime/securesms/transport/MmsTransport.java @@ -33,9 +33,10 @@ import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientFactory; import org.thoughtcrime.securesms.recipients.RecipientFormattingException; import org.thoughtcrime.securesms.util.NumberUtil; +import org.whispersystems.libaxolotl.SessionCipher; +import org.whispersystems.libaxolotl.protocol.CiphertextMessage; import org.whispersystems.textsecure.crypto.MasterSecret; -import org.whispersystems.textsecure.crypto.SessionCipher; -import org.whispersystems.textsecure.crypto.protocol.CiphertextMessage; +import org.whispersystems.textsecure.crypto.SessionCipherFactory; import org.whispersystems.textsecure.storage.RecipientDevice; import org.whispersystems.textsecure.storage.Session; import org.whispersystems.textsecure.util.Hex; @@ -177,7 +178,7 @@ public class MmsTransport { throw new InsecureFallbackApprovalException("No session exists for this secure message."); } - SessionCipher sessionCipher = SessionCipher.createFor(context, masterSecret, recipientDevice); + SessionCipher sessionCipher = SessionCipherFactory.getInstance(context, masterSecret, recipientDevice); CiphertextMessage ciphertextMessage = sessionCipher.encrypt(pduBytes); return transportDetails.getEncodedMessage(ciphertextMessage.serialize()); diff --git a/src/org/thoughtcrime/securesms/transport/PushTransport.java b/src/org/thoughtcrime/securesms/transport/PushTransport.java index b6f885e42..221bdfdb6 100644 --- a/src/org/thoughtcrime/securesms/transport/PushTransport.java +++ b/src/org/thoughtcrime/securesms/transport/PushTransport.java @@ -35,11 +35,12 @@ import org.thoughtcrime.securesms.recipients.RecipientFormattingException; import org.thoughtcrime.securesms.recipients.Recipients; import org.thoughtcrime.securesms.util.GroupUtil; import org.thoughtcrime.securesms.util.Util; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.SessionCipher; +import org.whispersystems.libaxolotl.protocol.CiphertextMessage; import org.whispersystems.textsecure.crypto.AttachmentCipher; -import org.whispersystems.textsecure.crypto.InvalidKeyException; import org.whispersystems.textsecure.crypto.MasterSecret; -import org.whispersystems.textsecure.crypto.SessionCipher; -import org.whispersystems.textsecure.crypto.protocol.CiphertextMessage; +import org.whispersystems.textsecure.crypto.SessionCipherFactory; import org.whispersystems.textsecure.push.MismatchedDevices; import org.whispersystems.textsecure.push.MismatchedDevicesException; import org.whispersystems.textsecure.push.OutgoingPushMessage; @@ -348,9 +349,9 @@ public class PushTransport extends BaseTransport { } } - SessionCipher cipher = SessionCipher.createFor(context, masterSecret, pushAddress); - CiphertextMessage message = cipher.encrypt(plaintext); - int remoteRegistrationId = cipher.getRemoteRegistrationId(); + SessionCipher cipher = SessionCipherFactory.getInstance(context, masterSecret, pushAddress); + CiphertextMessage message = cipher.encrypt(plaintext); + int remoteRegistrationId = cipher.getRemoteRegistrationId(); if (message.getType() == CiphertextMessage.PREKEY_TYPE) { return new PushBody(IncomingPushMessageSignal.Type.PREKEY_BUNDLE_VALUE, remoteRegistrationId, message.serialize()); diff --git a/src/org/thoughtcrime/securesms/transport/SmsTransport.java b/src/org/thoughtcrime/securesms/transport/SmsTransport.java index 2709c5815..e56f1d61c 100644 --- a/src/org/thoughtcrime/securesms/transport/SmsTransport.java +++ b/src/org/thoughtcrime/securesms/transport/SmsTransport.java @@ -30,9 +30,10 @@ import org.thoughtcrime.securesms.sms.OutgoingTextMessage; import org.thoughtcrime.securesms.sms.SmsTransportDetails; import org.thoughtcrime.securesms.util.NumberUtil; import org.thoughtcrime.securesms.util.TextSecurePreferences; +import org.whispersystems.libaxolotl.SessionCipher; +import org.whispersystems.libaxolotl.protocol.CiphertextMessage; import org.whispersystems.textsecure.crypto.MasterSecret; -import org.whispersystems.textsecure.crypto.SessionCipher; -import org.whispersystems.textsecure.crypto.protocol.CiphertextMessage; +import org.whispersystems.textsecure.crypto.SessionCipherFactory; import org.whispersystems.textsecure.storage.RecipientDevice; import org.whispersystems.textsecure.storage.Session; @@ -179,7 +180,7 @@ public class SmsTransport extends BaseTransport { String body = message.getMessageBody(); SmsTransportDetails transportDetails = new SmsTransportDetails(); - SessionCipher sessionCipher = SessionCipher.createFor(context, masterSecret, recipientDevice); + SessionCipher sessionCipher = SessionCipherFactory.getInstance(context, masterSecret, recipientDevice); byte[] paddedPlaintext = transportDetails.getPaddedMessageBody(body.getBytes()); CiphertextMessage ciphertextMessage = sessionCipher.encrypt(paddedPlaintext); String encodedCiphertext = new String(transportDetails.getEncodedMessage(ciphertextMessage.serialize())); diff --git a/src/org/thoughtcrime/securesms/transport/UntrustedIdentityException.java b/src/org/thoughtcrime/securesms/transport/UntrustedIdentityException.java index ac322f392..195bcd14c 100644 --- a/src/org/thoughtcrime/securesms/transport/UntrustedIdentityException.java +++ b/src/org/thoughtcrime/securesms/transport/UntrustedIdentityException.java @@ -1,7 +1,6 @@ package org.thoughtcrime.securesms.transport; -import org.whispersystems.textsecure.crypto.IdentityKey; -import org.whispersystems.textsecure.push.UnregisteredUserException; +import org.whispersystems.libaxolotl.IdentityKey; public class UntrustedIdentityException extends Exception {