Break core ratchet out into libaxolotol.

1) Break the core cryptography functions out into libaxolotol.

2) The objective for this code is a Java library that isn't
   dependent on any Android functions.  However, while the
   code has been separated from any Android functionality,
   it is still an 'android library project' because of the
   JNI.
master
Moxie Marlinspike 2014-04-21 08:40:19 -07:00
parent fe3d91c40c
commit d902c12941
116 changed files with 2268 additions and 1039 deletions

View File

@ -101,6 +101,12 @@ android {
} }
} }
tasks.whenTaskAdded { task ->
if (task.name.equals("lint")) {
task.enabled = false
}
}
def Properties props = new Properties() def Properties props = new Properties()
def propFile = new File('signing.properties') def propFile = new File('signing.properties')

2
libaxolotl/.gitignore vendored 100644
View File

@ -0,0 +1,2 @@
/build
/obj

View File

@ -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
}
}

View File

@ -21,7 +21,7 @@
#include <jni.h> #include <jni.h>
#include "curve25519-donna.h" #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) (JNIEnv *env, jclass clazz, jbyteArray random, jboolean ephemeral)
{ {
uint8_t* privateKey = (uint8_t*)(*env)->GetByteArrayElements(env, random, 0); 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; 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) (JNIEnv *env, jclass clazz, jbyteArray privateKey)
{ {
static const uint8_t basepoint[32] = {9}; static const uint8_t basepoint[32] = {9};
@ -57,7 +57,7 @@ JNIEXPORT jbyteArray JNICALL Java_org_whispersystems_textsecure_crypto_ecc_Curve
return publicKey; 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) (JNIEnv *env, jclass clazz, jbyteArray privateKey, jbyteArray publicKey)
{ {
jbyteArray sharedKey = (*env)->NewByteArray(env, 32); jbyteArray sharedKey = (*env)->NewByteArray(env, 32);

View File

@ -0,0 +1,3 @@
all:
protoc --java_out=../src/main/java/ WhisperTextProtocol.proto

View File

@ -1,6 +1,6 @@
package textsecure; package textsecure;
option java_package = "org.whispersystems.textsecure.crypto.protocol"; option java_package = "org.whispersystems.libaxolotl.protocol";
option java_outer_classname = "WhisperProtos"; option java_outer_classname = "WhisperProtos";
message WhisperMessage { message WhisperMessage {

View File

@ -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<ECPublicKey, InMemoryChain> 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<InMemoryChain.InMemoryMessageKey> 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<Integer, ECPublicKey> 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<InMemoryMessageKey> messageKeys = new LinkedList<>();
public static class InMemoryMessageKey {
public InMemoryMessageKey(){}
int index;
byte[] cipherKey;
byte[] macKey;
}
}
}

View File

@ -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<SessionState> previousSessionStates;
private SessionState checkedOutSessionState;
private List<SessionState> 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<SessionState> 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;
}
}

View File

@ -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());
}
}

View File

@ -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));
}
}
}

View File

@ -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));
}
}

View File

@ -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);
}
}

View File

@ -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));
}
}

View File

@ -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<RootKey, ChainKey> 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));
}
}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.whispersystems.libaxolotl"
android:versionCode="1"
android:versionName="0.1">
<application />
</manifest>

View File

@ -1,4 +1,4 @@
package org.whispersystems.textsecure.crypto; package org.whispersystems.libaxolotl;
public class DuplicateMessageException extends Exception { public class DuplicateMessageException extends Exception {
public DuplicateMessageException(String s) { public DuplicateMessageException(String s) {

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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();
}
}

View File

@ -14,9 +14,9 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
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. * Holder for public and private identity key pair.

View File

@ -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 * 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 * 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 * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.whispersystems.textsecure.crypto; package org.whispersystems.libaxolotl;
public class InvalidKeyException extends Exception { public class InvalidKeyException extends Exception {
public InvalidKeyException() { public InvalidKeyException() {}
// TODO Auto-generated constructor stub
}
public InvalidKeyException(String detailMessage) { public InvalidKeyException(String detailMessage) {
super(detailMessage); super(detailMessage);
// TODO Auto-generated constructor stub
} }
public InvalidKeyException(Throwable throwable) { public InvalidKeyException(Throwable throwable) {
super(throwable); super(throwable);
// TODO Auto-generated constructor stub
} }
public InvalidKeyException(String detailMessage, Throwable throwable) { public InvalidKeyException(String detailMessage, Throwable throwable) {
super(detailMessage, throwable); super(detailMessage, throwable);
// TODO Auto-generated constructor stub
} }
} }

View File

@ -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 * 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 * 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 * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.whispersystems.textsecure.crypto; package org.whispersystems.libaxolotl;
public class InvalidMacException extends Exception { public class InvalidMacException extends Exception {
public InvalidMacException() {
// TODO Auto-generated constructor stub
}
public InvalidMacException(String detailMessage) { public InvalidMacException(String detailMessage) {
super(detailMessage); super(detailMessage);
// TODO Auto-generated constructor stub
} }
public InvalidMacException(Throwable throwable) { public InvalidMacException(Throwable throwable) {
super(throwable); super(throwable);
// TODO Auto-generated constructor stub
} }
public InvalidMacException(String detailMessage, Throwable throwable) {
super(detailMessage, throwable);
// TODO Auto-generated constructor stub
}
} }

View File

@ -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 * 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 * 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 * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.whispersystems.textsecure.crypto; package org.whispersystems.libaxolotl;
import java.util.List;
public class InvalidMessageException extends Exception { public class InvalidMessageException extends Exception {
public InvalidMessageException() { public InvalidMessageException() {}
// TODO Auto-generated constructor stub
}
public InvalidMessageException(String detailMessage) { public InvalidMessageException(String detailMessage) {
super(detailMessage); super(detailMessage);
// TODO Auto-generated constructor stub
} }
public InvalidMessageException(Throwable throwable) { public InvalidMessageException(Throwable throwable) {
super(throwable); super(throwable);
// TODO Auto-generated constructor stub
} }
public InvalidMessageException(String detailMessage, Throwable throwable) { public InvalidMessageException(String detailMessage, Throwable throwable) {
super(detailMessage, throwable); super(detailMessage, throwable);
// TODO Auto-generated constructor stub
} }
public InvalidMessageException(String detailMessage, List<Exception> exceptions) {
super(detailMessage, exceptions.get(0));
}
} }

View File

@ -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 * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * 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 * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.whispersystems.textsecure.crypto; package org.whispersystems.libaxolotl;
public interface SerializableKey { public class InvalidVersionException extends Exception {
public byte[] serialize(); public InvalidVersionException(String detailMessage) {
super(detailMessage);
}
} }

View File

@ -1,4 +1,4 @@
package org.whispersystems.textsecure.crypto; package org.whispersystems.libaxolotl;
public class LegacyMessageException extends Exception { public class LegacyMessageException extends Exception {
public LegacyMessageException(String s) { public LegacyMessageException(String s) {

View File

@ -14,29 +14,23 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.whispersystems.textsecure.crypto; package org.whispersystems.libaxolotl;
import org.whispersystems.libaxolotl.ecc.Curve;
import android.content.Context; import org.whispersystems.libaxolotl.ecc.ECKeyPair;
import android.util.Log; import org.whispersystems.libaxolotl.ecc.ECPublicKey;
import android.util.Pair; import org.whispersystems.libaxolotl.protocol.CiphertextMessage;
import org.whispersystems.libaxolotl.protocol.PreKeyWhisperMessage;
import org.whispersystems.textsecure.crypto.ecc.Curve; import org.whispersystems.libaxolotl.protocol.WhisperMessage;
import org.whispersystems.textsecure.crypto.ecc.ECKeyPair; import org.whispersystems.libaxolotl.ratchet.ChainKey;
import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; import org.whispersystems.libaxolotl.ratchet.MessageKeys;
import org.whispersystems.textsecure.crypto.protocol.CiphertextMessage; import org.whispersystems.libaxolotl.ratchet.RootKey;
import org.whispersystems.textsecure.crypto.protocol.PreKeyWhisperMessage; import org.whispersystems.libaxolotl.util.ByteUtil;
import org.whispersystems.textsecure.crypto.protocol.WhisperMessage; import org.whispersystems.libaxolotl.util.Pair;
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 java.security.InvalidAlgorithmParameterException; import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import javax.crypto.BadPaddingException; import javax.crypto.BadPaddingException;
@ -50,36 +44,19 @@ public class SessionCipher {
private static final Object SESSION_LOCK = new Object(); private static final Object SESSION_LOCK = new Object();
private final Context context; private final SessionStore sessionStore;
private final MasterSecret masterSecret;
private final RecipientDevice recipient;
public static SessionCipher createFor(Context context, public SessionCipher(SessionStore sessionStore) {
MasterSecret masterSecret, this.sessionStore = sessionStore;
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 CiphertextMessage encrypt(byte[] paddedMessage) { public CiphertextMessage encrypt(byte[] paddedMessage) {
synchronized (SESSION_LOCK) { synchronized (SESSION_LOCK) {
SessionRecordV2 sessionRecord = getSessionRecord(); SessionState sessionState = sessionStore.getSessionState();
SessionState sessionState = sessionRecord.getSessionState(); ChainKey chainKey = sessionState.getSenderChainKey();
ChainKey chainKey = sessionState.getSenderChainKey(); MessageKeys messageKeys = chainKey.getMessageKeys();
MessageKeys messageKeys = chainKey.getMessageKeys(); ECPublicKey senderEphemeral = sessionState.getSenderEphemeral();
ECPublicKey senderEphemeral = sessionState.getSenderEphemeral(); int previousCounter = sessionState.getPreviousCounter();
int previousCounter = sessionState.getPreviousCounter();
byte[] ciphertextBody = getCiphertext(messageKeys, paddedMessage); byte[] ciphertextBody = getCiphertext(messageKeys, paddedMessage);
CiphertextMessage ciphertextMessage = new WhisperMessage(messageKeys.getMacKey(), CiphertextMessage ciphertextMessage = new WhisperMessage(messageKeys.getMacKey(),
@ -90,15 +67,14 @@ public class SessionCipher {
Pair<Integer, ECPublicKey> pendingPreKey = sessionState.getPendingPreKey(); Pair<Integer, ECPublicKey> pendingPreKey = sessionState.getPendingPreKey();
int localRegistrationId = sessionState.getLocalRegistrationId(); int localRegistrationId = sessionState.getLocalRegistrationId();
ciphertextMessage = new PreKeyWhisperMessage(localRegistrationId, pendingPreKey.first, ciphertextMessage = new PreKeyWhisperMessage(localRegistrationId, pendingPreKey.first(),
pendingPreKey.second, pendingPreKey.second(),
sessionState.getLocalIdentityKey(), sessionState.getLocalIdentityKey(),
(WhisperMessage) ciphertextMessage); (WhisperMessage) ciphertextMessage);
} }
sessionState.setSenderChainKey(chainKey.getNextChainKey()); sessionState.setSenderChainKey(chainKey.getNextChainKey());
sessionRecord.save(); sessionStore.save();
return ciphertextMessage; return ciphertextMessage;
} }
} }
@ -107,32 +83,31 @@ public class SessionCipher {
throws InvalidMessageException, DuplicateMessageException, LegacyMessageException throws InvalidMessageException, DuplicateMessageException, LegacyMessageException
{ {
synchronized (SESSION_LOCK) { synchronized (SESSION_LOCK) {
SessionRecordV2 sessionRecord = getSessionRecord(); SessionState sessionState = sessionStore.getSessionState();
SessionState sessionState = sessionRecord.getSessionState(); List<SessionState> previousStates = sessionStore.getPreviousSessionStates();
List<SessionState> previousStates = sessionRecord.getPreviousSessions(); List<Exception> exceptions = new LinkedList<Exception>();
try { try {
byte[] plaintext = decrypt(sessionState, decodedMessage); byte[] plaintext = decrypt(sessionState, decodedMessage);
sessionRecord.save(); sessionStore.save();
return plaintext; return plaintext;
} catch (InvalidMessageException e) { } catch (InvalidMessageException e) {
Log.w("SessionCipherV2", e); exceptions.add(e);
} }
for (SessionState previousState : previousStates) { for (SessionState previousState : previousStates) {
try { try {
Log.w("SessionCipherV2", "Attempting decrypt on previous state...");
byte[] plaintext = decrypt(previousState, decodedMessage); byte[] plaintext = decrypt(previousState, decodedMessage);
sessionRecord.save(); sessionStore.save();
return plaintext; return plaintext;
} catch (InvalidMessageException e) { } 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() { public int getRemoteRegistrationId() {
synchronized (SESSION_LOCK) { synchronized (SESSION_LOCK) {
SessionRecordV2 sessionRecord = getSessionRecord(); return sessionStore.getSessionState().getRemoteRegistrationId();
return sessionRecord.getSessionState().getRemoteRegistrationId();
} }
} }
@ -174,18 +148,18 @@ public class SessionCipher {
if (sessionState.hasReceiverChain(theirEphemeral)) { if (sessionState.hasReceiverChain(theirEphemeral)) {
return sessionState.getReceiverChainKey(theirEphemeral); return sessionState.getReceiverChainKey(theirEphemeral);
} else { } else {
RootKey rootKey = sessionState.getRootKey(); RootKey rootKey = sessionState.getRootKey();
ECKeyPair ourEphemeral = sessionState.getSenderEphemeralPair(); ECKeyPair ourEphemeral = sessionState.getSenderEphemeralPair();
Pair<RootKey, ChainKey> receiverChain = rootKey.createChain(theirEphemeral, ourEphemeral); Pair<RootKey, ChainKey> receiverChain = rootKey.createChain(theirEphemeral, ourEphemeral);
ECKeyPair ourNewEphemeral = Curve.generateKeyPair(true); ECKeyPair ourNewEphemeral = Curve.generateKeyPair(true);
Pair<RootKey, ChainKey> senderChain = receiverChain.first.createChain(theirEphemeral, ourNewEphemeral); Pair<RootKey, ChainKey> senderChain = receiverChain.first().createChain(theirEphemeral, ourNewEphemeral);
sessionState.setRootKey(senderChain.first); sessionState.setRootKey(senderChain.first());
sessionState.addReceiverChain(theirEphemeral, receiverChain.second); sessionState.addReceiverChain(theirEphemeral, receiverChain.second());
sessionState.setPreviousCounter(sessionState.getSenderChainKey().getIndex()-1); 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) { } catch (InvalidKeyException e) {
throw new InvalidMessageException(e); throw new InvalidMessageException(e);
@ -252,7 +226,7 @@ public class SessionCipher {
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding"); Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
byte[] ivBytes = new byte[16]; byte[] ivBytes = new byte[16];
Conversions.intToByteArray(ivBytes, 0, counter); ByteUtil.intToByteArray(ivBytes, 0, counter);
IvParameterSpec iv = new IvParameterSpec(ivBytes); IvParameterSpec iv = new IvParameterSpec(ivBytes);
cipher.init(mode, key, iv); cipher.init(mode, key, iv);
@ -268,8 +242,4 @@ public class SessionCipher {
throw new AssertionError(e); throw new AssertionError(e);
} }
} }
private SessionRecordV2 getSessionRecord() {
return new SessionRecordV2(context, masterSecret, recipient);
}
} }

View File

@ -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<Integer, ECPublicKey> getPendingPreKey();
public void clearPendingPreKey();
public void setRemoteRegistrationId(int registrationId);
public int getRemoteRegistrationId();
public void setLocalRegistrationId(int registrationId);
public int getLocalRegistrationId();
public byte[] serialize();
}

View File

@ -0,0 +1,12 @@
package org.whispersystems.libaxolotl;
import java.util.List;
public interface SessionStore {
public SessionState getSessionState();
public List<SessionState> getPreviousSessionStates();
public void save();
}

View File

@ -14,10 +14,9 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.whispersystems.textsecure.crypto.ecc; package org.whispersystems.libaxolotl.ecc;
import org.whispersystems.textsecure.crypto.InvalidKeyException; import org.whispersystems.libaxolotl.InvalidKeyException;
import org.whispersystems.textsecure.crypto.protocol.CiphertextMessage;
public class Curve { public class Curve {

View File

@ -14,9 +14,9 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
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.NoSuchAlgorithmException;
import java.security.SecureRandom; import java.security.SecureRandom;

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.whispersystems.textsecure.crypto.ecc; package org.whispersystems.libaxolotl.ecc;
public class DjbECPrivateKey implements ECPrivateKey { public class DjbECPrivateKey implements ECPrivateKey {

View File

@ -15,9 +15,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
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.math.BigInteger;
import java.util.Arrays; import java.util.Arrays;
@ -33,7 +33,7 @@ public class DjbECPublicKey implements ECPublicKey {
@Override @Override
public byte[] serialize() { public byte[] serialize() {
byte[] type = {Curve.DJB_TYPE}; byte[] type = {Curve.DJB_TYPE};
return Util.combine(type, publicKey); return ByteUtil.combine(type, publicKey);
} }
@Override @Override

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.whispersystems.textsecure.crypto.ecc; package org.whispersystems.libaxolotl.ecc;
public class ECKeyPair { public class ECKeyPair {

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.whispersystems.textsecure.crypto.ecc; package org.whispersystems.libaxolotl.ecc;
public interface ECPrivateKey { public interface ECPrivateKey {
public byte[] serialize(); public byte[] serialize();

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.whispersystems.textsecure.crypto.ecc; package org.whispersystems.libaxolotl.ecc;
public interface ECPublicKey extends Comparable<ECPublicKey> { public interface ECPublicKey extends Comparable<ECPublicKey> {

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.whispersystems.textsecure.crypto.kdf; package org.whispersystems.libaxolotl.kdf;
import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.SecretKeySpec;

View File

@ -15,13 +15,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.whispersystems.textsecure.crypto.kdf; package org.whispersystems.libaxolotl.kdf;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.math.BigInteger;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.List;
import javax.crypto.Mac; import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.SecretKeySpec;

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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();
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
package org.whispersystems.libaxolotl.protocol;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.InvalidProtocolBufferException;
import org.whispersystems.textsecure.crypto.IdentityKey; import org.whispersystems.libaxolotl.IdentityKey;
import org.whispersystems.textsecure.crypto.InvalidKeyException; import org.whispersystems.libaxolotl.InvalidKeyException;
import org.whispersystems.textsecure.crypto.InvalidMessageException; import org.whispersystems.libaxolotl.InvalidMessageException;
import org.whispersystems.textsecure.crypto.InvalidVersionException; import org.whispersystems.libaxolotl.InvalidVersionException;
import org.whispersystems.textsecure.crypto.LegacyMessageException; import org.whispersystems.libaxolotl.LegacyMessageException;
import org.whispersystems.textsecure.crypto.ecc.Curve; import org.whispersystems.libaxolotl.ecc.Curve;
import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; import org.whispersystems.libaxolotl.ecc.ECPublicKey;
import org.whispersystems.textsecure.util.Conversions; import org.whispersystems.libaxolotl.util.ByteUtil;
import org.whispersystems.textsecure.util.Util;
public class PreKeyWhisperMessage implements CiphertextMessage { public class PreKeyWhisperMessage implements CiphertextMessage {
@ -27,7 +43,7 @@ public class PreKeyWhisperMessage implements CiphertextMessage {
throws InvalidMessageException, InvalidVersionException throws InvalidMessageException, InvalidVersionException
{ {
try { try {
this.version = Conversions.highBitsToInt(serialized[0]); this.version = ByteUtil.highBitsToInt(serialized[0]);
if (this.version > CiphertextMessage.CURRENT_VERSION) { if (this.version > CiphertextMessage.CURRENT_VERSION) {
throw new InvalidVersionException("Unknown version: " + this.version); throw new InvalidVersionException("Unknown version: " + this.version);
@ -70,7 +86,7 @@ public class PreKeyWhisperMessage implements CiphertextMessage {
this.identityKey = identityKey; this.identityKey = identityKey;
this.message = message; this.message = message;
byte[] versionBytes = {Conversions.intsToByteHighAndLow(CURRENT_VERSION, this.version)}; byte[] versionBytes = {ByteUtil.intsToByteHighAndLow(CURRENT_VERSION, this.version)};
byte[] messageBytes = WhisperProtos.PreKeyWhisperMessage.newBuilder() byte[] messageBytes = WhisperProtos.PreKeyWhisperMessage.newBuilder()
.setPreKeyId(preKeyId) .setPreKeyId(preKeyId)
.setBaseKey(ByteString.copyFrom(baseKey.serialize())) .setBaseKey(ByteString.copyFrom(baseKey.serialize()))
@ -79,7 +95,7 @@ public class PreKeyWhisperMessage implements CiphertextMessage {
.setRegistrationId(registrationId) .setRegistrationId(registrationId)
.build().toByteArray(); .build().toByteArray();
this.serialized = Util.combine(versionBytes, messageBytes); this.serialized = ByteUtil.combine(versionBytes, messageBytes);
} }
public IdentityKey getIdentityKey() { public IdentityKey getIdentityKey() {

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
package org.whispersystems.libaxolotl.protocol;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.InvalidProtocolBufferException;
import org.whispersystems.textsecure.crypto.InvalidKeyException; import org.whispersystems.libaxolotl.InvalidKeyException;
import org.whispersystems.textsecure.crypto.InvalidMessageException; import org.whispersystems.libaxolotl.InvalidMessageException;
import org.whispersystems.textsecure.crypto.LegacyMessageException; import org.whispersystems.libaxolotl.LegacyMessageException;
import org.whispersystems.textsecure.crypto.ecc.Curve; import org.whispersystems.libaxolotl.ecc.Curve;
import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; import org.whispersystems.libaxolotl.ecc.ECPublicKey;
import org.whispersystems.textsecure.util.Conversions; import org.whispersystems.libaxolotl.util.ByteUtil;
import org.whispersystems.textsecure.util.Util;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
@ -30,17 +45,17 @@ public class WhisperMessage implements CiphertextMessage {
public WhisperMessage(byte[] serialized) throws InvalidMessageException, LegacyMessageException { public WhisperMessage(byte[] serialized) throws InvalidMessageException, LegacyMessageException {
try { 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 version = messageParts[0][0];
byte[] message = messageParts[1]; byte[] message = messageParts[1];
byte[] mac = messageParts[2]; byte[] mac = messageParts[2];
if (Conversions.highBitsToInt(version) <= CiphertextMessage.UNSUPPORTED_VERSION) { if (ByteUtil.highBitsToInt(version) <= CiphertextMessage.UNSUPPORTED_VERSION) {
throw new LegacyMessageException("Legacy message: " + Conversions.highBitsToInt(version)); throw new LegacyMessageException("Legacy message: " + ByteUtil.highBitsToInt(version));
} }
if (Conversions.highBitsToInt(version) != CURRENT_VERSION) { if (ByteUtil.highBitsToInt(version) != CURRENT_VERSION) {
throw new InvalidMessageException("Unknown version: " + Conversions.highBitsToInt(version)); throw new InvalidMessageException("Unknown version: " + ByteUtil.highBitsToInt(version));
} }
WhisperProtos.WhisperMessage whisperMessage = WhisperProtos.WhisperMessage.parseFrom(message); WhisperProtos.WhisperMessage whisperMessage = WhisperProtos.WhisperMessage.parseFrom(message);
@ -69,16 +84,16 @@ public class WhisperMessage implements CiphertextMessage {
public WhisperMessage(SecretKeySpec macKey, ECPublicKey senderEphemeral, public WhisperMessage(SecretKeySpec macKey, ECPublicKey senderEphemeral,
int counter, int previousCounter, byte[] ciphertext) 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() byte[] message = WhisperProtos.WhisperMessage.newBuilder()
.setEphemeralKey(ByteString.copyFrom(senderEphemeral.serialize())) .setEphemeralKey(ByteString.copyFrom(senderEphemeral.serialize()))
.setCounter(counter) .setCounter(counter)
.setPreviousCounter(previousCounter) .setPreviousCounter(previousCounter)
.setCiphertext(ByteString.copyFrom(ciphertext)) .setCiphertext(ByteString.copyFrom(ciphertext))
.build().toByteArray(); .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.senderEphemeral = senderEphemeral;
this.counter = counter; this.counter = counter;
this.previousCounter = previousCounter; this.previousCounter = previousCounter;
@ -100,7 +115,7 @@ public class WhisperMessage implements CiphertextMessage {
public void verifyMac(SecretKeySpec macKey) public void verifyMac(SecretKeySpec macKey)
throws InvalidMessageException 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[] ourMac = getMac(macKey, parts[0]);
byte[] theirMac = parts[1]; byte[] theirMac = parts[1];
@ -115,7 +130,7 @@ public class WhisperMessage implements CiphertextMessage {
mac.init(macKey); mac.init(macKey);
byte[] fullMac = mac.doFinal(serialized); byte[] fullMac = mac.doFinal(serialized);
return Util.trim(fullMac, MAC_LENGTH); return ByteUtil.trim(fullMac, MAC_LENGTH);
} catch (NoSuchAlgorithmException e) { } catch (NoSuchAlgorithmException e) {
throw new AssertionError(e); throw new AssertionError(e);
} catch (java.security.InvalidKeyException e) { } catch (java.security.InvalidKeyException e) {
@ -135,7 +150,7 @@ public class WhisperMessage implements CiphertextMessage {
public static boolean isLegacy(byte[] message) { public static boolean isLegacy(byte[] message) {
return message != null && message.length >= 1 && return message != null && message.length >= 1 &&
Conversions.highBitsToInt(message[0]) <= CiphertextMessage.UNSUPPORTED_VERSION; ByteUtil.highBitsToInt(message[0]) <= CiphertextMessage.UNSUPPORTED_VERSION;
} }
} }

View File

@ -1,7 +1,7 @@
// Generated by the protocol buffer compiler. DO NOT EDIT! // Generated by the protocol buffer compiler. DO NOT EDIT!
// source: WhisperTextProtocol.proto // source: WhisperTextProtocol.proto
package org.whispersystems.textsecure.crypto.protocol; package org.whispersystems.libaxolotl.protocol;
public final class WhisperProtos { public final class WhisperProtos {
private WhisperProtos() {} private WhisperProtos() {}
@ -47,12 +47,12 @@ public final class WhisperProtos {
public static final com.google.protobuf.Descriptors.Descriptor public static final com.google.protobuf.Descriptors.Descriptor
getDescriptor() { 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 protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
internalGetFieldAccessorTable() { 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_; private int bitField0_;
@ -163,41 +163,41 @@ public final class WhisperProtos {
return super.writeReplace(); 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) com.google.protobuf.ByteString data)
throws com.google.protobuf.InvalidProtocolBufferException { throws com.google.protobuf.InvalidProtocolBufferException {
return newBuilder().mergeFrom(data).buildParsed(); 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.ByteString data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry) com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException { throws com.google.protobuf.InvalidProtocolBufferException {
return newBuilder().mergeFrom(data, extensionRegistry) return newBuilder().mergeFrom(data, extensionRegistry)
.buildParsed(); .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 { throws com.google.protobuf.InvalidProtocolBufferException {
return newBuilder().mergeFrom(data).buildParsed(); 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, byte[] data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry) com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException { throws com.google.protobuf.InvalidProtocolBufferException {
return newBuilder().mergeFrom(data, extensionRegistry) return newBuilder().mergeFrom(data, extensionRegistry)
.buildParsed(); .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 { throws java.io.IOException {
return newBuilder().mergeFrom(input).buildParsed(); 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, java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry) com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException { throws java.io.IOException {
return newBuilder().mergeFrom(input, extensionRegistry) return newBuilder().mergeFrom(input, extensionRegistry)
.buildParsed(); .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 { throws java.io.IOException {
Builder builder = newBuilder(); Builder builder = newBuilder();
if (builder.mergeDelimitedFrom(input)) { if (builder.mergeDelimitedFrom(input)) {
@ -206,7 +206,7 @@ public final class WhisperProtos {
return null; 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, java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry) com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException { throws java.io.IOException {
@ -217,12 +217,12 @@ public final class WhisperProtos {
return null; 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) com.google.protobuf.CodedInputStream input)
throws java.io.IOException { throws java.io.IOException {
return newBuilder().mergeFrom(input).buildParsed(); 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.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry) com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException { throws java.io.IOException {
@ -232,7 +232,7 @@ public final class WhisperProtos {
public static Builder newBuilder() { return Builder.create(); } public static Builder newBuilder() { return Builder.create(); }
public Builder newBuilderForType() { return newBuilder(); } 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); return newBuilder().mergeFrom(prototype);
} }
public Builder toBuilder() { return newBuilder(this); } public Builder toBuilder() { return newBuilder(this); }
@ -245,18 +245,18 @@ public final class WhisperProtos {
} }
public static final class Builder extends public static final class Builder extends
com.google.protobuf.GeneratedMessage.Builder<Builder> com.google.protobuf.GeneratedMessage.Builder<Builder>
implements org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessageOrBuilder { implements org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessageOrBuilder {
public static final com.google.protobuf.Descriptors.Descriptor public static final com.google.protobuf.Descriptors.Descriptor
getDescriptor() { 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 protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
internalGetFieldAccessorTable() { 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() { private Builder() {
maybeForceBuilderInitialization(); maybeForceBuilderInitialization();
} }
@ -292,24 +292,24 @@ public final class WhisperProtos {
public com.google.protobuf.Descriptors.Descriptor public com.google.protobuf.Descriptors.Descriptor
getDescriptorForType() { 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() { public org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage getDefaultInstanceForType() {
return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage.getDefaultInstance(); return org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage.getDefaultInstance();
} }
public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage build() { public org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage build() {
org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage result = buildPartial(); org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage result = buildPartial();
if (!result.isInitialized()) { if (!result.isInitialized()) {
throw newUninitializedMessageException(result); throw newUninitializedMessageException(result);
} }
return 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 { 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()) { if (!result.isInitialized()) {
throw newUninitializedMessageException( throw newUninitializedMessageException(
result).asInvalidProtocolBufferException(); result).asInvalidProtocolBufferException();
@ -317,8 +317,8 @@ public final class WhisperProtos {
return result; return result;
} }
public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage buildPartial() { public org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage buildPartial() {
org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage result = new org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage(this); org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage result = new org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage(this);
int from_bitField0_ = bitField0_; int from_bitField0_ = bitField0_;
int to_bitField0_ = 0; int to_bitField0_ = 0;
if (((from_bitField0_ & 0x00000001) == 0x00000001)) { if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
@ -343,16 +343,16 @@ public final class WhisperProtos {
} }
public Builder mergeFrom(com.google.protobuf.Message other) { public Builder mergeFrom(com.google.protobuf.Message other) {
if (other instanceof org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage) { if (other instanceof org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage) {
return mergeFrom((org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage)other); return mergeFrom((org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage)other);
} else { } else {
super.mergeFrom(other); super.mergeFrom(other);
return this; return this;
} }
} }
public Builder mergeFrom(org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage other) { public Builder mergeFrom(org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage other) {
if (other == org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage.getDefaultInstance()) return this; if (other == org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage.getDefaultInstance()) return this;
if (other.hasEphemeralKey()) { if (other.hasEphemeralKey()) {
setEphemeralKey(other.getEphemeralKey()); setEphemeralKey(other.getEphemeralKey());
} }
@ -566,12 +566,12 @@ public final class WhisperProtos {
public static final com.google.protobuf.Descriptors.Descriptor public static final com.google.protobuf.Descriptors.Descriptor
getDescriptor() { 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 protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
internalGetFieldAccessorTable() { 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_; private int bitField0_;
@ -700,41 +700,41 @@ public final class WhisperProtos {
return super.writeReplace(); 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) com.google.protobuf.ByteString data)
throws com.google.protobuf.InvalidProtocolBufferException { throws com.google.protobuf.InvalidProtocolBufferException {
return newBuilder().mergeFrom(data).buildParsed(); 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.ByteString data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry) com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException { throws com.google.protobuf.InvalidProtocolBufferException {
return newBuilder().mergeFrom(data, extensionRegistry) return newBuilder().mergeFrom(data, extensionRegistry)
.buildParsed(); .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 { throws com.google.protobuf.InvalidProtocolBufferException {
return newBuilder().mergeFrom(data).buildParsed(); 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, byte[] data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry) com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException { throws com.google.protobuf.InvalidProtocolBufferException {
return newBuilder().mergeFrom(data, extensionRegistry) return newBuilder().mergeFrom(data, extensionRegistry)
.buildParsed(); .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 { throws java.io.IOException {
return newBuilder().mergeFrom(input).buildParsed(); 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, java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry) com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException { throws java.io.IOException {
return newBuilder().mergeFrom(input, extensionRegistry) return newBuilder().mergeFrom(input, extensionRegistry)
.buildParsed(); .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 { throws java.io.IOException {
Builder builder = newBuilder(); Builder builder = newBuilder();
if (builder.mergeDelimitedFrom(input)) { if (builder.mergeDelimitedFrom(input)) {
@ -743,7 +743,7 @@ public final class WhisperProtos {
return null; 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, java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry) com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException { throws java.io.IOException {
@ -754,12 +754,12 @@ public final class WhisperProtos {
return null; 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) com.google.protobuf.CodedInputStream input)
throws java.io.IOException { throws java.io.IOException {
return newBuilder().mergeFrom(input).buildParsed(); 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.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry) com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException { throws java.io.IOException {
@ -769,7 +769,7 @@ public final class WhisperProtos {
public static Builder newBuilder() { return Builder.create(); } public static Builder newBuilder() { return Builder.create(); }
public Builder newBuilderForType() { return newBuilder(); } 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); return newBuilder().mergeFrom(prototype);
} }
public Builder toBuilder() { return newBuilder(this); } public Builder toBuilder() { return newBuilder(this); }
@ -782,18 +782,18 @@ public final class WhisperProtos {
} }
public static final class Builder extends public static final class Builder extends
com.google.protobuf.GeneratedMessage.Builder<Builder> com.google.protobuf.GeneratedMessage.Builder<Builder>
implements org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessageOrBuilder { implements org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessageOrBuilder {
public static final com.google.protobuf.Descriptors.Descriptor public static final com.google.protobuf.Descriptors.Descriptor
getDescriptor() { 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 protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
internalGetFieldAccessorTable() { 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() { private Builder() {
maybeForceBuilderInitialization(); maybeForceBuilderInitialization();
} }
@ -831,24 +831,24 @@ public final class WhisperProtos {
public com.google.protobuf.Descriptors.Descriptor public com.google.protobuf.Descriptors.Descriptor
getDescriptorForType() { 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() { public org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage getDefaultInstanceForType() {
return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage.getDefaultInstance(); return org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage.getDefaultInstance();
} }
public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage build() { public org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage build() {
org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage result = buildPartial(); org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage result = buildPartial();
if (!result.isInitialized()) { if (!result.isInitialized()) {
throw newUninitializedMessageException(result); throw newUninitializedMessageException(result);
} }
return 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 { 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()) { if (!result.isInitialized()) {
throw newUninitializedMessageException( throw newUninitializedMessageException(
result).asInvalidProtocolBufferException(); result).asInvalidProtocolBufferException();
@ -856,8 +856,8 @@ public final class WhisperProtos {
return result; return result;
} }
public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage buildPartial() { public org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage buildPartial() {
org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage result = new org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage(this); org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage result = new org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage(this);
int from_bitField0_ = bitField0_; int from_bitField0_ = bitField0_;
int to_bitField0_ = 0; int to_bitField0_ = 0;
if (((from_bitField0_ & 0x00000001) == 0x00000001)) { if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
@ -886,16 +886,16 @@ public final class WhisperProtos {
} }
public Builder mergeFrom(com.google.protobuf.Message other) { public Builder mergeFrom(com.google.protobuf.Message other) {
if (other instanceof org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage) { if (other instanceof org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage) {
return mergeFrom((org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage)other); return mergeFrom((org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage)other);
} else { } else {
super.mergeFrom(other); super.mergeFrom(other);
return this; return this;
} }
} }
public Builder mergeFrom(org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage other) { public Builder mergeFrom(org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage other) {
if (other == org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage.getDefaultInstance()) return this; if (other == org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage.getDefaultInstance()) return this;
if (other.hasRegistrationId()) { if (other.hasRegistrationId()) {
setRegistrationId(other.getRegistrationId()); setRegistrationId(other.getRegistrationId());
} }
@ -1137,12 +1137,12 @@ public final class WhisperProtos {
public static final com.google.protobuf.Descriptors.Descriptor public static final com.google.protobuf.Descriptors.Descriptor
getDescriptor() { 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 protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
internalGetFieldAccessorTable() { 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_; private int bitField0_;
@ -1253,41 +1253,41 @@ public final class WhisperProtos {
return super.writeReplace(); 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) com.google.protobuf.ByteString data)
throws com.google.protobuf.InvalidProtocolBufferException { throws com.google.protobuf.InvalidProtocolBufferException {
return newBuilder().mergeFrom(data).buildParsed(); 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.ByteString data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry) com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException { throws com.google.protobuf.InvalidProtocolBufferException {
return newBuilder().mergeFrom(data, extensionRegistry) return newBuilder().mergeFrom(data, extensionRegistry)
.buildParsed(); .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 { throws com.google.protobuf.InvalidProtocolBufferException {
return newBuilder().mergeFrom(data).buildParsed(); 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, byte[] data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry) com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException { throws com.google.protobuf.InvalidProtocolBufferException {
return newBuilder().mergeFrom(data, extensionRegistry) return newBuilder().mergeFrom(data, extensionRegistry)
.buildParsed(); .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 { throws java.io.IOException {
return newBuilder().mergeFrom(input).buildParsed(); 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, java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry) com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException { throws java.io.IOException {
return newBuilder().mergeFrom(input, extensionRegistry) return newBuilder().mergeFrom(input, extensionRegistry)
.buildParsed(); .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 { throws java.io.IOException {
Builder builder = newBuilder(); Builder builder = newBuilder();
if (builder.mergeDelimitedFrom(input)) { if (builder.mergeDelimitedFrom(input)) {
@ -1296,7 +1296,7 @@ public final class WhisperProtos {
return null; 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, java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry) com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException { throws java.io.IOException {
@ -1307,12 +1307,12 @@ public final class WhisperProtos {
return null; 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) com.google.protobuf.CodedInputStream input)
throws java.io.IOException { throws java.io.IOException {
return newBuilder().mergeFrom(input).buildParsed(); 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.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry) com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException { throws java.io.IOException {
@ -1322,7 +1322,7 @@ public final class WhisperProtos {
public static Builder newBuilder() { return Builder.create(); } public static Builder newBuilder() { return Builder.create(); }
public Builder newBuilderForType() { return newBuilder(); } 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); return newBuilder().mergeFrom(prototype);
} }
public Builder toBuilder() { return newBuilder(this); } public Builder toBuilder() { return newBuilder(this); }
@ -1335,18 +1335,18 @@ public final class WhisperProtos {
} }
public static final class Builder extends public static final class Builder extends
com.google.protobuf.GeneratedMessage.Builder<Builder> com.google.protobuf.GeneratedMessage.Builder<Builder>
implements org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessageOrBuilder { implements org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessageOrBuilder {
public static final com.google.protobuf.Descriptors.Descriptor public static final com.google.protobuf.Descriptors.Descriptor
getDescriptor() { 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 protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
internalGetFieldAccessorTable() { 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() { private Builder() {
maybeForceBuilderInitialization(); maybeForceBuilderInitialization();
} }
@ -1382,24 +1382,24 @@ public final class WhisperProtos {
public com.google.protobuf.Descriptors.Descriptor public com.google.protobuf.Descriptors.Descriptor
getDescriptorForType() { 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() { public org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage getDefaultInstanceForType() {
return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage.getDefaultInstance(); return org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage.getDefaultInstance();
} }
public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage build() { public org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage build() {
org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage result = buildPartial(); org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage result = buildPartial();
if (!result.isInitialized()) { if (!result.isInitialized()) {
throw newUninitializedMessageException(result); throw newUninitializedMessageException(result);
} }
return 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 { 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()) { if (!result.isInitialized()) {
throw newUninitializedMessageException( throw newUninitializedMessageException(
result).asInvalidProtocolBufferException(); result).asInvalidProtocolBufferException();
@ -1407,8 +1407,8 @@ public final class WhisperProtos {
return result; return result;
} }
public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage buildPartial() { public org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage buildPartial() {
org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage result = new org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage(this); org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage result = new org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage(this);
int from_bitField0_ = bitField0_; int from_bitField0_ = bitField0_;
int to_bitField0_ = 0; int to_bitField0_ = 0;
if (((from_bitField0_ & 0x00000001) == 0x00000001)) { if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
@ -1433,16 +1433,16 @@ public final class WhisperProtos {
} }
public Builder mergeFrom(com.google.protobuf.Message other) { public Builder mergeFrom(com.google.protobuf.Message other) {
if (other instanceof org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage) { if (other instanceof org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage) {
return mergeFrom((org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage)other); return mergeFrom((org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage)other);
} else { } else {
super.mergeFrom(other); super.mergeFrom(other);
return this; return this;
} }
} }
public Builder mergeFrom(org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage other) { public Builder mergeFrom(org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage other) {
if (other == org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage.getDefaultInstance()) return this; if (other == org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage.getDefaultInstance()) return this;
if (other.hasId()) { if (other.hasId()) {
setId(other.getId()); 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" + "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" + "\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" + "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-" + "emeralKey\030\003 \001(\014\022\023\n\013identityKey\030\004 \001(\014B7\n&" +
"org.whispersystems.textsecure.crypto.pro", "org.whispersystems.libaxolotl.protocolB\r",
"tocolB\rWhisperProtos" "WhisperProtos"
}; };
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
@ -1663,24 +1663,24 @@ public final class WhisperProtos {
com.google.protobuf.GeneratedMessage.FieldAccessorTable( com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_textsecure_WhisperMessage_descriptor, internal_static_textsecure_WhisperMessage_descriptor,
new java.lang.String[] { "EphemeralKey", "Counter", "PreviousCounter", "Ciphertext", }, new java.lang.String[] { "EphemeralKey", "Counter", "PreviousCounter", "Ciphertext", },
org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage.class, org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage.class,
org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage.Builder.class); org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage.Builder.class);
internal_static_textsecure_PreKeyWhisperMessage_descriptor = internal_static_textsecure_PreKeyWhisperMessage_descriptor =
getDescriptor().getMessageTypes().get(1); getDescriptor().getMessageTypes().get(1);
internal_static_textsecure_PreKeyWhisperMessage_fieldAccessorTable = new internal_static_textsecure_PreKeyWhisperMessage_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable( com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_textsecure_PreKeyWhisperMessage_descriptor, internal_static_textsecure_PreKeyWhisperMessage_descriptor,
new java.lang.String[] { "RegistrationId", "PreKeyId", "BaseKey", "IdentityKey", "Message", }, new java.lang.String[] { "RegistrationId", "PreKeyId", "BaseKey", "IdentityKey", "Message", },
org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage.class, org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage.class,
org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage.Builder.class); org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage.Builder.class);
internal_static_textsecure_KeyExchangeMessage_descriptor = internal_static_textsecure_KeyExchangeMessage_descriptor =
getDescriptor().getMessageTypes().get(2); getDescriptor().getMessageTypes().get(2);
internal_static_textsecure_KeyExchangeMessage_fieldAccessorTable = new internal_static_textsecure_KeyExchangeMessage_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable( com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_textsecure_KeyExchangeMessage_descriptor, internal_static_textsecure_KeyExchangeMessage_descriptor,
new java.lang.String[] { "Id", "BaseKey", "EphemeralKey", "IdentityKey", }, new java.lang.String[] { "Id", "BaseKey", "EphemeralKey", "IdentityKey", },
org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage.class, org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage.class,
org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage.Builder.class); org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage.Builder.class);
return null; return null;
} }
}; };

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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.InvalidKeyException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
@ -49,9 +66,7 @@ public class ChainKey {
mac.init(new SecretKeySpec(key, "HmacSHA256")); mac.init(new SecretKeySpec(key, "HmacSHA256"));
return mac.doFinal(seed); return mac.doFinal(seed);
} catch (NoSuchAlgorithmException e) { } catch (NoSuchAlgorithmException | InvalidKeyException e) {
throw new AssertionError(e);
} catch (InvalidKeyException e) {
throw new AssertionError(e); throw new AssertionError(e);
} }
} }

View File

@ -0,0 +1,44 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*/
package org.whispersystems.libaxolotl.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;
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
package org.whispersystems.libaxolotl.ratchet;
import android.util.Pair; import android.util.Log;
import org.whispersystems.textsecure.crypto.IdentityKey; import org.whispersystems.libaxolotl.IdentityKey;
import org.whispersystems.textsecure.crypto.IdentityKeyPair; import org.whispersystems.libaxolotl.IdentityKeyPair;
import org.whispersystems.textsecure.crypto.InvalidKeyException; import org.whispersystems.libaxolotl.InvalidKeyException;
import org.whispersystems.textsecure.crypto.ecc.Curve; import org.whispersystems.libaxolotl.SessionState;
import org.whispersystems.textsecure.crypto.ecc.ECKeyPair; import org.whispersystems.libaxolotl.ecc.Curve;
import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; import org.whispersystems.libaxolotl.ecc.ECKeyPair;
import org.whispersystems.textsecure.crypto.kdf.DerivedSecrets; import org.whispersystems.libaxolotl.ecc.ECPublicKey;
import org.whispersystems.textsecure.crypto.kdf.HKDF; import org.whispersystems.libaxolotl.kdf.DerivedSecrets;
import org.whispersystems.textsecure.storage.SessionState; 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.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
@ -47,11 +65,11 @@ public class RatchetingSession {
ECKeyPair sendingKey = Curve.generateKeyPair(true); ECKeyPair sendingKey = Curve.generateKeyPair(true);
Pair<RootKey, ChainKey> receivingChain = calculate3DHE(true, ourBaseKey, theirBaseKey, ourIdentityKey, theirIdentityKey); Pair<RootKey, ChainKey> receivingChain = calculate3DHE(true, ourBaseKey, theirBaseKey, ourIdentityKey, theirIdentityKey);
Pair<RootKey, ChainKey> sendingChain = receivingChain.first.createChain(theirEphemeralKey, sendingKey); Pair<RootKey, ChainKey> sendingChain = receivingChain.first().createChain(theirEphemeralKey, sendingKey);
sessionState.addReceiverChain(theirEphemeralKey, receivingChain.second); sessionState.addReceiverChain(theirEphemeralKey, receivingChain.second());
sessionState.setSenderChain(sendingKey, sendingChain.second); sessionState.setSenderChain(sendingKey, sendingChain.second());
sessionState.setRootKey(sendingChain.first); sessionState.setRootKey(sendingChain.first());
} }
private static void initializeSessionAsBob(SessionState sessionState, private static void initializeSessionAsBob(SessionState sessionState,
@ -67,8 +85,8 @@ public class RatchetingSession {
Pair<RootKey, ChainKey> sendingChain = calculate3DHE(false, ourBaseKey, theirBaseKey, Pair<RootKey, ChainKey> sendingChain = calculate3DHE(false, ourBaseKey, theirBaseKey,
ourIdentityKey, theirIdentityKey); ourIdentityKey, theirIdentityKey);
sessionState.setSenderChain(ourEphemeralKey, sendingChain.second); sessionState.setSenderChain(ourEphemeralKey, sendingChain.second());
sessionState.setRootKey(sendingChain.first); sessionState.setRootKey(sendingChain.first());
} }
private static Pair<RootKey, ChainKey> calculate3DHE(boolean isAlice, private static Pair<RootKey, ChainKey> calculate3DHE(boolean isAlice,

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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<RootKey, ChainKey> 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);
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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));
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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<bytes.length;i++) {
appendHexChar(buf, bytes[i]);
}
return buf.toString();
}
public static byte[] fromStringCondensed(String encoded) throws IOException {
final char[] data = encoded.toCharArray();
final int len = data.length;
if ((len & 0x01) != 0) {
throw new IOException("Odd number of characters.");
}
final byte[] out = new byte[len >> 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]);
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
package org.whispersystems.libaxolotl.util;
public class Pair<T1, T2> {
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);
}
}

View File

@ -23,6 +23,8 @@ dependencies {
compile 'com.madgag:sc-light-jdk15on:1.47.0.2' compile 'com.madgag:sc-light-jdk15on:1.47.0.2'
compile 'com.googlecode.libphonenumber:libphonenumber:6.1' compile 'com.googlecode.libphonenumber:libphonenumber:6.1'
compile 'org.whispersystems:gson:2.2.4' compile 'org.whispersystems:gson:2.2.4'
compile project(':libaxolotl')
} }
android { android {
@ -45,6 +47,12 @@ android {
} }
} }
tasks.whenTaskAdded { task ->
if (task.name.equals("lint")) {
task.enabled = false
}
}
version '0.1' version '0.1'
group 'org.whispersystems.textsecure' group 'org.whispersystems.textsecure'
archivesBaseName = 'textsecure-library' archivesBaseName = 'textsecure-library'

View File

@ -18,6 +18,8 @@ package org.whispersystems.textsecure.crypto;
import android.util.Log; 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.Hex;
import org.whispersystems.textsecure.util.Util; import org.whispersystems.textsecure.util.Util;

View File

@ -18,6 +18,8 @@ package org.whispersystems.textsecure.crypto;
import android.util.Log; import android.util.Log;
import org.whispersystems.libaxolotl.InvalidMacException;
import org.whispersystems.libaxolotl.InvalidMessageException;
import org.whispersystems.textsecure.util.Util; import org.whispersystems.textsecure.util.Util;
import java.io.File; import java.io.File;

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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<IdentityKey> CREATOR = new Parcelable.Creator<IdentityKey>() {
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);
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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<IdentityKeyParcelable> CREATOR = new Parcelable.Creator<IdentityKeyParcelable>() {
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());
}
}

View File

@ -1,40 +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 <http://www.gnu.org/licenses/>.
*/
package org.whispersystems.textsecure.crypto;
public class InvalidVersionException extends Exception {
public InvalidVersionException() {
// TODO Auto-generated constructor stub
}
public InvalidVersionException(String detailMessage) {
super(detailMessage);
// TODO Auto-generated constructor stub
}
public InvalidVersionException(Throwable throwable) {
super(throwable);
// TODO Auto-generated constructor stub
}
public InvalidVersionException(String detailMessage, Throwable throwable) {
super(detailMessage, throwable);
// TODO Auto-generated constructor stub
}
}

View File

@ -19,8 +19,9 @@ package org.whispersystems.textsecure.crypto;
import android.util.Log; import android.util.Log;
import org.whispersystems.textsecure.crypto.ecc.Curve; import org.whispersystems.libaxolotl.InvalidMessageException;
import org.whispersystems.textsecure.crypto.ecc.ECPrivateKey; import org.whispersystems.libaxolotl.ecc.Curve;
import org.whispersystems.libaxolotl.ecc.ECPrivateKey;
import org.whispersystems.textsecure.util.Base64; import org.whispersystems.textsecure.util.Base64;
import org.whispersystems.textsecure.util.Hex; import org.whispersystems.textsecure.util.Hex;
@ -84,12 +85,12 @@ public class MasterCipher {
} }
public ECPrivateKey decryptKey(byte[] key) public ECPrivateKey decryptKey(byte[] key)
throws org.whispersystems.textsecure.crypto.InvalidKeyException throws org.whispersystems.libaxolotl.InvalidKeyException
{ {
try { try {
return Curve.decodePrivatePoint(decryptBytes(key)); return Curve.decodePrivatePoint(decryptBytes(key));
} catch (InvalidMessageException ime) { } catch (InvalidMessageException ime) {
throw new org.whispersystems.textsecure.crypto.InvalidKeyException(ime); throw new org.whispersystems.libaxolotl.InvalidKeyException(ime);
} }
} }

View File

@ -22,8 +22,8 @@ import android.util.Log;
import com.google.thoughtcrimegson.Gson; import com.google.thoughtcrimegson.Gson;
import org.whispersystems.textsecure.crypto.ecc.Curve25519; import org.whispersystems.libaxolotl.ecc.Curve25519;
import org.whispersystems.textsecure.crypto.ecc.ECKeyPair; import org.whispersystems.libaxolotl.ecc.ECKeyPair;
import org.whispersystems.textsecure.storage.InvalidKeyIdException; import org.whispersystems.textsecure.storage.InvalidKeyIdException;
import org.whispersystems.textsecure.storage.PreKeyRecord; import org.whispersystems.textsecure.storage.PreKeyRecord;
import org.whispersystems.textsecure.util.Medium; import org.whispersystems.textsecure.util.Medium;

View File

@ -19,8 +19,9 @@ package org.whispersystems.textsecure.crypto;
import android.util.Log; import android.util.Log;
import org.whispersystems.textsecure.crypto.ecc.Curve; import org.whispersystems.libaxolotl.InvalidKeyException;
import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; import org.whispersystems.libaxolotl.ecc.Curve;
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
import org.whispersystems.textsecure.util.Conversions; import org.whispersystems.textsecure.util.Conversions;
import org.whispersystems.textsecure.util.Hex; import org.whispersystems.textsecure.util.Hex;
import org.whispersystems.textsecure.util.Util; import org.whispersystems.textsecure.util.Util;

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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.");
}
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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();
}
}

View File

@ -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();
}

View File

@ -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;
}
}

View File

@ -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<RootKey, ChainKey> 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<RootKey, ChainKey>(newRootKey, newChainKey);
}
}

View File

@ -2,7 +2,7 @@ package org.whispersystems.textsecure.push;
import android.util.Log; 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.util.Base64;
import org.whispersystems.textsecure.push.PushMessageProtos.IncomingPushMessageSignal; import org.whispersystems.textsecure.push.PushMessageProtos.IncomingPushMessageSignal;
import org.whispersystems.textsecure.util.Hex; import org.whispersystems.textsecure.util.Hex;

View File

@ -10,10 +10,10 @@ import com.google.thoughtcrimegson.JsonSerializationContext;
import com.google.thoughtcrimegson.JsonSerializer; import com.google.thoughtcrimegson.JsonSerializer;
import com.google.thoughtcrimegson.annotations.Expose; import com.google.thoughtcrimegson.annotations.Expose;
import org.whispersystems.textsecure.crypto.IdentityKey; import org.whispersystems.libaxolotl.IdentityKey;
import org.whispersystems.textsecure.crypto.InvalidKeyException; import org.whispersystems.libaxolotl.InvalidKeyException;
import org.whispersystems.textsecure.crypto.ecc.Curve; import org.whispersystems.libaxolotl.ecc.Curve;
import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; import org.whispersystems.libaxolotl.ecc.ECPublicKey;
import org.whispersystems.textsecure.util.Base64; import org.whispersystems.textsecure.util.Base64;
import java.io.IOException; import java.io.IOException;

View File

@ -23,7 +23,7 @@ import com.google.thoughtcrimegson.Gson;
import com.google.thoughtcrimegson.JsonParseException; import com.google.thoughtcrimegson.JsonParseException;
import org.apache.http.conn.ssl.StrictHostnameVerifier; 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.storage.PreKeyRecord;
import org.whispersystems.textsecure.util.Base64; import org.whispersystems.textsecure.util.Base64;
import org.whispersystems.textsecure.util.BlacklistingTrustManager; import org.whispersystems.textsecure.util.BlacklistingTrustManager;

View File

@ -5,14 +5,14 @@ import android.util.Log;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import org.whispersystems.textsecure.crypto.InvalidKeyException; import org.whispersystems.libaxolotl.InvalidKeyException;
import org.whispersystems.textsecure.crypto.InvalidMessageException; 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.MasterCipher;
import org.whispersystems.textsecure.crypto.MasterSecret; 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.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;

View File

@ -30,7 +30,7 @@ import java.nio.channels.FileChannel;
public abstract class Record { 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"; protected static final String SESSIONS_DIRECTORY_V2 = "sessions-v2";
public static final String PREKEY_DIRECTORY = "prekeys"; public static final String PREKEY_DIRECTORY = "prekeys";
@ -48,7 +48,7 @@ public abstract class Record {
delete(this.context, this.directory, this.address); 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(); getAddressFile(context, directory, address).delete();
} }

View File

@ -3,8 +3,11 @@ package org.whispersystems.textsecure.storage;
import android.content.Context; import android.content.Context;
import android.util.Log; 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.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. * Helper class for generating key pairs and calculating ECDH agreements.

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@ -19,7 +19,9 @@ package org.whispersystems.textsecure.storage;
import android.content.Context; import android.content.Context;
import android.util.Log; 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.MasterCipher;
import org.whispersystems.textsecure.crypto.MasterSecret; import org.whispersystems.textsecure.crypto.MasterSecret;
@ -41,7 +43,7 @@ import static org.whispersystems.textsecure.storage.StorageProtos.SessionStructu
* @author Moxie Marlinspike * @author Moxie Marlinspike
*/ */
public class SessionRecordV2 extends Record { public class SessionRecordV2 extends Record implements SessionStore {
private static final Object FILE_LOCK = new Object(); private static final Object FILE_LOCK = new Object();
@ -51,8 +53,8 @@ public class SessionRecordV2 extends Record {
private final MasterSecret masterSecret; private final MasterSecret masterSecret;
private SessionState sessionState = new SessionState(SessionStructure.newBuilder().build()); private TextSecureSessionState sessionState = new TextSecureSessionState(SessionStructure.newBuilder().build());
private List<SessionState> previousStates = new LinkedList<SessionState>(); private List<SessionState> previousStates = new LinkedList<SessionState>();
public SessionRecordV2(Context context, MasterSecret masterSecret, RecipientDevice peer) { public SessionRecordV2(Context context, MasterSecret masterSecret, RecipientDevice peer) {
this(context, masterSecret, peer.getRecipientId(), peer.getDeviceId()); this(context, masterSecret, peer.getRecipientId(), peer.getDeviceId());
@ -68,12 +70,12 @@ public class SessionRecordV2 extends Record {
return recipientId + (deviceId == RecipientDevice.DEFAULT_DEVICE_ID ? "" : "." + deviceId); return recipientId + (deviceId == RecipientDevice.DEFAULT_DEVICE_ID ? "" : "." + deviceId);
} }
public SessionState getSessionState() { public TextSecureSessionState getSessionState() {
return sessionState; return sessionState;
} }
public List<SessionState> getPreviousSessions() { public List<SessionState> getPreviousSessionStates() {
return previousStates; return previousStates;
} }
@ -139,13 +141,13 @@ public class SessionRecordV2 extends Record {
} }
public void clear() { public void clear() {
this.sessionState = new SessionState(SessionStructure.newBuilder().build()); this.sessionState = new TextSecureSessionState(SessionStructure.newBuilder().build());
this.previousStates = new LinkedList<SessionState>(); this.previousStates = new LinkedList<SessionState>();
} }
public void archiveCurrentState() { public void archiveCurrentState() {
this.previousStates.add(sessionState); this.previousStates.add(sessionState);
this.sessionState = new SessionState(SessionStructure.newBuilder().build()); this.sessionState = new TextSecureSessionState(SessionStructure.newBuilder().build());
} }
public void save() { public void save() {
@ -154,7 +156,7 @@ public class SessionRecordV2 extends Record {
List<SessionStructure> previousStructures = new LinkedList<SessionStructure>(); List<SessionStructure> previousStructures = new LinkedList<SessionStructure>();
for (SessionState previousState : previousStates) { for (SessionState previousState : previousStates) {
previousStructures.add(previousState.getStructure()); previousStructures.add(((TextSecureSessionState)previousState).getStructure());
} }
RecordStructure record = RecordStructure.newBuilder() RecordStructure record = RecordStructure.newBuilder()
@ -194,16 +196,16 @@ public class SessionRecordV2 extends Record {
if (versionMarker == SINGLE_STATE_VERSION) { if (versionMarker == SINGLE_STATE_VERSION) {
byte[] plaintextBytes = cipher.decryptBytes(encryptedBlob); byte[] plaintextBytes = cipher.decryptBytes(encryptedBlob);
SessionStructure sessionStructure = SessionStructure.parseFrom(plaintextBytes); SessionStructure sessionStructure = SessionStructure.parseFrom(plaintextBytes);
this.sessionState = new SessionState(sessionStructure); this.sessionState = new TextSecureSessionState(sessionStructure);
} else if (versionMarker == ARCHIVE_STATES_VERSION) { } else if (versionMarker == ARCHIVE_STATES_VERSION) {
byte[] plaintextBytes = cipher.decryptBytes(encryptedBlob); byte[] plaintextBytes = cipher.decryptBytes(encryptedBlob);
RecordStructure recordStructure = RecordStructure.parseFrom(plaintextBytes); RecordStructure recordStructure = RecordStructure.parseFrom(plaintextBytes);
this.sessionState = new SessionState(recordStructure.getCurrentSession()); this.sessionState = new TextSecureSessionState(recordStructure.getCurrentSession());
this.previousStates = new LinkedList<SessionState>(); this.previousStates = new LinkedList<SessionState>();
for (SessionStructure sessionStructure : recordStructure.getPreviousSessionsList()) { for (SessionStructure sessionStructure : recordStructure.getPreviousSessionsList()) {
this.previousStates.add(new SessionState(sessionStructure)); this.previousStates.add(new TextSecureSessionState(sessionStructure));
} }
} else { } else {
throw new AssertionError("Unknown version: " + versionMarker); throw new AssertionError("Unknown version: " + versionMarker);
@ -217,8 +219,9 @@ public class SessionRecordV2 extends Record {
} catch (IOException ioe) { } catch (IOException ioe) {
Log.w("SessionRecordV2", ioe); Log.w("SessionRecordV2", ioe);
// XXX // XXX
} catch (InvalidMessageException e) { } catch (InvalidMessageException ime) {
Log.w("SessionRecordV2", e); Log.w("SessionRecordV2", ime);
// XXX
} }
} }
} }

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
package org.whispersystems.textsecure.storage; package org.whispersystems.textsecure.storage;
import android.util.Log; import android.util.Log;
import android.util.Pair;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import org.whispersystems.textsecure.crypto.IdentityKey; import org.whispersystems.libaxolotl.IdentityKey;
import org.whispersystems.textsecure.crypto.IdentityKeyPair; import org.whispersystems.libaxolotl.IdentityKeyPair;
import org.whispersystems.textsecure.crypto.InvalidKeyException; import org.whispersystems.libaxolotl.InvalidKeyException;
import org.whispersystems.textsecure.crypto.ecc.Curve; import org.whispersystems.libaxolotl.SessionState;
import org.whispersystems.textsecure.crypto.ecc.ECKeyPair; import org.whispersystems.libaxolotl.ecc.Curve;
import org.whispersystems.textsecure.crypto.ecc.ECPrivateKey; import org.whispersystems.libaxolotl.ecc.ECKeyPair;
import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; import org.whispersystems.libaxolotl.ecc.ECPrivateKey;
import org.whispersystems.textsecure.crypto.ratchet.ChainKey; import org.whispersystems.libaxolotl.ecc.ECPublicKey;
import org.whispersystems.textsecure.crypto.ratchet.MessageKeys; import org.whispersystems.libaxolotl.ratchet.ChainKey;
import org.whispersystems.textsecure.crypto.ratchet.RootKey; 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.Chain;
import org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange; import org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange;
import org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey; 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; import static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure;
public class SessionState { public class TextSecureSessionState implements SessionState {
private SessionStructure sessionStructure; private SessionStructure sessionStructure;
public SessionState(SessionStructure sessionStructure) { public TextSecureSessionState(SessionStructure sessionStructure) {
this.sessionStructure = sessionStructure; this.sessionStructure = sessionStructure;
} }
@ -160,7 +177,7 @@ public class SessionState {
public ChainKey getReceiverChainKey(ECPublicKey senderEphemeral) { public ChainKey getReceiverChainKey(ECPublicKey senderEphemeral) {
Pair<Chain,Integer> receiverChainAndIndex = getReceiverChain(senderEphemeral); Pair<Chain,Integer> receiverChainAndIndex = getReceiverChain(senderEphemeral);
Chain receiverChain = receiverChainAndIndex.first; Chain receiverChain = receiverChainAndIndex.first();
if (receiverChain == null) { if (receiverChain == null) {
return null; return null;
@ -225,7 +242,7 @@ public class SessionState {
public boolean hasMessageKeys(ECPublicKey senderEphemeral, int counter) { public boolean hasMessageKeys(ECPublicKey senderEphemeral, int counter) {
Pair<Chain,Integer> chainAndIndex = getReceiverChain(senderEphemeral); Pair<Chain,Integer> chainAndIndex = getReceiverChain(senderEphemeral);
Chain chain = chainAndIndex.first; Chain chain = chainAndIndex.first();
if (chain == null) { if (chain == null) {
return false; return false;
@ -244,7 +261,7 @@ public class SessionState {
public MessageKeys removeMessageKeys(ECPublicKey senderEphemeral, int counter) { public MessageKeys removeMessageKeys(ECPublicKey senderEphemeral, int counter) {
Pair<Chain,Integer> chainAndIndex = getReceiverChain(senderEphemeral); Pair<Chain,Integer> chainAndIndex = getReceiverChain(senderEphemeral);
Chain chain = chainAndIndex.first; Chain chain = chainAndIndex.first();
if (chain == null) { if (chain == null) {
return null; return null;
@ -272,7 +289,7 @@ public class SessionState {
.build(); .build();
this.sessionStructure = this.sessionStructure.toBuilder() this.sessionStructure = this.sessionStructure.toBuilder()
.setReceiverChains(chainAndIndex.second, updatedChain) .setReceiverChains(chainAndIndex.second(), updatedChain)
.build(); .build();
return result; return result;
@ -280,7 +297,7 @@ public class SessionState {
public void setMessageKeys(ECPublicKey senderEphemeral, MessageKeys messageKeys) { public void setMessageKeys(ECPublicKey senderEphemeral, MessageKeys messageKeys) {
Pair<Chain,Integer> chainAndIndex = getReceiverChain(senderEphemeral); Pair<Chain,Integer> chainAndIndex = getReceiverChain(senderEphemeral);
Chain chain = chainAndIndex.first; Chain chain = chainAndIndex.first();
Chain.MessageKey messageKeyStructure = Chain.MessageKey.newBuilder() Chain.MessageKey messageKeyStructure = Chain.MessageKey.newBuilder()
.setCipherKey(ByteString.copyFrom(messageKeys.getCipherKey().getEncoded())) .setCipherKey(ByteString.copyFrom(messageKeys.getCipherKey().getEncoded()))
.setMacKey(ByteString.copyFrom(messageKeys.getMacKey().getEncoded())) .setMacKey(ByteString.copyFrom(messageKeys.getMacKey().getEncoded()))
@ -292,13 +309,13 @@ public class SessionState {
.build(); .build();
this.sessionStructure = this.sessionStructure.toBuilder() this.sessionStructure = this.sessionStructure.toBuilder()
.setReceiverChains(chainAndIndex.second, updatedChain) .setReceiverChains(chainAndIndex.second(), updatedChain)
.build(); .build();
} }
public void setReceiverChainKey(ECPublicKey senderEphemeral, ChainKey chainKey) { public void setReceiverChainKey(ECPublicKey senderEphemeral, ChainKey chainKey) {
Pair<Chain,Integer> chainAndIndex = getReceiverChain(senderEphemeral); Pair<Chain,Integer> chainAndIndex = getReceiverChain(senderEphemeral);
Chain chain = chainAndIndex.first; Chain chain = chainAndIndex.first();
Chain.ChainKey chainKeyStructure = Chain.ChainKey.newBuilder() Chain.ChainKey chainKeyStructure = Chain.ChainKey.newBuilder()
.setKey(ByteString.copyFrom(chainKey.getKey())) .setKey(ByteString.copyFrom(chainKey.getKey()))
@ -308,7 +325,7 @@ public class SessionState {
Chain updatedChain = chain.toBuilder().setChainKey(chainKeyStructure).build(); Chain updatedChain = chain.toBuilder().setChainKey(chainKeyStructure).build();
this.sessionStructure = this.sessionStructure.toBuilder() this.sessionStructure = this.sessionStructure.toBuilder()
.setReceiverChains(chainAndIndex.second, updatedChain) .setReceiverChains(chainAndIndex.second(), updatedChain)
.build(); .build();
} }

View File

@ -15,10 +15,13 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.whispersystems.textsecure.storage; package org.whispersystems.textsecure.storage.legacy;
import android.content.Context; import android.content.Context;
import org.whispersystems.textsecure.storage.CanonicalRecipient;
import org.whispersystems.textsecure.storage.Record;
public class LocalKeyRecord { public class LocalKeyRecord {
public static void delete(Context context, CanonicalRecipient recipient) { public static void delete(Context context, CanonicalRecipient recipient) {

View File

@ -14,21 +14,12 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.whispersystems.textsecure.storage; package org.whispersystems.textsecure.storage.legacy;
import android.content.Context; import android.content.Context;
import android.util.Log;
import org.whispersystems.textsecure.crypto.InvalidKeyException; import org.whispersystems.textsecure.storage.CanonicalRecipient;
import org.whispersystems.textsecure.crypto.PublicKey; import org.whispersystems.textsecure.storage.Record;
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;
/** /**
* Represents the current and last public key belonging to the "remote" * Represents the current and last public key belonging to the "remote"

View File

@ -1,7 +1,10 @@
package org.whispersystems.textsecure.storage; package org.whispersystems.textsecure.storage.legacy;
import android.content.Context; import android.content.Context;
import org.whispersystems.textsecure.storage.CanonicalRecipient;
import org.whispersystems.textsecure.storage.Record;
/** /**
* A disk record representing a current session. * A disk record representing a current session.
* *

View File

@ -1 +1 @@
include ':library' include ':library', ':libaxolotl'

View File

@ -102,7 +102,7 @@ import org.thoughtcrime.securesms.util.EncryptedCharacterCalculator;
import org.thoughtcrime.securesms.util.GroupUtil; import org.thoughtcrime.securesms.util.GroupUtil;
import org.thoughtcrime.securesms.util.MemoryCleaner; import org.thoughtcrime.securesms.util.MemoryCleaner;
import org.thoughtcrime.securesms.util.TextSecurePreferences; 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.MasterCipher;
import org.whispersystems.textsecure.crypto.MasterSecret; import org.whispersystems.textsecure.crypto.MasterSecret;
import org.whispersystems.textsecure.storage.RecipientDevice; import org.whispersystems.textsecure.storage.RecipientDevice;

View File

@ -20,7 +20,7 @@ import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.widget.Toast; import android.widget.Toast;
import org.whispersystems.textsecure.crypto.SerializableKey; import org.whispersystems.libaxolotl.IdentityKey;
import org.whispersystems.textsecure.util.Base64; import org.whispersystems.textsecure.util.Base64;
import org.thoughtcrime.securesms.util.Dialogs; import org.thoughtcrime.securesms.util.Dialogs;
import org.thoughtcrime.securesms.util.DynamicTheme; import org.thoughtcrime.securesms.util.DynamicTheme;
@ -112,8 +112,8 @@ public abstract class KeyScanningActivity extends PassphraseRequiredSherlockActi
protected abstract String getNotVerifiedTitle(); protected abstract String getNotVerifiedTitle();
protected abstract String getNotVerifiedMessage(); protected abstract String getNotVerifiedMessage();
protected abstract SerializableKey getIdentityKeyToCompare(); protected abstract IdentityKey getIdentityKeyToCompare();
protected abstract SerializableKey getIdentityKeyToDisplay(); protected abstract IdentityKey getIdentityKeyToDisplay();
protected abstract String getVerifiedTitle(); protected abstract String getVerifiedTitle();
protected abstract String getVerifiedMessage(); protected abstract String getVerifiedMessage();

View File

@ -34,20 +34,21 @@ import org.thoughtcrime.securesms.crypto.DecryptingQueue;
import org.thoughtcrime.securesms.crypto.KeyExchangeProcessor; import org.thoughtcrime.securesms.crypto.KeyExchangeProcessor;
import org.thoughtcrime.securesms.crypto.KeyExchangeProcessorV2; import org.thoughtcrime.securesms.crypto.KeyExchangeProcessorV2;
import org.thoughtcrime.securesms.crypto.protocol.KeyExchangeMessage; import org.thoughtcrime.securesms.crypto.protocol.KeyExchangeMessage;
import org.whispersystems.textsecure.crypto.LegacyMessageException;
import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.service.SendReceiveService; import org.thoughtcrime.securesms.service.SendReceiveService;
import org.thoughtcrime.securesms.sms.SmsTransportDetails; import org.thoughtcrime.securesms.sms.SmsTransportDetails;
import org.thoughtcrime.securesms.util.MemoryCleaner; import org.thoughtcrime.securesms.util.MemoryCleaner;
import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.textsecure.crypto.IdentityKey; import org.whispersystems.libaxolotl.IdentityKey;
import org.whispersystems.textsecure.crypto.InvalidKeyException; import org.whispersystems.libaxolotl.InvalidKeyException;
import org.whispersystems.textsecure.crypto.InvalidMessageException; import org.whispersystems.libaxolotl.InvalidMessageException;
import org.whispersystems.textsecure.crypto.InvalidVersionException; 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.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.push.IncomingPushMessage;
import org.whispersystems.textsecure.storage.InvalidKeyIdException; import org.whispersystems.textsecure.storage.InvalidKeyIdException;
import org.whispersystems.textsecure.storage.RecipientDevice; import org.whispersystems.textsecure.storage.RecipientDevice;
@ -136,7 +137,7 @@ public class ReceiveKeyActivity extends Activity {
Intent intent = new Intent(ReceiveKeyActivity.this, VerifyIdentityActivity.class); Intent intent = new Intent(ReceiveKeyActivity.this, VerifyIdentityActivity.class);
intent.putExtra("recipient", recipient); intent.putExtra("recipient", recipient);
intent.putExtra("master_secret", masterSecret); intent.putExtra("master_secret", masterSecret);
intent.putExtra("remote_identity", remoteIdentity); intent.putExtra("remote_identity", new IdentityKeyParcelable(remoteIdentity));
startActivity(intent); startActivity(intent);
} }
}, getString(R.string.ReceiveKeyActivity_the_signature_on_this_key_exchange_is_different).length() +1, }, getString(R.string.ReceiveKeyActivity_the_signature_on_this_key_exchange_is_different).length() +1,

View File

@ -26,7 +26,8 @@ import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.DynamicLanguage; import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicTheme; import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.MemoryCleaner; 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.crypto.MasterSecret;
import org.whispersystems.textsecure.storage.Session; import org.whispersystems.textsecure.storage.Session;
@ -83,7 +84,12 @@ public class VerifyIdentityActivity extends KeyScanningActivity {
} }
private void initializeRemoteIdentityKey() { 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) { if (identityKey == null) {
identityKey = Session.getRemoteIdentityKey(this, masterSecret, recipient); identityKey = Session.getRemoteIdentityKey(this, masterSecret, recipient);

View File

@ -19,7 +19,8 @@ package org.thoughtcrime.securesms;
import android.os.Bundle; import android.os.Bundle;
import android.widget.TextView; 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. * Activity for displaying an identity key.
@ -28,6 +29,9 @@ import org.whispersystems.textsecure.crypto.IdentityKey;
*/ */
public class ViewIdentityActivity extends KeyScanningActivity { public class ViewIdentityActivity extends KeyScanningActivity {
public static final String IDENTITY_KEY = "identity_key";
public static final String TITLE = "title";
private TextView identityFingerprint; private TextView identityFingerprint;
private IdentityKey identityKey; private IdentityKey identityKey;
@ -54,12 +58,18 @@ public class ViewIdentityActivity extends KeyScanningActivity {
} }
private void initializeResources() { 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); this.identityFingerprint = (TextView)findViewById(R.id.identity_fingerprint);
String title = getIntent().getStringExtra("title"); String title = getIntent().getStringExtra(TITLE);
if (title != null) { if (title != null) {
getSupportActionBar().setTitle(getIntent().getStringExtra("title")); getSupportActionBar().setTitle(getIntent().getStringExtra(TITLE));
} }
} }

View File

@ -17,20 +17,14 @@
*/ */
package org.thoughtcrime.securesms; 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.os.Bundle;
import android.widget.Toast;
import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuInflater; import com.actionbarsherlock.view.MenuInflater;
import com.actionbarsherlock.view.MenuItem; import com.actionbarsherlock.view.MenuItem;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil; import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.util.Dialogs; import org.whispersystems.textsecure.crypto.IdentityKeyParcelable;
import org.whispersystems.textsecure.crypto.MasterSecret;
/** /**
* Activity that displays the local identity key and offers the option to regenerate it. * 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 { public class ViewLocalIdentityActivity extends ViewIdentityActivity {
private MasterSecret masterSecret;
public void onCreate(Bundle bundle) { public void onCreate(Bundle bundle) {
this.masterSecret = getIntent().getParcelableExtra("master_secret"); getIntent().putExtra(ViewIdentityActivity.IDENTITY_KEY,
new IdentityKeyParcelable(IdentityKeyUtil.getIdentityKey(this)));
getIntent().putExtra("identity_key", IdentityKeyUtil.getIdentityKey(this)); getIntent().putExtra(ViewIdentityActivity.TITLE,
getIntent().putExtra("title", getString(R.string.ViewIdentityActivity_my_identity_fingerprint)); getString(R.string.ViewIdentityActivity_my_identity_fingerprint));
super.onCreate(bundle); super.onCreate(bundle);
} }
@ -64,62 +56,9 @@ public class ViewLocalIdentityActivity extends ViewIdentityActivity {
super.onOptionsItemSelected(item); super.onOptionsItemSelected(item);
switch (item.getItemId()) { 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; 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<Void, Void, Void>() {
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();
}
} }

View File

@ -17,7 +17,6 @@
package org.thoughtcrime.securesms.contacts; package org.thoughtcrime.securesms.contacts;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context; import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.database.MergeCursor; import android.database.MergeCursor;
@ -25,7 +24,6 @@ import android.net.Uri;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.provider.ContactsContract; import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Im;
import android.provider.ContactsContract.CommonDataKinds.Phone; import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.Contacts; import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data; 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.CursorLoader;
import android.support.v4.content.Loader; import android.support.v4.content.Loader;
import android.telephony.PhoneNumberUtils; 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.directory.Directory;
import org.whispersystems.textsecure.util.Base64;
import java.io.IOException;
import java.lang.Long;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.LinkedList; import java.util.LinkedList;
@ -248,49 +240,6 @@ public class ContactAccessor {
return Phone.getTypeLabel(mContext.getResources(), type, label); return Phone.getTypeLabel(mContext.getResources(), type, label);
} }
public void insertIdentityKey(Context context, List<Long> 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) { private long getContactIdFromLookupUri(Context context, Uri uri) {
Cursor cursor = null; Cursor cursor = null;

View File

@ -17,15 +17,15 @@
*/ */
package org.thoughtcrime.securesms.crypto; package org.thoughtcrime.securesms.crypto;
import org.whispersystems.textsecure.crypto.InvalidKeyException; import org.whispersystems.libaxolotl.InvalidKeyException;
import org.whispersystems.textsecure.crypto.InvalidMessageException; 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.MasterCipher;
import org.whispersystems.textsecure.crypto.MasterSecret; import org.whispersystems.textsecure.crypto.MasterSecret;
import org.whispersystems.textsecure.crypto.PublicKey; 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.Base64;
import org.whispersystems.textsecure.util.Conversions; import org.whispersystems.textsecure.util.Conversions;
import org.whispersystems.textsecure.util.Util; import org.whispersystems.textsecure.util.Util;

View File

@ -17,9 +17,8 @@
*/ */
package org.thoughtcrime.securesms.crypto; package org.thoughtcrime.securesms.crypto;
import org.whispersystems.textsecure.crypto.ecc.Curve; import org.whispersystems.libaxolotl.ecc.ECPrivateKey;
import org.whispersystems.textsecure.crypto.ecc.ECPrivateKey; import org.whispersystems.libaxolotl.ecc.ECPublicKey;
import org.whispersystems.textsecure.crypto.ecc.ECPublicKey;
/** /**
* When a user first initializes TextSecure, a few secrets * When a user first initializes TextSecure, a few secrets
@ -40,7 +39,7 @@ import org.whispersystems.textsecure.crypto.ecc.ECPublicKey;
public class AsymmetricMasterSecret { public class AsymmetricMasterSecret {
private final ECPublicKey djbPublicKey; private final ECPublicKey djbPublicKey;
private final ECPrivateKey djbPrivateKey; private final ECPrivateKey djbPrivateKey;

View File

@ -23,7 +23,6 @@ import android.database.Cursor;
import android.util.Log; import android.util.Log;
import org.thoughtcrime.securesms.crypto.protocol.KeyExchangeMessage; import org.thoughtcrime.securesms.crypto.protocol.KeyExchangeMessage;
import org.whispersystems.textsecure.crypto.LegacyMessageException;
import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.EncryptingSmsDatabase; import org.thoughtcrime.securesms.database.EncryptingSmsDatabase;
import org.thoughtcrime.securesms.database.MmsDatabase; 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.service.SendReceiveService;
import org.thoughtcrime.securesms.sms.SmsTransportDetails; import org.thoughtcrime.securesms.sms.SmsTransportDetails;
import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.textsecure.crypto.DuplicateMessageException; import org.whispersystems.libaxolotl.DuplicateMessageException;
import org.whispersystems.textsecure.crypto.InvalidKeyException; import org.whispersystems.libaxolotl.InvalidKeyException;
import org.whispersystems.textsecure.crypto.InvalidMessageException; import org.whispersystems.libaxolotl.InvalidMessageException;
import org.whispersystems.textsecure.crypto.InvalidVersionException; 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.MasterSecret;
import org.whispersystems.textsecure.crypto.SessionCipher; import org.whispersystems.textsecure.crypto.SessionCipherFactory;
import org.whispersystems.textsecure.crypto.protocol.WhisperMessage;
import org.whispersystems.textsecure.push.IncomingPushMessage; import org.whispersystems.textsecure.push.IncomingPushMessage;
import org.whispersystems.textsecure.storage.RecipientDevice; import org.whispersystems.textsecure.storage.RecipientDevice;
import org.whispersystems.textsecure.storage.Session; import org.whispersystems.textsecure.storage.Session;
@ -205,7 +206,7 @@ public class DecryptingQueue {
return; return;
} }
SessionCipher sessionCipher = SessionCipher.createFor(context, masterSecret, recipientDevice); SessionCipher sessionCipher = SessionCipherFactory.getInstance(context, masterSecret, recipientDevice);
byte[] plaintextBody = sessionCipher.decrypt(message.getBody()); byte[] plaintextBody = sessionCipher.decrypt(message.getBody());
message = message.withBody(plaintextBody); message = message.withBody(plaintextBody);
@ -290,7 +291,7 @@ public class DecryptingQueue {
Log.w("DecryptingQueue", "Decrypting: " + Hex.toString(ciphertextPduBytes)); Log.w("DecryptingQueue", "Decrypting: " + Hex.toString(ciphertextPduBytes));
TextTransport transportDetails = new TextTransport(); TextTransport transportDetails = new TextTransport();
SessionCipher sessionCipher = SessionCipher.createFor(context, masterSecret, recipientDevice); SessionCipher sessionCipher = SessionCipherFactory.getInstance(context, masterSecret, recipientDevice);
byte[] decodedCiphertext = transportDetails.getDecodedMessage(ciphertextPduBytes); byte[] decodedCiphertext = transportDetails.getDecodedMessage(ciphertextPduBytes);
try { try {
@ -385,7 +386,7 @@ public class DecryptingQueue {
return; return;
} }
SessionCipher sessionCipher = SessionCipher.createFor(context, masterSecret, recipientDevice); SessionCipher sessionCipher = SessionCipherFactory.getInstance(context, masterSecret, recipientDevice);
byte[] paddedPlaintext = sessionCipher.decrypt(decodedCiphertext); byte[] paddedPlaintext = sessionCipher.decrypt(decodedCiphertext);
plaintextBody = new String(transportDetails.getStrippedPaddingMessageBody(paddedPlaintext)); plaintextBody = new String(transportDetails.getStrippedPaddingMessageBody(paddedPlaintext));

View File

@ -22,14 +22,14 @@ import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor; import android.content.SharedPreferences.Editor;
import android.util.Log; import android.util.Log;
import org.whispersystems.textsecure.crypto.IdentityKey; import org.whispersystems.libaxolotl.IdentityKey;
import org.whispersystems.textsecure.crypto.IdentityKeyPair; import org.whispersystems.libaxolotl.IdentityKeyPair;
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.textsecure.crypto.MasterCipher; import org.whispersystems.textsecure.crypto.MasterCipher;
import org.whispersystems.textsecure.crypto.MasterSecret; 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 org.whispersystems.textsecure.util.Base64;
import java.io.IOException; import java.io.IOException;

View File

@ -27,10 +27,10 @@ import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.sms.MessageSender; import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.sms.OutgoingKeyExchangeMessage; import org.thoughtcrime.securesms.sms.OutgoingKeyExchangeMessage;
import org.thoughtcrime.securesms.util.Dialogs; 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.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.RecipientDevice;
import org.whispersystems.textsecure.storage.SessionRecordV2; import org.whispersystems.textsecure.storage.SessionRecordV2;

View File

@ -21,10 +21,8 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import org.thoughtcrime.securesms.crypto.protocol.KeyExchangeMessage; 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.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.crypto.MasterSecret;
import org.whispersystems.textsecure.storage.RecipientDevice; import org.whispersystems.textsecure.storage.RecipientDevice;

View File

@ -12,16 +12,16 @@ import org.thoughtcrime.securesms.service.PreKeyService;
import org.thoughtcrime.securesms.sms.MessageSender; import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.sms.OutgoingKeyExchangeMessage; import org.thoughtcrime.securesms.sms.OutgoingKeyExchangeMessage;
import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.textsecure.crypto.IdentityKey; import org.whispersystems.libaxolotl.IdentityKey;
import org.whispersystems.textsecure.crypto.IdentityKeyPair; import org.whispersystems.libaxolotl.IdentityKeyPair;
import org.whispersystems.textsecure.crypto.InvalidKeyException; import org.whispersystems.libaxolotl.InvalidKeyException;
import org.whispersystems.textsecure.crypto.InvalidMessageException; 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.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.push.PreKeyEntity;
import org.whispersystems.textsecure.storage.InvalidKeyIdException; import org.whispersystems.textsecure.storage.InvalidKeyIdException;
import org.whispersystems.textsecure.storage.PreKeyRecord; import org.whispersystems.textsecure.storage.PreKeyRecord;

View File

@ -21,13 +21,13 @@ import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.util.Log; 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.MasterCipher;
import org.whispersystems.textsecure.crypto.MasterSecret; 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.Base64;
import org.whispersystems.textsecure.util.Util; import org.whispersystems.textsecure.util.Util;
@ -129,8 +129,8 @@ public class MasterSecretUtil {
byte[] djbPublicBytes = retrieve(context, ASYMMETRIC_LOCAL_PUBLIC_DJB); byte[] djbPublicBytes = retrieve(context, ASYMMETRIC_LOCAL_PUBLIC_DJB);
byte[] djbPrivateBytes = retrieve(context, ASYMMETRIC_LOCAL_PRIVATE_DJB); byte[] djbPrivateBytes = retrieve(context, ASYMMETRIC_LOCAL_PRIVATE_DJB);
ECPublicKey djbPublicKey = null; ECPublicKey djbPublicKey = null;
ECPrivateKey djbPrivateKey = null; ECPrivateKey djbPrivateKey = null;
if (djbPublicBytes != null) { if (djbPublicBytes != null) {
djbPublicKey = Curve.decodePoint(djbPublicBytes, 0); djbPublicKey = Curve.decodePoint(djbPublicBytes, 0);

View File

@ -17,12 +17,12 @@
*/ */
package org.thoughtcrime.securesms.crypto.protocol; 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 class KeyExchangeMessage {
public abstract IdentityKey getIdentityKey(); public abstract IdentityKey getIdentityKey();

View File

@ -3,15 +3,15 @@ package org.thoughtcrime.securesms.crypto.protocol;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.InvalidProtocolBufferException;
import org.whispersystems.textsecure.crypto.IdentityKey; import org.whispersystems.libaxolotl.IdentityKey;
import org.whispersystems.textsecure.crypto.InvalidKeyException; import org.whispersystems.libaxolotl.InvalidKeyException;
import org.whispersystems.textsecure.crypto.InvalidMessageException; import org.whispersystems.libaxolotl.InvalidMessageException;
import org.whispersystems.textsecure.crypto.InvalidVersionException; import org.whispersystems.libaxolotl.InvalidVersionException;
import org.whispersystems.textsecure.crypto.LegacyMessageException; import org.whispersystems.libaxolotl.LegacyMessageException;
import org.whispersystems.textsecure.crypto.ecc.Curve; import org.whispersystems.libaxolotl.ecc.Curve;
import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; import org.whispersystems.libaxolotl.ecc.ECPublicKey;
import org.whispersystems.textsecure.crypto.protocol.CiphertextMessage; import org.whispersystems.libaxolotl.protocol.CiphertextMessage;
import org.whispersystems.textsecure.crypto.protocol.WhisperProtos; import org.whispersystems.libaxolotl.protocol.WhisperProtos;
import org.whispersystems.textsecure.util.Base64; import org.whispersystems.textsecure.util.Base64;
import org.whispersystems.textsecure.util.Conversions; import org.whispersystems.textsecure.util.Conversions;
import org.whispersystems.textsecure.util.Util; import org.whispersystems.textsecure.util.Util;

View File

@ -28,11 +28,11 @@ import org.thoughtcrime.securesms.DatabaseUpgradeActivity;
import org.thoughtcrime.securesms.crypto.DecryptingPartInputStream; import org.thoughtcrime.securesms.crypto.DecryptingPartInputStream;
import org.thoughtcrime.securesms.crypto.DecryptingQueue; import org.thoughtcrime.securesms.crypto.DecryptingQueue;
import org.thoughtcrime.securesms.crypto.MasterSecretUtil; import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
import org.whispersystems.textsecure.crypto.IdentityKey; import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.whispersystems.textsecure.crypto.InvalidMessageException; import org.whispersystems.libaxolotl.IdentityKey;
import org.whispersystems.libaxolotl.InvalidMessageException;
import org.whispersystems.textsecure.crypto.MasterCipher; import org.whispersystems.textsecure.crypto.MasterCipher;
import org.whispersystems.textsecure.crypto.MasterSecret; import org.whispersystems.textsecure.crypto.MasterSecret;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.whispersystems.textsecure.storage.Session; import org.whispersystems.textsecure.storage.Session;
import org.whispersystems.textsecure.util.Base64; import org.whispersystems.textsecure.util.Base64;
import org.whispersystems.textsecure.util.Util; import org.whispersystems.textsecure.util.Util;

View File

@ -7,7 +7,7 @@ import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log; import android.util.Log;
import org.whispersystems.textsecure.crypto.InvalidMessageException; import org.whispersystems.libaxolotl.InvalidMessageException;
import org.whispersystems.textsecure.crypto.MasterCipher; import org.whispersystems.textsecure.crypto.MasterCipher;
import java.util.LinkedList; import java.util.LinkedList;

View File

@ -28,7 +28,7 @@ import org.thoughtcrime.securesms.database.model.DisplayRecord;
import org.thoughtcrime.securesms.sms.IncomingTextMessage; import org.thoughtcrime.securesms.sms.IncomingTextMessage;
import org.thoughtcrime.securesms.sms.OutgoingTextMessage; import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
import org.thoughtcrime.securesms.util.LRUCache; 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.MasterCipher;
import org.whispersystems.textsecure.crypto.MasterSecret; import org.whispersystems.textsecure.crypto.MasterSecret;

Some files were not shown because too many files have changed in this diff Show More