mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-21 15:05:19 +00:00
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.
This commit is contained in:
parent
fe3d91c40c
commit
d902c12941
@ -101,6 +101,12 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
tasks.whenTaskAdded { task ->
|
||||
if (task.name.equals("lint")) {
|
||||
task.enabled = false
|
||||
}
|
||||
}
|
||||
|
||||
def Properties props = new Properties()
|
||||
def propFile = new File('signing.properties')
|
||||
|
||||
|
2
libaxolotl/.gitignore
vendored
Normal file
2
libaxolotl/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/build
|
||||
/obj
|
34
libaxolotl/build.gradle
Normal file
34
libaxolotl/build.gradle
Normal 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
|
||||
}
|
||||
}
|
@ -21,7 +21,7 @@
|
||||
#include <jni.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)
|
||||
{
|
||||
uint8_t* privateKey = (uint8_t*)(*env)->GetByteArrayElements(env, random, 0);
|
||||
@ -40,7 +40,7 @@ JNIEXPORT jbyteArray JNICALL Java_org_whispersystems_textsecure_crypto_ecc_Curve
|
||||
return random;
|
||||
}
|
||||
|
||||
JNIEXPORT jbyteArray JNICALL Java_org_whispersystems_textsecure_crypto_ecc_Curve25519_generatePublicKey
|
||||
JNIEXPORT jbyteArray JNICALL Java_org_whispersystems_libaxolotl_ecc_Curve25519_generatePublicKey
|
||||
(JNIEnv *env, jclass clazz, jbyteArray privateKey)
|
||||
{
|
||||
static const uint8_t basepoint[32] = {9};
|
||||
@ -57,7 +57,7 @@ JNIEXPORT jbyteArray JNICALL Java_org_whispersystems_textsecure_crypto_ecc_Curve
|
||||
return publicKey;
|
||||
}
|
||||
|
||||
JNIEXPORT jbyteArray JNICALL Java_org_whispersystems_textsecure_crypto_ecc_Curve25519_calculateAgreement
|
||||
JNIEXPORT jbyteArray JNICALL Java_org_whispersystems_libaxolotl_ecc_Curve25519_calculateAgreement
|
||||
(JNIEnv *env, jclass clazz, jbyteArray privateKey, jbyteArray publicKey)
|
||||
{
|
||||
jbyteArray sharedKey = (*env)->NewByteArray(env, 32);
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
3
libaxolotl/protobuf/Makefile
Normal file
3
libaxolotl/protobuf/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
|
||||
all:
|
||||
protoc --java_out=../src/main/java/ WhisperTextProtocol.proto
|
@ -1,6 +1,6 @@
|
||||
package textsecure;
|
||||
|
||||
option java_package = "org.whispersystems.textsecure.crypto.protocol";
|
||||
option java_package = "org.whispersystems.libaxolotl.protocol";
|
||||
option java_outer_classname = "WhisperProtos";
|
||||
|
||||
message WhisperMessage {
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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));
|
||||
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
7
libaxolotl/src/main/AndroidManifest.xml
Normal file
7
libaxolotl/src/main/AndroidManifest.xml
Normal 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>
|
@ -1,4 +1,4 @@
|
||||
package org.whispersystems.textsecure.crypto;
|
||||
package org.whispersystems.libaxolotl;
|
||||
|
||||
public class DuplicateMessageException extends Exception {
|
||||
public DuplicateMessageException(String s) {
|
@ -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();
|
||||
}
|
||||
}
|
@ -14,9 +14,9 @@
|
||||
* 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;
|
||||
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.
|
@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (C) 2011 Whisper Systems
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -14,27 +14,21 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.crypto;
|
||||
package org.whispersystems.libaxolotl;
|
||||
|
||||
public class InvalidKeyException extends Exception {
|
||||
|
||||
public InvalidKeyException() {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
public InvalidKeyException() {}
|
||||
|
||||
public InvalidKeyException(String detailMessage) {
|
||||
super(detailMessage);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public InvalidKeyException(Throwable throwable) {
|
||||
super(throwable);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public InvalidKeyException(String detailMessage, Throwable throwable) {
|
||||
super(detailMessage, throwable);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (C) 2011 Whisper Systems
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -14,27 +14,15 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.crypto;
|
||||
package org.whispersystems.libaxolotl;
|
||||
|
||||
public class InvalidMacException extends Exception {
|
||||
|
||||
public InvalidMacException() {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public InvalidMacException(String detailMessage) {
|
||||
super(detailMessage);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public InvalidMacException(Throwable throwable) {
|
||||
super(throwable);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public InvalidMacException(String detailMessage, Throwable throwable) {
|
||||
super(detailMessage, throwable);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (C) 2011 Whisper Systems
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -14,27 +14,27 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.crypto;
|
||||
package org.whispersystems.libaxolotl;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class InvalidMessageException extends Exception {
|
||||
|
||||
public InvalidMessageException() {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
public InvalidMessageException() {}
|
||||
|
||||
public InvalidMessageException(String detailMessage) {
|
||||
super(detailMessage);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public InvalidMessageException(Throwable throwable) {
|
||||
super(throwable);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public InvalidMessageException(String detailMessage, Throwable throwable) {
|
||||
super(detailMessage, throwable);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public InvalidMessageException(String detailMessage, List<Exception> exceptions) {
|
||||
super(detailMessage, exceptions.get(0));
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Copyright (C) 2011 Whisper Systems
|
||||
*
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
@ -10,12 +10,14 @@
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.crypto;
|
||||
package org.whispersystems.libaxolotl;
|
||||
|
||||
public interface SerializableKey {
|
||||
public byte[] serialize();
|
||||
public class InvalidVersionException extends Exception {
|
||||
public InvalidVersionException(String detailMessage) {
|
||||
super(detailMessage);
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package org.whispersystems.textsecure.crypto;
|
||||
package org.whispersystems.libaxolotl;
|
||||
|
||||
public class LegacyMessageException extends Exception {
|
||||
public LegacyMessageException(String s) {
|
@ -14,29 +14,23 @@
|
||||
* 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;
|
||||
package org.whispersystems.libaxolotl;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import org.whispersystems.textsecure.crypto.ecc.Curve;
|
||||
import org.whispersystems.textsecure.crypto.ecc.ECKeyPair;
|
||||
import org.whispersystems.textsecure.crypto.ecc.ECPublicKey;
|
||||
import org.whispersystems.textsecure.crypto.protocol.CiphertextMessage;
|
||||
import org.whispersystems.textsecure.crypto.protocol.PreKeyWhisperMessage;
|
||||
import org.whispersystems.textsecure.crypto.protocol.WhisperMessage;
|
||||
import org.whispersystems.textsecure.crypto.ratchet.ChainKey;
|
||||
import org.whispersystems.textsecure.crypto.ratchet.MessageKeys;
|
||||
import org.whispersystems.textsecure.crypto.ratchet.RootKey;
|
||||
import org.whispersystems.textsecure.storage.RecipientDevice;
|
||||
import org.whispersystems.textsecure.storage.SessionRecordV2;
|
||||
import org.whispersystems.textsecure.storage.SessionState;
|
||||
import org.whispersystems.textsecure.util.Conversions;
|
||||
import org.whispersystems.libaxolotl.ecc.Curve;
|
||||
import org.whispersystems.libaxolotl.ecc.ECKeyPair;
|
||||
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
|
||||
import org.whispersystems.libaxolotl.protocol.CiphertextMessage;
|
||||
import org.whispersystems.libaxolotl.protocol.PreKeyWhisperMessage;
|
||||
import org.whispersystems.libaxolotl.protocol.WhisperMessage;
|
||||
import org.whispersystems.libaxolotl.ratchet.ChainKey;
|
||||
import org.whispersystems.libaxolotl.ratchet.MessageKeys;
|
||||
import org.whispersystems.libaxolotl.ratchet.RootKey;
|
||||
import org.whispersystems.libaxolotl.util.ByteUtil;
|
||||
import org.whispersystems.libaxolotl.util.Pair;
|
||||
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
@ -50,36 +44,19 @@ public class SessionCipher {
|
||||
|
||||
private static final Object SESSION_LOCK = new Object();
|
||||
|
||||
private final Context context;
|
||||
private final MasterSecret masterSecret;
|
||||
private final RecipientDevice recipient;
|
||||
private final SessionStore sessionStore;
|
||||
|
||||
public static SessionCipher createFor(Context context,
|
||||
MasterSecret masterSecret,
|
||||
RecipientDevice recipient)
|
||||
{
|
||||
if (SessionRecordV2.hasSession(context, masterSecret, recipient)) {
|
||||
return new SessionCipher(context, masterSecret, recipient);
|
||||
} else {
|
||||
throw new AssertionError("Attempt to initialize cipher for non-existing session.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private SessionCipher(Context context, MasterSecret masterSecret, RecipientDevice recipient) {
|
||||
this.recipient = recipient;
|
||||
this.masterSecret = masterSecret;
|
||||
this.context = context;
|
||||
public SessionCipher(SessionStore sessionStore) {
|
||||
this.sessionStore = sessionStore;
|
||||
}
|
||||
|
||||
public CiphertextMessage encrypt(byte[] paddedMessage) {
|
||||
synchronized (SESSION_LOCK) {
|
||||
SessionRecordV2 sessionRecord = getSessionRecord();
|
||||
SessionState sessionState = sessionRecord.getSessionState();
|
||||
ChainKey chainKey = sessionState.getSenderChainKey();
|
||||
MessageKeys messageKeys = chainKey.getMessageKeys();
|
||||
ECPublicKey senderEphemeral = sessionState.getSenderEphemeral();
|
||||
int previousCounter = sessionState.getPreviousCounter();
|
||||
SessionState sessionState = sessionStore.getSessionState();
|
||||
ChainKey chainKey = sessionState.getSenderChainKey();
|
||||
MessageKeys messageKeys = chainKey.getMessageKeys();
|
||||
ECPublicKey senderEphemeral = sessionState.getSenderEphemeral();
|
||||
int previousCounter = sessionState.getPreviousCounter();
|
||||
|
||||
byte[] ciphertextBody = getCiphertext(messageKeys, paddedMessage);
|
||||
CiphertextMessage ciphertextMessage = new WhisperMessage(messageKeys.getMacKey(),
|
||||
@ -90,15 +67,14 @@ public class SessionCipher {
|
||||
Pair<Integer, ECPublicKey> pendingPreKey = sessionState.getPendingPreKey();
|
||||
int localRegistrationId = sessionState.getLocalRegistrationId();
|
||||
|
||||
ciphertextMessage = new PreKeyWhisperMessage(localRegistrationId, pendingPreKey.first,
|
||||
pendingPreKey.second,
|
||||
ciphertextMessage = new PreKeyWhisperMessage(localRegistrationId, pendingPreKey.first(),
|
||||
pendingPreKey.second(),
|
||||
sessionState.getLocalIdentityKey(),
|
||||
(WhisperMessage) ciphertextMessage);
|
||||
}
|
||||
|
||||
sessionState.setSenderChainKey(chainKey.getNextChainKey());
|
||||
sessionRecord.save();
|
||||
|
||||
sessionStore.save();
|
||||
return ciphertextMessage;
|
||||
}
|
||||
}
|
||||
@ -107,32 +83,31 @@ public class SessionCipher {
|
||||
throws InvalidMessageException, DuplicateMessageException, LegacyMessageException
|
||||
{
|
||||
synchronized (SESSION_LOCK) {
|
||||
SessionRecordV2 sessionRecord = getSessionRecord();
|
||||
SessionState sessionState = sessionRecord.getSessionState();
|
||||
List<SessionState> previousStates = sessionRecord.getPreviousSessions();
|
||||
SessionState sessionState = sessionStore.getSessionState();
|
||||
List<SessionState> previousStates = sessionStore.getPreviousSessionStates();
|
||||
List<Exception> exceptions = new LinkedList<Exception>();
|
||||
|
||||
try {
|
||||
byte[] plaintext = decrypt(sessionState, decodedMessage);
|
||||
sessionRecord.save();
|
||||
sessionStore.save();
|
||||
|
||||
return plaintext;
|
||||
} catch (InvalidMessageException e) {
|
||||
Log.w("SessionCipherV2", e);
|
||||
exceptions.add(e);
|
||||
}
|
||||
|
||||
for (SessionState previousState : previousStates) {
|
||||
try {
|
||||
Log.w("SessionCipherV2", "Attempting decrypt on previous state...");
|
||||
byte[] plaintext = decrypt(previousState, decodedMessage);
|
||||
sessionRecord.save();
|
||||
sessionStore.save();
|
||||
|
||||
return plaintext;
|
||||
} catch (InvalidMessageException e) {
|
||||
Log.w("SessionCipherV2", e);
|
||||
exceptions.add(e);
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidMessageException("No valid sessions.");
|
||||
throw new InvalidMessageException("No valid sessions.", exceptions);
|
||||
}
|
||||
}
|
||||
|
||||
@ -162,8 +137,7 @@ public class SessionCipher {
|
||||
|
||||
public int getRemoteRegistrationId() {
|
||||
synchronized (SESSION_LOCK) {
|
||||
SessionRecordV2 sessionRecord = getSessionRecord();
|
||||
return sessionRecord.getSessionState().getRemoteRegistrationId();
|
||||
return sessionStore.getSessionState().getRemoteRegistrationId();
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,18 +148,18 @@ public class SessionCipher {
|
||||
if (sessionState.hasReceiverChain(theirEphemeral)) {
|
||||
return sessionState.getReceiverChainKey(theirEphemeral);
|
||||
} else {
|
||||
RootKey rootKey = sessionState.getRootKey();
|
||||
ECKeyPair ourEphemeral = sessionState.getSenderEphemeralPair();
|
||||
RootKey rootKey = sessionState.getRootKey();
|
||||
ECKeyPair ourEphemeral = sessionState.getSenderEphemeralPair();
|
||||
Pair<RootKey, ChainKey> receiverChain = rootKey.createChain(theirEphemeral, ourEphemeral);
|
||||
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.addReceiverChain(theirEphemeral, receiverChain.second);
|
||||
sessionState.setRootKey(senderChain.first());
|
||||
sessionState.addReceiverChain(theirEphemeral, receiverChain.second());
|
||||
sessionState.setPreviousCounter(sessionState.getSenderChainKey().getIndex()-1);
|
||||
sessionState.setSenderChain(ourNewEphemeral, senderChain.second);
|
||||
sessionState.setSenderChain(ourNewEphemeral, senderChain.second());
|
||||
|
||||
return receiverChain.second;
|
||||
return receiverChain.second();
|
||||
}
|
||||
} catch (InvalidKeyException e) {
|
||||
throw new InvalidMessageException(e);
|
||||
@ -252,7 +226,7 @@ public class SessionCipher {
|
||||
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
|
||||
|
||||
byte[] ivBytes = new byte[16];
|
||||
Conversions.intToByteArray(ivBytes, 0, counter);
|
||||
ByteUtil.intToByteArray(ivBytes, 0, counter);
|
||||
|
||||
IvParameterSpec iv = new IvParameterSpec(ivBytes);
|
||||
cipher.init(mode, key, iv);
|
||||
@ -268,8 +242,4 @@ public class SessionCipher {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private SessionRecordV2 getSessionRecord() {
|
||||
return new SessionRecordV2(context, masterSecret, recipient);
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
@ -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();
|
||||
|
||||
|
||||
}
|
@ -14,10 +14,9 @@
|
||||
* 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.ecc;
|
||||
package org.whispersystems.libaxolotl.ecc;
|
||||
|
||||
import org.whispersystems.textsecure.crypto.InvalidKeyException;
|
||||
import org.whispersystems.textsecure.crypto.protocol.CiphertextMessage;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
|
||||
public class Curve {
|
||||
|
@ -14,9 +14,9 @@
|
||||
* 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.ecc;
|
||||
package org.whispersystems.libaxolotl.ecc;
|
||||
|
||||
import org.whispersystems.textsecure.crypto.InvalidKeyException;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
@ -15,7 +15,7 @@
|
||||
* 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 {
|
||||
|
@ -15,9 +15,9 @@
|
||||
* 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.util.Arrays;
|
||||
@ -33,7 +33,7 @@ public class DjbECPublicKey implements ECPublicKey {
|
||||
@Override
|
||||
public byte[] serialize() {
|
||||
byte[] type = {Curve.DJB_TYPE};
|
||||
return Util.combine(type, publicKey);
|
||||
return ByteUtil.combine(type, publicKey);
|
||||
}
|
||||
|
||||
@Override
|
@ -15,7 +15,7 @@
|
||||
* 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 {
|
||||
|
@ -15,7 +15,7 @@
|
||||
* 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 byte[] serialize();
|
@ -15,7 +15,7 @@
|
||||
* 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> {
|
||||
|
@ -15,7 +15,7 @@
|
||||
* 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;
|
||||
|
@ -15,13 +15,11 @@
|
||||
* 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.math.BigInteger;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.List;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
@ -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();
|
||||
|
||||
}
|
@ -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.InvalidProtocolBufferException;
|
||||
|
||||
import org.whispersystems.textsecure.crypto.IdentityKey;
|
||||
import org.whispersystems.textsecure.crypto.InvalidKeyException;
|
||||
import org.whispersystems.textsecure.crypto.InvalidMessageException;
|
||||
import org.whispersystems.textsecure.crypto.InvalidVersionException;
|
||||
import org.whispersystems.textsecure.crypto.LegacyMessageException;
|
||||
import org.whispersystems.textsecure.crypto.ecc.Curve;
|
||||
import org.whispersystems.textsecure.crypto.ecc.ECPublicKey;
|
||||
import org.whispersystems.textsecure.util.Conversions;
|
||||
import org.whispersystems.textsecure.util.Util;
|
||||
import org.whispersystems.libaxolotl.IdentityKey;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
import org.whispersystems.libaxolotl.InvalidMessageException;
|
||||
import org.whispersystems.libaxolotl.InvalidVersionException;
|
||||
import org.whispersystems.libaxolotl.LegacyMessageException;
|
||||
import org.whispersystems.libaxolotl.ecc.Curve;
|
||||
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
|
||||
import org.whispersystems.libaxolotl.util.ByteUtil;
|
||||
|
||||
|
||||
public class PreKeyWhisperMessage implements CiphertextMessage {
|
||||
|
||||
@ -27,7 +43,7 @@ public class PreKeyWhisperMessage implements CiphertextMessage {
|
||||
throws InvalidMessageException, InvalidVersionException
|
||||
{
|
||||
try {
|
||||
this.version = Conversions.highBitsToInt(serialized[0]);
|
||||
this.version = ByteUtil.highBitsToInt(serialized[0]);
|
||||
|
||||
if (this.version > CiphertextMessage.CURRENT_VERSION) {
|
||||
throw new InvalidVersionException("Unknown version: " + this.version);
|
||||
@ -70,7 +86,7 @@ public class PreKeyWhisperMessage implements CiphertextMessage {
|
||||
this.identityKey = identityKey;
|
||||
this.message = message;
|
||||
|
||||
byte[] versionBytes = {Conversions.intsToByteHighAndLow(CURRENT_VERSION, this.version)};
|
||||
byte[] versionBytes = {ByteUtil.intsToByteHighAndLow(CURRENT_VERSION, this.version)};
|
||||
byte[] messageBytes = WhisperProtos.PreKeyWhisperMessage.newBuilder()
|
||||
.setPreKeyId(preKeyId)
|
||||
.setBaseKey(ByteString.copyFrom(baseKey.serialize()))
|
||||
@ -79,7 +95,7 @@ public class PreKeyWhisperMessage implements CiphertextMessage {
|
||||
.setRegistrationId(registrationId)
|
||||
.build().toByteArray();
|
||||
|
||||
this.serialized = Util.combine(versionBytes, messageBytes);
|
||||
this.serialized = ByteUtil.combine(versionBytes, messageBytes);
|
||||
}
|
||||
|
||||
public IdentityKey getIdentityKey() {
|
@ -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.InvalidProtocolBufferException;
|
||||
|
||||
import org.whispersystems.textsecure.crypto.InvalidKeyException;
|
||||
import org.whispersystems.textsecure.crypto.InvalidMessageException;
|
||||
import org.whispersystems.textsecure.crypto.LegacyMessageException;
|
||||
import org.whispersystems.textsecure.crypto.ecc.Curve;
|
||||
import org.whispersystems.textsecure.crypto.ecc.ECPublicKey;
|
||||
import org.whispersystems.textsecure.util.Conversions;
|
||||
import org.whispersystems.textsecure.util.Util;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
import org.whispersystems.libaxolotl.InvalidMessageException;
|
||||
import org.whispersystems.libaxolotl.LegacyMessageException;
|
||||
import org.whispersystems.libaxolotl.ecc.Curve;
|
||||
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
|
||||
import org.whispersystems.libaxolotl.util.ByteUtil;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
@ -30,17 +45,17 @@ public class WhisperMessage implements CiphertextMessage {
|
||||
|
||||
public WhisperMessage(byte[] serialized) throws InvalidMessageException, LegacyMessageException {
|
||||
try {
|
||||
byte[][] messageParts = Util.split(serialized, 1, serialized.length - 1 - MAC_LENGTH, MAC_LENGTH);
|
||||
byte[][] messageParts = ByteUtil.split(serialized, 1, serialized.length - 1 - MAC_LENGTH, MAC_LENGTH);
|
||||
byte version = messageParts[0][0];
|
||||
byte[] message = messageParts[1];
|
||||
byte[] mac = messageParts[2];
|
||||
|
||||
if (Conversions.highBitsToInt(version) <= CiphertextMessage.UNSUPPORTED_VERSION) {
|
||||
throw new LegacyMessageException("Legacy message: " + Conversions.highBitsToInt(version));
|
||||
if (ByteUtil.highBitsToInt(version) <= CiphertextMessage.UNSUPPORTED_VERSION) {
|
||||
throw new LegacyMessageException("Legacy message: " + ByteUtil.highBitsToInt(version));
|
||||
}
|
||||
|
||||
if (Conversions.highBitsToInt(version) != CURRENT_VERSION) {
|
||||
throw new InvalidMessageException("Unknown version: " + Conversions.highBitsToInt(version));
|
||||
if (ByteUtil.highBitsToInt(version) != CURRENT_VERSION) {
|
||||
throw new InvalidMessageException("Unknown version: " + ByteUtil.highBitsToInt(version));
|
||||
}
|
||||
|
||||
WhisperProtos.WhisperMessage whisperMessage = WhisperProtos.WhisperMessage.parseFrom(message);
|
||||
@ -69,16 +84,16 @@ public class WhisperMessage implements CiphertextMessage {
|
||||
public WhisperMessage(SecretKeySpec macKey, ECPublicKey senderEphemeral,
|
||||
int counter, int previousCounter, byte[] ciphertext)
|
||||
{
|
||||
byte[] version = {Conversions.intsToByteHighAndLow(CURRENT_VERSION, CURRENT_VERSION)};
|
||||
byte[] version = {ByteUtil.intsToByteHighAndLow(CURRENT_VERSION, CURRENT_VERSION)};
|
||||
byte[] message = WhisperProtos.WhisperMessage.newBuilder()
|
||||
.setEphemeralKey(ByteString.copyFrom(senderEphemeral.serialize()))
|
||||
.setCounter(counter)
|
||||
.setPreviousCounter(previousCounter)
|
||||
.setCiphertext(ByteString.copyFrom(ciphertext))
|
||||
.build().toByteArray();
|
||||
byte[] mac = getMac(macKey, Util.combine(version, message));
|
||||
byte[] mac = getMac(macKey, ByteUtil.combine(version, message));
|
||||
|
||||
this.serialized = Util.combine(version, message, mac);
|
||||
this.serialized = ByteUtil.combine(version, message, mac);
|
||||
this.senderEphemeral = senderEphemeral;
|
||||
this.counter = counter;
|
||||
this.previousCounter = previousCounter;
|
||||
@ -100,7 +115,7 @@ public class WhisperMessage implements CiphertextMessage {
|
||||
public void verifyMac(SecretKeySpec macKey)
|
||||
throws InvalidMessageException
|
||||
{
|
||||
byte[][] parts = Util.split(serialized, serialized.length - MAC_LENGTH, MAC_LENGTH);
|
||||
byte[][] parts = ByteUtil.split(serialized, serialized.length - MAC_LENGTH, MAC_LENGTH);
|
||||
byte[] ourMac = getMac(macKey, parts[0]);
|
||||
byte[] theirMac = parts[1];
|
||||
|
||||
@ -115,7 +130,7 @@ public class WhisperMessage implements CiphertextMessage {
|
||||
mac.init(macKey);
|
||||
|
||||
byte[] fullMac = mac.doFinal(serialized);
|
||||
return Util.trim(fullMac, MAC_LENGTH);
|
||||
return ByteUtil.trim(fullMac, MAC_LENGTH);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new AssertionError(e);
|
||||
} catch (java.security.InvalidKeyException e) {
|
||||
@ -135,7 +150,7 @@ public class WhisperMessage implements CiphertextMessage {
|
||||
|
||||
public static boolean isLegacy(byte[] message) {
|
||||
return message != null && message.length >= 1 &&
|
||||
Conversions.highBitsToInt(message[0]) <= CiphertextMessage.UNSUPPORTED_VERSION;
|
||||
ByteUtil.highBitsToInt(message[0]) <= CiphertextMessage.UNSUPPORTED_VERSION;
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
// Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
// source: WhisperTextProtocol.proto
|
||||
|
||||
package org.whispersystems.textsecure.crypto.protocol;
|
||||
package org.whispersystems.libaxolotl.protocol;
|
||||
|
||||
public final class WhisperProtos {
|
||||
private WhisperProtos() {}
|
||||
@ -47,12 +47,12 @@ public final class WhisperProtos {
|
||||
|
||||
public static final com.google.protobuf.Descriptors.Descriptor
|
||||
getDescriptor() {
|
||||
return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_WhisperMessage_descriptor;
|
||||
return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_WhisperMessage_descriptor;
|
||||
}
|
||||
|
||||
protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
|
||||
internalGetFieldAccessorTable() {
|
||||
return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_WhisperMessage_fieldAccessorTable;
|
||||
return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_WhisperMessage_fieldAccessorTable;
|
||||
}
|
||||
|
||||
private int bitField0_;
|
||||
@ -163,41 +163,41 @@ public final class WhisperProtos {
|
||||
return super.writeReplace();
|
||||
}
|
||||
|
||||
public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseFrom(
|
||||
public static org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage parseFrom(
|
||||
com.google.protobuf.ByteString data)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return newBuilder().mergeFrom(data).buildParsed();
|
||||
}
|
||||
public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseFrom(
|
||||
public static org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage parseFrom(
|
||||
com.google.protobuf.ByteString data,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return newBuilder().mergeFrom(data, extensionRegistry)
|
||||
.buildParsed();
|
||||
}
|
||||
public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseFrom(byte[] data)
|
||||
public static org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage parseFrom(byte[] data)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return newBuilder().mergeFrom(data).buildParsed();
|
||||
}
|
||||
public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseFrom(
|
||||
public static org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage parseFrom(
|
||||
byte[] data,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return newBuilder().mergeFrom(data, extensionRegistry)
|
||||
.buildParsed();
|
||||
}
|
||||
public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseFrom(java.io.InputStream input)
|
||||
public static org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage parseFrom(java.io.InputStream input)
|
||||
throws java.io.IOException {
|
||||
return newBuilder().mergeFrom(input).buildParsed();
|
||||
}
|
||||
public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseFrom(
|
||||
public static org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage parseFrom(
|
||||
java.io.InputStream input,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws java.io.IOException {
|
||||
return newBuilder().mergeFrom(input, extensionRegistry)
|
||||
.buildParsed();
|
||||
}
|
||||
public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseDelimitedFrom(java.io.InputStream input)
|
||||
public static org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage parseDelimitedFrom(java.io.InputStream input)
|
||||
throws java.io.IOException {
|
||||
Builder builder = newBuilder();
|
||||
if (builder.mergeDelimitedFrom(input)) {
|
||||
@ -206,7 +206,7 @@ public final class WhisperProtos {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseDelimitedFrom(
|
||||
public static org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage parseDelimitedFrom(
|
||||
java.io.InputStream input,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws java.io.IOException {
|
||||
@ -217,12 +217,12 @@ public final class WhisperProtos {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseFrom(
|
||||
public static org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage parseFrom(
|
||||
com.google.protobuf.CodedInputStream input)
|
||||
throws java.io.IOException {
|
||||
return newBuilder().mergeFrom(input).buildParsed();
|
||||
}
|
||||
public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseFrom(
|
||||
public static org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage parseFrom(
|
||||
com.google.protobuf.CodedInputStream input,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws java.io.IOException {
|
||||
@ -232,7 +232,7 @@ public final class WhisperProtos {
|
||||
|
||||
public static Builder newBuilder() { return Builder.create(); }
|
||||
public Builder newBuilderForType() { return newBuilder(); }
|
||||
public static Builder newBuilder(org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage prototype) {
|
||||
public static Builder newBuilder(org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage prototype) {
|
||||
return newBuilder().mergeFrom(prototype);
|
||||
}
|
||||
public Builder toBuilder() { return newBuilder(this); }
|
||||
@ -245,18 +245,18 @@ public final class WhisperProtos {
|
||||
}
|
||||
public static final class Builder extends
|
||||
com.google.protobuf.GeneratedMessage.Builder<Builder>
|
||||
implements org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessageOrBuilder {
|
||||
implements org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessageOrBuilder {
|
||||
public static final com.google.protobuf.Descriptors.Descriptor
|
||||
getDescriptor() {
|
||||
return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_WhisperMessage_descriptor;
|
||||
return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_WhisperMessage_descriptor;
|
||||
}
|
||||
|
||||
protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
|
||||
internalGetFieldAccessorTable() {
|
||||
return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_WhisperMessage_fieldAccessorTable;
|
||||
return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_WhisperMessage_fieldAccessorTable;
|
||||
}
|
||||
|
||||
// Construct using org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage.newBuilder()
|
||||
// Construct using org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage.newBuilder()
|
||||
private Builder() {
|
||||
maybeForceBuilderInitialization();
|
||||
}
|
||||
@ -292,24 +292,24 @@ public final class WhisperProtos {
|
||||
|
||||
public com.google.protobuf.Descriptors.Descriptor
|
||||
getDescriptorForType() {
|
||||
return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage.getDescriptor();
|
||||
return org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage.getDescriptor();
|
||||
}
|
||||
|
||||
public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage getDefaultInstanceForType() {
|
||||
return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage.getDefaultInstance();
|
||||
public org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage getDefaultInstanceForType() {
|
||||
return org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage.getDefaultInstance();
|
||||
}
|
||||
|
||||
public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage build() {
|
||||
org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage result = buildPartial();
|
||||
public org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage build() {
|
||||
org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage result = buildPartial();
|
||||
if (!result.isInitialized()) {
|
||||
throw newUninitializedMessageException(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage buildParsed()
|
||||
private org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage buildParsed()
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage result = buildPartial();
|
||||
org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage result = buildPartial();
|
||||
if (!result.isInitialized()) {
|
||||
throw newUninitializedMessageException(
|
||||
result).asInvalidProtocolBufferException();
|
||||
@ -317,8 +317,8 @@ public final class WhisperProtos {
|
||||
return result;
|
||||
}
|
||||
|
||||
public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage buildPartial() {
|
||||
org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage result = new org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage(this);
|
||||
public org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage buildPartial() {
|
||||
org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage result = new org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage(this);
|
||||
int from_bitField0_ = bitField0_;
|
||||
int to_bitField0_ = 0;
|
||||
if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
|
||||
@ -343,16 +343,16 @@ public final class WhisperProtos {
|
||||
}
|
||||
|
||||
public Builder mergeFrom(com.google.protobuf.Message other) {
|
||||
if (other instanceof org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage) {
|
||||
return mergeFrom((org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage)other);
|
||||
if (other instanceof org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage) {
|
||||
return mergeFrom((org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage)other);
|
||||
} else {
|
||||
super.mergeFrom(other);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public Builder mergeFrom(org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage other) {
|
||||
if (other == org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage.getDefaultInstance()) return this;
|
||||
public Builder mergeFrom(org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage other) {
|
||||
if (other == org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage.getDefaultInstance()) return this;
|
||||
if (other.hasEphemeralKey()) {
|
||||
setEphemeralKey(other.getEphemeralKey());
|
||||
}
|
||||
@ -566,12 +566,12 @@ public final class WhisperProtos {
|
||||
|
||||
public static final com.google.protobuf.Descriptors.Descriptor
|
||||
getDescriptor() {
|
||||
return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_PreKeyWhisperMessage_descriptor;
|
||||
return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_PreKeyWhisperMessage_descriptor;
|
||||
}
|
||||
|
||||
protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
|
||||
internalGetFieldAccessorTable() {
|
||||
return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_PreKeyWhisperMessage_fieldAccessorTable;
|
||||
return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_PreKeyWhisperMessage_fieldAccessorTable;
|
||||
}
|
||||
|
||||
private int bitField0_;
|
||||
@ -700,41 +700,41 @@ public final class WhisperProtos {
|
||||
return super.writeReplace();
|
||||
}
|
||||
|
||||
public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom(
|
||||
public static org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom(
|
||||
com.google.protobuf.ByteString data)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return newBuilder().mergeFrom(data).buildParsed();
|
||||
}
|
||||
public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom(
|
||||
public static org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom(
|
||||
com.google.protobuf.ByteString data,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return newBuilder().mergeFrom(data, extensionRegistry)
|
||||
.buildParsed();
|
||||
}
|
||||
public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom(byte[] data)
|
||||
public static org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom(byte[] data)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return newBuilder().mergeFrom(data).buildParsed();
|
||||
}
|
||||
public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom(
|
||||
public static org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom(
|
||||
byte[] data,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return newBuilder().mergeFrom(data, extensionRegistry)
|
||||
.buildParsed();
|
||||
}
|
||||
public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom(java.io.InputStream input)
|
||||
public static org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom(java.io.InputStream input)
|
||||
throws java.io.IOException {
|
||||
return newBuilder().mergeFrom(input).buildParsed();
|
||||
}
|
||||
public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom(
|
||||
public static org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom(
|
||||
java.io.InputStream input,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws java.io.IOException {
|
||||
return newBuilder().mergeFrom(input, extensionRegistry)
|
||||
.buildParsed();
|
||||
}
|
||||
public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseDelimitedFrom(java.io.InputStream input)
|
||||
public static org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage parseDelimitedFrom(java.io.InputStream input)
|
||||
throws java.io.IOException {
|
||||
Builder builder = newBuilder();
|
||||
if (builder.mergeDelimitedFrom(input)) {
|
||||
@ -743,7 +743,7 @@ public final class WhisperProtos {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseDelimitedFrom(
|
||||
public static org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage parseDelimitedFrom(
|
||||
java.io.InputStream input,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws java.io.IOException {
|
||||
@ -754,12 +754,12 @@ public final class WhisperProtos {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom(
|
||||
public static org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom(
|
||||
com.google.protobuf.CodedInputStream input)
|
||||
throws java.io.IOException {
|
||||
return newBuilder().mergeFrom(input).buildParsed();
|
||||
}
|
||||
public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom(
|
||||
public static org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom(
|
||||
com.google.protobuf.CodedInputStream input,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws java.io.IOException {
|
||||
@ -769,7 +769,7 @@ public final class WhisperProtos {
|
||||
|
||||
public static Builder newBuilder() { return Builder.create(); }
|
||||
public Builder newBuilderForType() { return newBuilder(); }
|
||||
public static Builder newBuilder(org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage prototype) {
|
||||
public static Builder newBuilder(org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage prototype) {
|
||||
return newBuilder().mergeFrom(prototype);
|
||||
}
|
||||
public Builder toBuilder() { return newBuilder(this); }
|
||||
@ -782,18 +782,18 @@ public final class WhisperProtos {
|
||||
}
|
||||
public static final class Builder extends
|
||||
com.google.protobuf.GeneratedMessage.Builder<Builder>
|
||||
implements org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessageOrBuilder {
|
||||
implements org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessageOrBuilder {
|
||||
public static final com.google.protobuf.Descriptors.Descriptor
|
||||
getDescriptor() {
|
||||
return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_PreKeyWhisperMessage_descriptor;
|
||||
return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_PreKeyWhisperMessage_descriptor;
|
||||
}
|
||||
|
||||
protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
|
||||
internalGetFieldAccessorTable() {
|
||||
return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_PreKeyWhisperMessage_fieldAccessorTable;
|
||||
return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_PreKeyWhisperMessage_fieldAccessorTable;
|
||||
}
|
||||
|
||||
// Construct using org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage.newBuilder()
|
||||
// Construct using org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage.newBuilder()
|
||||
private Builder() {
|
||||
maybeForceBuilderInitialization();
|
||||
}
|
||||
@ -831,24 +831,24 @@ public final class WhisperProtos {
|
||||
|
||||
public com.google.protobuf.Descriptors.Descriptor
|
||||
getDescriptorForType() {
|
||||
return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage.getDescriptor();
|
||||
return org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage.getDescriptor();
|
||||
}
|
||||
|
||||
public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage getDefaultInstanceForType() {
|
||||
return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage.getDefaultInstance();
|
||||
public org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage getDefaultInstanceForType() {
|
||||
return org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage.getDefaultInstance();
|
||||
}
|
||||
|
||||
public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage build() {
|
||||
org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage result = buildPartial();
|
||||
public org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage build() {
|
||||
org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage result = buildPartial();
|
||||
if (!result.isInitialized()) {
|
||||
throw newUninitializedMessageException(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage buildParsed()
|
||||
private org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage buildParsed()
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage result = buildPartial();
|
||||
org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage result = buildPartial();
|
||||
if (!result.isInitialized()) {
|
||||
throw newUninitializedMessageException(
|
||||
result).asInvalidProtocolBufferException();
|
||||
@ -856,8 +856,8 @@ public final class WhisperProtos {
|
||||
return result;
|
||||
}
|
||||
|
||||
public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage buildPartial() {
|
||||
org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage result = new org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage(this);
|
||||
public org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage buildPartial() {
|
||||
org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage result = new org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage(this);
|
||||
int from_bitField0_ = bitField0_;
|
||||
int to_bitField0_ = 0;
|
||||
if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
|
||||
@ -886,16 +886,16 @@ public final class WhisperProtos {
|
||||
}
|
||||
|
||||
public Builder mergeFrom(com.google.protobuf.Message other) {
|
||||
if (other instanceof org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage) {
|
||||
return mergeFrom((org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage)other);
|
||||
if (other instanceof org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage) {
|
||||
return mergeFrom((org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage)other);
|
||||
} else {
|
||||
super.mergeFrom(other);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public Builder mergeFrom(org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage other) {
|
||||
if (other == org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage.getDefaultInstance()) return this;
|
||||
public Builder mergeFrom(org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage other) {
|
||||
if (other == org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage.getDefaultInstance()) return this;
|
||||
if (other.hasRegistrationId()) {
|
||||
setRegistrationId(other.getRegistrationId());
|
||||
}
|
||||
@ -1137,12 +1137,12 @@ public final class WhisperProtos {
|
||||
|
||||
public static final com.google.protobuf.Descriptors.Descriptor
|
||||
getDescriptor() {
|
||||
return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_KeyExchangeMessage_descriptor;
|
||||
return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_KeyExchangeMessage_descriptor;
|
||||
}
|
||||
|
||||
protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
|
||||
internalGetFieldAccessorTable() {
|
||||
return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_KeyExchangeMessage_fieldAccessorTable;
|
||||
return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_KeyExchangeMessage_fieldAccessorTable;
|
||||
}
|
||||
|
||||
private int bitField0_;
|
||||
@ -1253,41 +1253,41 @@ public final class WhisperProtos {
|
||||
return super.writeReplace();
|
||||
}
|
||||
|
||||
public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseFrom(
|
||||
public static org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage parseFrom(
|
||||
com.google.protobuf.ByteString data)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return newBuilder().mergeFrom(data).buildParsed();
|
||||
}
|
||||
public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseFrom(
|
||||
public static org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage parseFrom(
|
||||
com.google.protobuf.ByteString data,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return newBuilder().mergeFrom(data, extensionRegistry)
|
||||
.buildParsed();
|
||||
}
|
||||
public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseFrom(byte[] data)
|
||||
public static org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage parseFrom(byte[] data)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return newBuilder().mergeFrom(data).buildParsed();
|
||||
}
|
||||
public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseFrom(
|
||||
public static org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage parseFrom(
|
||||
byte[] data,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return newBuilder().mergeFrom(data, extensionRegistry)
|
||||
.buildParsed();
|
||||
}
|
||||
public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseFrom(java.io.InputStream input)
|
||||
public static org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage parseFrom(java.io.InputStream input)
|
||||
throws java.io.IOException {
|
||||
return newBuilder().mergeFrom(input).buildParsed();
|
||||
}
|
||||
public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseFrom(
|
||||
public static org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage parseFrom(
|
||||
java.io.InputStream input,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws java.io.IOException {
|
||||
return newBuilder().mergeFrom(input, extensionRegistry)
|
||||
.buildParsed();
|
||||
}
|
||||
public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseDelimitedFrom(java.io.InputStream input)
|
||||
public static org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage parseDelimitedFrom(java.io.InputStream input)
|
||||
throws java.io.IOException {
|
||||
Builder builder = newBuilder();
|
||||
if (builder.mergeDelimitedFrom(input)) {
|
||||
@ -1296,7 +1296,7 @@ public final class WhisperProtos {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseDelimitedFrom(
|
||||
public static org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage parseDelimitedFrom(
|
||||
java.io.InputStream input,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws java.io.IOException {
|
||||
@ -1307,12 +1307,12 @@ public final class WhisperProtos {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseFrom(
|
||||
public static org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage parseFrom(
|
||||
com.google.protobuf.CodedInputStream input)
|
||||
throws java.io.IOException {
|
||||
return newBuilder().mergeFrom(input).buildParsed();
|
||||
}
|
||||
public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseFrom(
|
||||
public static org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage parseFrom(
|
||||
com.google.protobuf.CodedInputStream input,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws java.io.IOException {
|
||||
@ -1322,7 +1322,7 @@ public final class WhisperProtos {
|
||||
|
||||
public static Builder newBuilder() { return Builder.create(); }
|
||||
public Builder newBuilderForType() { return newBuilder(); }
|
||||
public static Builder newBuilder(org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage prototype) {
|
||||
public static Builder newBuilder(org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage prototype) {
|
||||
return newBuilder().mergeFrom(prototype);
|
||||
}
|
||||
public Builder toBuilder() { return newBuilder(this); }
|
||||
@ -1335,18 +1335,18 @@ public final class WhisperProtos {
|
||||
}
|
||||
public static final class Builder extends
|
||||
com.google.protobuf.GeneratedMessage.Builder<Builder>
|
||||
implements org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessageOrBuilder {
|
||||
implements org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessageOrBuilder {
|
||||
public static final com.google.protobuf.Descriptors.Descriptor
|
||||
getDescriptor() {
|
||||
return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_KeyExchangeMessage_descriptor;
|
||||
return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_KeyExchangeMessage_descriptor;
|
||||
}
|
||||
|
||||
protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
|
||||
internalGetFieldAccessorTable() {
|
||||
return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_KeyExchangeMessage_fieldAccessorTable;
|
||||
return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_KeyExchangeMessage_fieldAccessorTable;
|
||||
}
|
||||
|
||||
// Construct using org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage.newBuilder()
|
||||
// Construct using org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage.newBuilder()
|
||||
private Builder() {
|
||||
maybeForceBuilderInitialization();
|
||||
}
|
||||
@ -1382,24 +1382,24 @@ public final class WhisperProtos {
|
||||
|
||||
public com.google.protobuf.Descriptors.Descriptor
|
||||
getDescriptorForType() {
|
||||
return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage.getDescriptor();
|
||||
return org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage.getDescriptor();
|
||||
}
|
||||
|
||||
public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage getDefaultInstanceForType() {
|
||||
return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage.getDefaultInstance();
|
||||
public org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage getDefaultInstanceForType() {
|
||||
return org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage.getDefaultInstance();
|
||||
}
|
||||
|
||||
public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage build() {
|
||||
org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage result = buildPartial();
|
||||
public org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage build() {
|
||||
org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage result = buildPartial();
|
||||
if (!result.isInitialized()) {
|
||||
throw newUninitializedMessageException(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage buildParsed()
|
||||
private org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage buildParsed()
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage result = buildPartial();
|
||||
org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage result = buildPartial();
|
||||
if (!result.isInitialized()) {
|
||||
throw newUninitializedMessageException(
|
||||
result).asInvalidProtocolBufferException();
|
||||
@ -1407,8 +1407,8 @@ public final class WhisperProtos {
|
||||
return result;
|
||||
}
|
||||
|
||||
public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage buildPartial() {
|
||||
org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage result = new org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage(this);
|
||||
public org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage buildPartial() {
|
||||
org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage result = new org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage(this);
|
||||
int from_bitField0_ = bitField0_;
|
||||
int to_bitField0_ = 0;
|
||||
if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
|
||||
@ -1433,16 +1433,16 @@ public final class WhisperProtos {
|
||||
}
|
||||
|
||||
public Builder mergeFrom(com.google.protobuf.Message other) {
|
||||
if (other instanceof org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage) {
|
||||
return mergeFrom((org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage)other);
|
||||
if (other instanceof org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage) {
|
||||
return mergeFrom((org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage)other);
|
||||
} else {
|
||||
super.mergeFrom(other);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public Builder mergeFrom(org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage other) {
|
||||
if (other == org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage.getDefaultInstance()) return this;
|
||||
public Builder mergeFrom(org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage other) {
|
||||
if (other == org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage.getDefaultInstance()) return this;
|
||||
if (other.hasId()) {
|
||||
setId(other.getId());
|
||||
}
|
||||
@ -1648,9 +1648,9 @@ public final class WhisperProtos {
|
||||
"d\030\001 \001(\r\022\017\n\007baseKey\030\002 \001(\014\022\023\n\013identityKey\030" +
|
||||
"\003 \001(\014\022\017\n\007message\030\004 \001(\014\"\\\n\022KeyExchangeMes" +
|
||||
"sage\022\n\n\002id\030\001 \001(\r\022\017\n\007baseKey\030\002 \001(\014\022\024\n\014eph" +
|
||||
"emeralKey\030\003 \001(\014\022\023\n\013identityKey\030\004 \001(\014B>\n-" +
|
||||
"org.whispersystems.textsecure.crypto.pro",
|
||||
"tocolB\rWhisperProtos"
|
||||
"emeralKey\030\003 \001(\014\022\023\n\013identityKey\030\004 \001(\014B7\n&" +
|
||||
"org.whispersystems.libaxolotl.protocolB\r",
|
||||
"WhisperProtos"
|
||||
};
|
||||
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
|
||||
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
|
||||
@ -1663,24 +1663,24 @@ public final class WhisperProtos {
|
||||
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
|
||||
internal_static_textsecure_WhisperMessage_descriptor,
|
||||
new java.lang.String[] { "EphemeralKey", "Counter", "PreviousCounter", "Ciphertext", },
|
||||
org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage.class,
|
||||
org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage.Builder.class);
|
||||
org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage.class,
|
||||
org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage.Builder.class);
|
||||
internal_static_textsecure_PreKeyWhisperMessage_descriptor =
|
||||
getDescriptor().getMessageTypes().get(1);
|
||||
internal_static_textsecure_PreKeyWhisperMessage_fieldAccessorTable = new
|
||||
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
|
||||
internal_static_textsecure_PreKeyWhisperMessage_descriptor,
|
||||
new java.lang.String[] { "RegistrationId", "PreKeyId", "BaseKey", "IdentityKey", "Message", },
|
||||
org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage.class,
|
||||
org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage.Builder.class);
|
||||
org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage.class,
|
||||
org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage.Builder.class);
|
||||
internal_static_textsecure_KeyExchangeMessage_descriptor =
|
||||
getDescriptor().getMessageTypes().get(2);
|
||||
internal_static_textsecure_KeyExchangeMessage_fieldAccessorTable = new
|
||||
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
|
||||
internal_static_textsecure_KeyExchangeMessage_descriptor,
|
||||
new java.lang.String[] { "Id", "BaseKey", "EphemeralKey", "IdentityKey", },
|
||||
org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage.class,
|
||||
org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage.Builder.class);
|
||||
org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage.class,
|
||||
org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage.Builder.class);
|
||||
return null;
|
||||
}
|
||||
};
|
@ -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.NoSuchAlgorithmException;
|
||||
@ -49,9 +66,7 @@ public class ChainKey {
|
||||
mac.init(new SecretKeySpec(key, "HmacSHA256"));
|
||||
|
||||
return mac.doFinal(seed);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new AssertionError(e);
|
||||
} catch (InvalidKeyException e) {
|
||||
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Copyright (C) 2011 Whisper Systems
|
||||
*
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
@ -10,31 +10,35 @@
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.crypto;
|
||||
package org.whispersystems.libaxolotl.ratchet;
|
||||
|
||||
public class InvalidVersionException extends Exception {
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
public InvalidVersionException() {
|
||||
// TODO Auto-generated constructor stub
|
||||
public class MessageKeys {
|
||||
|
||||
private final SecretKeySpec cipherKey;
|
||||
private final SecretKeySpec macKey;
|
||||
private final int counter;
|
||||
|
||||
public MessageKeys(SecretKeySpec cipherKey, SecretKeySpec macKey, int counter) {
|
||||
this.cipherKey = cipherKey;
|
||||
this.macKey = macKey;
|
||||
this.counter = counter;
|
||||
}
|
||||
|
||||
public InvalidVersionException(String detailMessage) {
|
||||
super(detailMessage);
|
||||
// TODO Auto-generated constructor stub
|
||||
public SecretKeySpec getCipherKey() {
|
||||
return cipherKey;
|
||||
}
|
||||
|
||||
public InvalidVersionException(Throwable throwable) {
|
||||
super(throwable);
|
||||
// TODO Auto-generated constructor stub
|
||||
public SecretKeySpec getMacKey() {
|
||||
return macKey;
|
||||
}
|
||||
|
||||
public InvalidVersionException(String detailMessage, Throwable throwable) {
|
||||
super(detailMessage, throwable);
|
||||
// TODO Auto-generated constructor stub
|
||||
public int getCounter() {
|
||||
return counter;
|
||||
}
|
||||
|
||||
}
|
@ -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.textsecure.crypto.IdentityKeyPair;
|
||||
import org.whispersystems.textsecure.crypto.InvalidKeyException;
|
||||
import org.whispersystems.textsecure.crypto.ecc.Curve;
|
||||
import org.whispersystems.textsecure.crypto.ecc.ECKeyPair;
|
||||
import org.whispersystems.textsecure.crypto.ecc.ECPublicKey;
|
||||
import org.whispersystems.textsecure.crypto.kdf.DerivedSecrets;
|
||||
import org.whispersystems.textsecure.crypto.kdf.HKDF;
|
||||
import org.whispersystems.textsecure.storage.SessionState;
|
||||
import org.whispersystems.libaxolotl.IdentityKey;
|
||||
import org.whispersystems.libaxolotl.IdentityKeyPair;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
import org.whispersystems.libaxolotl.SessionState;
|
||||
import org.whispersystems.libaxolotl.ecc.Curve;
|
||||
import org.whispersystems.libaxolotl.ecc.ECKeyPair;
|
||||
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
|
||||
import org.whispersystems.libaxolotl.kdf.DerivedSecrets;
|
||||
import org.whispersystems.libaxolotl.kdf.HKDF;
|
||||
import org.whispersystems.libaxolotl.util.Hex;
|
||||
import org.whispersystems.libaxolotl.util.Pair;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
@ -47,11 +65,11 @@ public class RatchetingSession {
|
||||
|
||||
ECKeyPair sendingKey = Curve.generateKeyPair(true);
|
||||
Pair<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.setSenderChain(sendingKey, sendingChain.second);
|
||||
sessionState.setRootKey(sendingChain.first);
|
||||
sessionState.addReceiverChain(theirEphemeralKey, receivingChain.second());
|
||||
sessionState.setSenderChain(sendingKey, sendingChain.second());
|
||||
sessionState.setRootKey(sendingChain.first());
|
||||
}
|
||||
|
||||
private static void initializeSessionAsBob(SessionState sessionState,
|
||||
@ -67,8 +85,8 @@ public class RatchetingSession {
|
||||
Pair<RootKey, ChainKey> sendingChain = calculate3DHE(false, ourBaseKey, theirBaseKey,
|
||||
ourIdentityKey, theirIdentityKey);
|
||||
|
||||
sessionState.setSenderChain(ourEphemeralKey, sendingChain.second);
|
||||
sessionState.setRootKey(sendingChain.first);
|
||||
sessionState.setSenderChain(ourEphemeralKey, sendingChain.second());
|
||||
sessionState.setRootKey(sendingChain.first());
|
||||
}
|
||||
|
||||
private static Pair<RootKey, ChainKey> calculate3DHE(boolean isAlice,
|
@ -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);
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
@ -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]);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -23,6 +23,8 @@ dependencies {
|
||||
compile 'com.madgag:sc-light-jdk15on:1.47.0.2'
|
||||
compile 'com.googlecode.libphonenumber:libphonenumber:6.1'
|
||||
compile 'org.whispersystems:gson:2.2.4'
|
||||
|
||||
compile project(':libaxolotl')
|
||||
}
|
||||
|
||||
android {
|
||||
@ -45,6 +47,12 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
tasks.whenTaskAdded { task ->
|
||||
if (task.name.equals("lint")) {
|
||||
task.enabled = false
|
||||
}
|
||||
}
|
||||
|
||||
version '0.1'
|
||||
group 'org.whispersystems.textsecure'
|
||||
archivesBaseName = 'textsecure-library'
|
||||
|
@ -18,6 +18,8 @@ package org.whispersystems.textsecure.crypto;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.whispersystems.libaxolotl.InvalidMacException;
|
||||
import org.whispersystems.libaxolotl.InvalidMessageException;
|
||||
import org.whispersystems.textsecure.util.Hex;
|
||||
import org.whispersystems.textsecure.util.Util;
|
||||
|
||||
|
@ -18,6 +18,8 @@ package org.whispersystems.textsecure.crypto;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.whispersystems.libaxolotl.InvalidMacException;
|
||||
import org.whispersystems.libaxolotl.InvalidMessageException;
|
||||
import org.whispersystems.textsecure.util.Util;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
@ -19,8 +19,9 @@ package org.whispersystems.textsecure.crypto;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.whispersystems.textsecure.crypto.ecc.Curve;
|
||||
import org.whispersystems.textsecure.crypto.ecc.ECPrivateKey;
|
||||
import org.whispersystems.libaxolotl.InvalidMessageException;
|
||||
import org.whispersystems.libaxolotl.ecc.Curve;
|
||||
import org.whispersystems.libaxolotl.ecc.ECPrivateKey;
|
||||
import org.whispersystems.textsecure.util.Base64;
|
||||
import org.whispersystems.textsecure.util.Hex;
|
||||
|
||||
@ -84,12 +85,12 @@ public class MasterCipher {
|
||||
}
|
||||
|
||||
public ECPrivateKey decryptKey(byte[] key)
|
||||
throws org.whispersystems.textsecure.crypto.InvalidKeyException
|
||||
throws org.whispersystems.libaxolotl.InvalidKeyException
|
||||
{
|
||||
try {
|
||||
return Curve.decodePrivatePoint(decryptBytes(key));
|
||||
} catch (InvalidMessageException ime) {
|
||||
throw new org.whispersystems.textsecure.crypto.InvalidKeyException(ime);
|
||||
throw new org.whispersystems.libaxolotl.InvalidKeyException(ime);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,8 +22,8 @@ import android.util.Log;
|
||||
|
||||
import com.google.thoughtcrimegson.Gson;
|
||||
|
||||
import org.whispersystems.textsecure.crypto.ecc.Curve25519;
|
||||
import org.whispersystems.textsecure.crypto.ecc.ECKeyPair;
|
||||
import org.whispersystems.libaxolotl.ecc.Curve25519;
|
||||
import org.whispersystems.libaxolotl.ecc.ECKeyPair;
|
||||
import org.whispersystems.textsecure.storage.InvalidKeyIdException;
|
||||
import org.whispersystems.textsecure.storage.PreKeyRecord;
|
||||
import org.whispersystems.textsecure.util.Medium;
|
||||
|
@ -19,8 +19,9 @@ package org.whispersystems.textsecure.crypto;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.whispersystems.textsecure.crypto.ecc.Curve;
|
||||
import org.whispersystems.textsecure.crypto.ecc.ECPublicKey;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
import org.whispersystems.libaxolotl.ecc.Curve;
|
||||
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
|
||||
import org.whispersystems.textsecure.util.Conversions;
|
||||
import org.whispersystems.textsecure.util.Hex;
|
||||
import org.whispersystems.textsecure.util.Util;
|
||||
|
@ -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.");
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@ package org.whispersystems.textsecure.push;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.whispersystems.textsecure.crypto.InvalidVersionException;
|
||||
import org.whispersystems.libaxolotl.InvalidVersionException;
|
||||
import org.whispersystems.textsecure.util.Base64;
|
||||
import org.whispersystems.textsecure.push.PushMessageProtos.IncomingPushMessageSignal;
|
||||
import org.whispersystems.textsecure.util.Hex;
|
||||
|
@ -10,10 +10,10 @@ import com.google.thoughtcrimegson.JsonSerializationContext;
|
||||
import com.google.thoughtcrimegson.JsonSerializer;
|
||||
import com.google.thoughtcrimegson.annotations.Expose;
|
||||
|
||||
import org.whispersystems.textsecure.crypto.IdentityKey;
|
||||
import org.whispersystems.textsecure.crypto.InvalidKeyException;
|
||||
import org.whispersystems.textsecure.crypto.ecc.Curve;
|
||||
import org.whispersystems.textsecure.crypto.ecc.ECPublicKey;
|
||||
import org.whispersystems.libaxolotl.IdentityKey;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
import org.whispersystems.libaxolotl.ecc.Curve;
|
||||
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
|
||||
import org.whispersystems.textsecure.util.Base64;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -23,7 +23,7 @@ import com.google.thoughtcrimegson.Gson;
|
||||
import com.google.thoughtcrimegson.JsonParseException;
|
||||
|
||||
import org.apache.http.conn.ssl.StrictHostnameVerifier;
|
||||
import org.whispersystems.textsecure.crypto.IdentityKey;
|
||||
import org.whispersystems.libaxolotl.IdentityKey;
|
||||
import org.whispersystems.textsecure.storage.PreKeyRecord;
|
||||
import org.whispersystems.textsecure.util.Base64;
|
||||
import org.whispersystems.textsecure.util.BlacklistingTrustManager;
|
||||
|
@ -5,14 +5,14 @@ import android.util.Log;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
|
||||
import org.whispersystems.textsecure.crypto.InvalidKeyException;
|
||||
import org.whispersystems.textsecure.crypto.InvalidMessageException;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
import org.whispersystems.libaxolotl.InvalidMessageException;
|
||||
import org.whispersystems.libaxolotl.ecc.Curve;
|
||||
import org.whispersystems.libaxolotl.ecc.ECKeyPair;
|
||||
import org.whispersystems.libaxolotl.ecc.ECPrivateKey;
|
||||
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
|
||||
import org.whispersystems.textsecure.crypto.MasterCipher;
|
||||
import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||
import org.whispersystems.textsecure.crypto.ecc.Curve;
|
||||
import org.whispersystems.textsecure.crypto.ecc.ECKeyPair;
|
||||
import org.whispersystems.textsecure.crypto.ecc.ECPrivateKey;
|
||||
import org.whispersystems.textsecure.crypto.ecc.ECPublicKey;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
|
@ -30,7 +30,7 @@ import java.nio.channels.FileChannel;
|
||||
|
||||
public abstract class Record {
|
||||
|
||||
protected static final String SESSIONS_DIRECTORY = "sessions";
|
||||
public static final String SESSIONS_DIRECTORY = "sessions";
|
||||
protected static final String SESSIONS_DIRECTORY_V2 = "sessions-v2";
|
||||
public static final String PREKEY_DIRECTORY = "prekeys";
|
||||
|
||||
@ -48,7 +48,7 @@ public abstract class Record {
|
||||
delete(this.context, this.directory, this.address);
|
||||
}
|
||||
|
||||
protected static void delete(Context context, String directory, String address) {
|
||||
public static void delete(Context context, String directory, String address) {
|
||||
getAddressFile(context, directory, address).delete();
|
||||
}
|
||||
|
||||
|
@ -3,8 +3,11 @@ package org.whispersystems.textsecure.storage;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import org.whispersystems.textsecure.crypto.IdentityKey;
|
||||
import org.whispersystems.libaxolotl.IdentityKey;
|
||||
import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||
import org.whispersystems.textsecure.storage.legacy.LocalKeyRecord;
|
||||
import org.whispersystems.textsecure.storage.legacy.RemoteKeyRecord;
|
||||
import org.whispersystems.textsecure.storage.legacy.SessionRecordV1;
|
||||
|
||||
/**
|
||||
* Helper class for generating key pairs and calculating ECDH agreements.
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -19,7 +19,9 @@ package org.whispersystems.textsecure.storage;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import org.whispersystems.textsecure.crypto.InvalidMessageException;
|
||||
import org.whispersystems.libaxolotl.InvalidMessageException;
|
||||
import org.whispersystems.libaxolotl.SessionState;
|
||||
import org.whispersystems.libaxolotl.SessionStore;
|
||||
import org.whispersystems.textsecure.crypto.MasterCipher;
|
||||
import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||
|
||||
@ -41,7 +43,7 @@ import static org.whispersystems.textsecure.storage.StorageProtos.SessionStructu
|
||||
* @author Moxie Marlinspike
|
||||
*/
|
||||
|
||||
public class SessionRecordV2 extends Record {
|
||||
public class SessionRecordV2 extends Record implements SessionStore {
|
||||
|
||||
private static final Object FILE_LOCK = new Object();
|
||||
|
||||
@ -51,8 +53,8 @@ public class SessionRecordV2 extends Record {
|
||||
|
||||
private final MasterSecret masterSecret;
|
||||
|
||||
private SessionState sessionState = new SessionState(SessionStructure.newBuilder().build());
|
||||
private List<SessionState> previousStates = new LinkedList<SessionState>();
|
||||
private TextSecureSessionState sessionState = new TextSecureSessionState(SessionStructure.newBuilder().build());
|
||||
private List<SessionState> previousStates = new LinkedList<SessionState>();
|
||||
|
||||
public SessionRecordV2(Context context, MasterSecret masterSecret, RecipientDevice peer) {
|
||||
this(context, masterSecret, peer.getRecipientId(), peer.getDeviceId());
|
||||
@ -68,12 +70,12 @@ public class SessionRecordV2 extends Record {
|
||||
return recipientId + (deviceId == RecipientDevice.DEFAULT_DEVICE_ID ? "" : "." + deviceId);
|
||||
}
|
||||
|
||||
public SessionState getSessionState() {
|
||||
public TextSecureSessionState getSessionState() {
|
||||
return sessionState;
|
||||
}
|
||||
|
||||
|
||||
public List<SessionState> getPreviousSessions() {
|
||||
public List<SessionState> getPreviousSessionStates() {
|
||||
return previousStates;
|
||||
}
|
||||
|
||||
@ -139,13 +141,13 @@ public class SessionRecordV2 extends Record {
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
this.sessionState = new SessionState(SessionStructure.newBuilder().build());
|
||||
this.sessionState = new TextSecureSessionState(SessionStructure.newBuilder().build());
|
||||
this.previousStates = new LinkedList<SessionState>();
|
||||
}
|
||||
|
||||
public void archiveCurrentState() {
|
||||
this.previousStates.add(sessionState);
|
||||
this.sessionState = new SessionState(SessionStructure.newBuilder().build());
|
||||
this.sessionState = new TextSecureSessionState(SessionStructure.newBuilder().build());
|
||||
}
|
||||
|
||||
public void save() {
|
||||
@ -154,7 +156,7 @@ public class SessionRecordV2 extends Record {
|
||||
List<SessionStructure> previousStructures = new LinkedList<SessionStructure>();
|
||||
|
||||
for (SessionState previousState : previousStates) {
|
||||
previousStructures.add(previousState.getStructure());
|
||||
previousStructures.add(((TextSecureSessionState)previousState).getStructure());
|
||||
}
|
||||
|
||||
RecordStructure record = RecordStructure.newBuilder()
|
||||
@ -194,16 +196,16 @@ public class SessionRecordV2 extends Record {
|
||||
if (versionMarker == SINGLE_STATE_VERSION) {
|
||||
byte[] plaintextBytes = cipher.decryptBytes(encryptedBlob);
|
||||
SessionStructure sessionStructure = SessionStructure.parseFrom(plaintextBytes);
|
||||
this.sessionState = new SessionState(sessionStructure);
|
||||
this.sessionState = new TextSecureSessionState(sessionStructure);
|
||||
} else if (versionMarker == ARCHIVE_STATES_VERSION) {
|
||||
byte[] plaintextBytes = cipher.decryptBytes(encryptedBlob);
|
||||
RecordStructure recordStructure = RecordStructure.parseFrom(plaintextBytes);
|
||||
|
||||
this.sessionState = new SessionState(recordStructure.getCurrentSession());
|
||||
this.sessionState = new TextSecureSessionState(recordStructure.getCurrentSession());
|
||||
this.previousStates = new LinkedList<SessionState>();
|
||||
|
||||
for (SessionStructure sessionStructure : recordStructure.getPreviousSessionsList()) {
|
||||
this.previousStates.add(new SessionState(sessionStructure));
|
||||
this.previousStates.add(new TextSecureSessionState(sessionStructure));
|
||||
}
|
||||
} else {
|
||||
throw new AssertionError("Unknown version: " + versionMarker);
|
||||
@ -217,8 +219,9 @@ public class SessionRecordV2 extends Record {
|
||||
} catch (IOException ioe) {
|
||||
Log.w("SessionRecordV2", ioe);
|
||||
// XXX
|
||||
} catch (InvalidMessageException e) {
|
||||
Log.w("SessionRecordV2", e);
|
||||
} catch (InvalidMessageException ime) {
|
||||
Log.w("SessionRecordV2", ime);
|
||||
// XXX
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
|
||||
import org.whispersystems.textsecure.crypto.IdentityKey;
|
||||
import org.whispersystems.textsecure.crypto.IdentityKeyPair;
|
||||
import org.whispersystems.textsecure.crypto.InvalidKeyException;
|
||||
import org.whispersystems.textsecure.crypto.ecc.Curve;
|
||||
import org.whispersystems.textsecure.crypto.ecc.ECKeyPair;
|
||||
import org.whispersystems.textsecure.crypto.ecc.ECPrivateKey;
|
||||
import org.whispersystems.textsecure.crypto.ecc.ECPublicKey;
|
||||
import org.whispersystems.textsecure.crypto.ratchet.ChainKey;
|
||||
import org.whispersystems.textsecure.crypto.ratchet.MessageKeys;
|
||||
import org.whispersystems.textsecure.crypto.ratchet.RootKey;
|
||||
import org.whispersystems.libaxolotl.IdentityKey;
|
||||
import org.whispersystems.libaxolotl.IdentityKeyPair;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
import org.whispersystems.libaxolotl.SessionState;
|
||||
import org.whispersystems.libaxolotl.ecc.Curve;
|
||||
import org.whispersystems.libaxolotl.ecc.ECKeyPair;
|
||||
import org.whispersystems.libaxolotl.ecc.ECPrivateKey;
|
||||
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
|
||||
import org.whispersystems.libaxolotl.ratchet.ChainKey;
|
||||
import org.whispersystems.libaxolotl.ratchet.MessageKeys;
|
||||
import org.whispersystems.libaxolotl.ratchet.RootKey;
|
||||
import org.whispersystems.libaxolotl.util.Pair;
|
||||
import org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain;
|
||||
import org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange;
|
||||
import org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey;
|
||||
@ -27,11 +44,11 @@ import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure;
|
||||
|
||||
public class SessionState {
|
||||
public class TextSecureSessionState implements SessionState {
|
||||
|
||||
private SessionStructure sessionStructure;
|
||||
|
||||
public SessionState(SessionStructure sessionStructure) {
|
||||
public TextSecureSessionState(SessionStructure sessionStructure) {
|
||||
this.sessionStructure = sessionStructure;
|
||||
}
|
||||
|
||||
@ -160,7 +177,7 @@ public class SessionState {
|
||||
|
||||
public ChainKey getReceiverChainKey(ECPublicKey senderEphemeral) {
|
||||
Pair<Chain,Integer> receiverChainAndIndex = getReceiverChain(senderEphemeral);
|
||||
Chain receiverChain = receiverChainAndIndex.first;
|
||||
Chain receiverChain = receiverChainAndIndex.first();
|
||||
|
||||
if (receiverChain == null) {
|
||||
return null;
|
||||
@ -225,7 +242,7 @@ public class SessionState {
|
||||
|
||||
public boolean hasMessageKeys(ECPublicKey senderEphemeral, int counter) {
|
||||
Pair<Chain,Integer> chainAndIndex = getReceiverChain(senderEphemeral);
|
||||
Chain chain = chainAndIndex.first;
|
||||
Chain chain = chainAndIndex.first();
|
||||
|
||||
if (chain == null) {
|
||||
return false;
|
||||
@ -244,7 +261,7 @@ public class SessionState {
|
||||
|
||||
public MessageKeys removeMessageKeys(ECPublicKey senderEphemeral, int counter) {
|
||||
Pair<Chain,Integer> chainAndIndex = getReceiverChain(senderEphemeral);
|
||||
Chain chain = chainAndIndex.first;
|
||||
Chain chain = chainAndIndex.first();
|
||||
|
||||
if (chain == null) {
|
||||
return null;
|
||||
@ -272,7 +289,7 @@ public class SessionState {
|
||||
.build();
|
||||
|
||||
this.sessionStructure = this.sessionStructure.toBuilder()
|
||||
.setReceiverChains(chainAndIndex.second, updatedChain)
|
||||
.setReceiverChains(chainAndIndex.second(), updatedChain)
|
||||
.build();
|
||||
|
||||
return result;
|
||||
@ -280,7 +297,7 @@ public class SessionState {
|
||||
|
||||
public void setMessageKeys(ECPublicKey senderEphemeral, MessageKeys messageKeys) {
|
||||
Pair<Chain,Integer> chainAndIndex = getReceiverChain(senderEphemeral);
|
||||
Chain chain = chainAndIndex.first;
|
||||
Chain chain = chainAndIndex.first();
|
||||
Chain.MessageKey messageKeyStructure = Chain.MessageKey.newBuilder()
|
||||
.setCipherKey(ByteString.copyFrom(messageKeys.getCipherKey().getEncoded()))
|
||||
.setMacKey(ByteString.copyFrom(messageKeys.getMacKey().getEncoded()))
|
||||
@ -292,13 +309,13 @@ public class SessionState {
|
||||
.build();
|
||||
|
||||
this.sessionStructure = this.sessionStructure.toBuilder()
|
||||
.setReceiverChains(chainAndIndex.second, updatedChain)
|
||||
.setReceiverChains(chainAndIndex.second(), updatedChain)
|
||||
.build();
|
||||
}
|
||||
|
||||
public void setReceiverChainKey(ECPublicKey senderEphemeral, ChainKey chainKey) {
|
||||
Pair<Chain,Integer> chainAndIndex = getReceiverChain(senderEphemeral);
|
||||
Chain chain = chainAndIndex.first;
|
||||
Chain chain = chainAndIndex.first();
|
||||
|
||||
Chain.ChainKey chainKeyStructure = Chain.ChainKey.newBuilder()
|
||||
.setKey(ByteString.copyFrom(chainKey.getKey()))
|
||||
@ -308,7 +325,7 @@ public class SessionState {
|
||||
Chain updatedChain = chain.toBuilder().setChainKey(chainKeyStructure).build();
|
||||
|
||||
this.sessionStructure = this.sessionStructure.toBuilder()
|
||||
.setReceiverChains(chainAndIndex.second, updatedChain)
|
||||
.setReceiverChains(chainAndIndex.second(), updatedChain)
|
||||
.build();
|
||||
}
|
||||
|
@ -15,10 +15,13 @@
|
||||
* 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.legacy;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import org.whispersystems.textsecure.storage.CanonicalRecipient;
|
||||
import org.whispersystems.textsecure.storage.Record;
|
||||
|
||||
public class LocalKeyRecord {
|
||||
|
||||
public static void delete(Context context, CanonicalRecipient recipient) {
|
@ -14,21 +14,12 @@
|
||||
* 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.legacy;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import org.whispersystems.textsecure.crypto.InvalidKeyException;
|
||||
import org.whispersystems.textsecure.crypto.PublicKey;
|
||||
import org.whispersystems.textsecure.util.Hex;
|
||||
import org.whispersystems.textsecure.util.Medium;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.channels.FileChannel;
|
||||
import org.whispersystems.textsecure.storage.CanonicalRecipient;
|
||||
import org.whispersystems.textsecure.storage.Record;
|
||||
|
||||
/**
|
||||
* Represents the current and last public key belonging to the "remote"
|
@ -1,7 +1,10 @@
|
||||
package org.whispersystems.textsecure.storage;
|
||||
package org.whispersystems.textsecure.storage.legacy;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import org.whispersystems.textsecure.storage.CanonicalRecipient;
|
||||
import org.whispersystems.textsecure.storage.Record;
|
||||
|
||||
/**
|
||||
* A disk record representing a current session.
|
||||
*
|
@ -1 +1 @@
|
||||
include ':library'
|
||||
include ':library', ':libaxolotl'
|
||||
|
@ -102,7 +102,7 @@ import org.thoughtcrime.securesms.util.EncryptedCharacterCalculator;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.thoughtcrime.securesms.util.MemoryCleaner;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.textsecure.crypto.InvalidMessageException;
|
||||
import org.whispersystems.libaxolotl.InvalidMessageException;
|
||||
import org.whispersystems.textsecure.crypto.MasterCipher;
|
||||
import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||
import org.whispersystems.textsecure.storage.RecipientDevice;
|
||||
|
@ -20,7 +20,7 @@ import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.whispersystems.textsecure.crypto.SerializableKey;
|
||||
import org.whispersystems.libaxolotl.IdentityKey;
|
||||
import org.whispersystems.textsecure.util.Base64;
|
||||
import org.thoughtcrime.securesms.util.Dialogs;
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||
@ -112,8 +112,8 @@ public abstract class KeyScanningActivity extends PassphraseRequiredSherlockActi
|
||||
protected abstract String getNotVerifiedTitle();
|
||||
protected abstract String getNotVerifiedMessage();
|
||||
|
||||
protected abstract SerializableKey getIdentityKeyToCompare();
|
||||
protected abstract SerializableKey getIdentityKeyToDisplay();
|
||||
protected abstract IdentityKey getIdentityKeyToCompare();
|
||||
protected abstract IdentityKey getIdentityKeyToDisplay();
|
||||
|
||||
protected abstract String getVerifiedTitle();
|
||||
protected abstract String getVerifiedMessage();
|
||||
|
@ -34,20 +34,21 @@ import org.thoughtcrime.securesms.crypto.DecryptingQueue;
|
||||
import org.thoughtcrime.securesms.crypto.KeyExchangeProcessor;
|
||||
import org.thoughtcrime.securesms.crypto.KeyExchangeProcessorV2;
|
||||
import org.thoughtcrime.securesms.crypto.protocol.KeyExchangeMessage;
|
||||
import org.whispersystems.textsecure.crypto.LegacyMessageException;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.service.SendReceiveService;
|
||||
import org.thoughtcrime.securesms.sms.SmsTransportDetails;
|
||||
import org.thoughtcrime.securesms.util.MemoryCleaner;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.textsecure.crypto.IdentityKey;
|
||||
import org.whispersystems.textsecure.crypto.InvalidKeyException;
|
||||
import org.whispersystems.textsecure.crypto.InvalidMessageException;
|
||||
import org.whispersystems.textsecure.crypto.InvalidVersionException;
|
||||
import org.whispersystems.libaxolotl.IdentityKey;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
import org.whispersystems.libaxolotl.InvalidMessageException;
|
||||
import org.whispersystems.libaxolotl.InvalidVersionException;
|
||||
import org.whispersystems.libaxolotl.LegacyMessageException;
|
||||
import org.whispersystems.libaxolotl.protocol.CiphertextMessage;
|
||||
import org.whispersystems.libaxolotl.protocol.PreKeyWhisperMessage;
|
||||
import org.whispersystems.textsecure.crypto.IdentityKeyParcelable;
|
||||
import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||
import org.whispersystems.textsecure.crypto.protocol.CiphertextMessage;
|
||||
import org.whispersystems.textsecure.crypto.protocol.PreKeyWhisperMessage;
|
||||
import org.whispersystems.textsecure.push.IncomingPushMessage;
|
||||
import org.whispersystems.textsecure.storage.InvalidKeyIdException;
|
||||
import org.whispersystems.textsecure.storage.RecipientDevice;
|
||||
@ -136,7 +137,7 @@ public class ReceiveKeyActivity extends Activity {
|
||||
Intent intent = new Intent(ReceiveKeyActivity.this, VerifyIdentityActivity.class);
|
||||
intent.putExtra("recipient", recipient);
|
||||
intent.putExtra("master_secret", masterSecret);
|
||||
intent.putExtra("remote_identity", remoteIdentity);
|
||||
intent.putExtra("remote_identity", new IdentityKeyParcelable(remoteIdentity));
|
||||
startActivity(intent);
|
||||
}
|
||||
}, getString(R.string.ReceiveKeyActivity_the_signature_on_this_key_exchange_is_different).length() +1,
|
||||
|
@ -26,7 +26,8 @@ import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||
import org.thoughtcrime.securesms.util.MemoryCleaner;
|
||||
import org.whispersystems.textsecure.crypto.IdentityKey;
|
||||
import org.whispersystems.libaxolotl.IdentityKey;
|
||||
import org.whispersystems.textsecure.crypto.IdentityKeyParcelable;
|
||||
import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||
import org.whispersystems.textsecure.storage.Session;
|
||||
|
||||
@ -83,7 +84,12 @@ public class VerifyIdentityActivity extends KeyScanningActivity {
|
||||
}
|
||||
|
||||
private void initializeRemoteIdentityKey() {
|
||||
IdentityKey identityKey = getIntent().getParcelableExtra("remote_identity");
|
||||
IdentityKeyParcelable identityKeyParcelable = getIntent().getParcelableExtra("remote_identity");
|
||||
IdentityKey identityKey = null;
|
||||
|
||||
if (identityKeyParcelable != null) {
|
||||
identityKey = identityKeyParcelable.get();
|
||||
}
|
||||
|
||||
if (identityKey == null) {
|
||||
identityKey = Session.getRemoteIdentityKey(this, masterSecret, recipient);
|
||||
|
@ -19,7 +19,8 @@ package org.thoughtcrime.securesms;
|
||||
import android.os.Bundle;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.whispersystems.textsecure.crypto.IdentityKey;
|
||||
import org.whispersystems.libaxolotl.IdentityKey;
|
||||
import org.whispersystems.textsecure.crypto.IdentityKeyParcelable;
|
||||
|
||||
/**
|
||||
* Activity for displaying an identity key.
|
||||
@ -28,6 +29,9 @@ import org.whispersystems.textsecure.crypto.IdentityKey;
|
||||
*/
|
||||
public class ViewIdentityActivity extends KeyScanningActivity {
|
||||
|
||||
public static final String IDENTITY_KEY = "identity_key";
|
||||
public static final String TITLE = "title";
|
||||
|
||||
private TextView identityFingerprint;
|
||||
private IdentityKey identityKey;
|
||||
|
||||
@ -54,12 +58,18 @@ public class ViewIdentityActivity extends KeyScanningActivity {
|
||||
}
|
||||
|
||||
private void initializeResources() {
|
||||
this.identityKey = (IdentityKey)getIntent().getParcelableExtra("identity_key");
|
||||
IdentityKeyParcelable identityKeyParcelable = getIntent().getParcelableExtra(IDENTITY_KEY);
|
||||
|
||||
if (identityKeyParcelable == null) {
|
||||
throw new AssertionError("No identity key!");
|
||||
}
|
||||
|
||||
this.identityKey = identityKeyParcelable.get();
|
||||
this.identityFingerprint = (TextView)findViewById(R.id.identity_fingerprint);
|
||||
String title = getIntent().getStringExtra("title");
|
||||
String title = getIntent().getStringExtra(TITLE);
|
||||
|
||||
if (title != null) {
|
||||
getSupportActionBar().setTitle(getIntent().getStringExtra("title"));
|
||||
getSupportActionBar().setTitle(getIntent().getStringExtra(TITLE));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,20 +17,14 @@
|
||||
*/
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuInflater;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
|
||||
import org.thoughtcrime.securesms.util.Dialogs;
|
||||
import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||
import org.whispersystems.textsecure.crypto.IdentityKeyParcelable;
|
||||
|
||||
/**
|
||||
* Activity that displays the local identity key and offers the option to regenerate it.
|
||||
@ -39,13 +33,11 @@ import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||
*/
|
||||
public class ViewLocalIdentityActivity extends ViewIdentityActivity {
|
||||
|
||||
private MasterSecret masterSecret;
|
||||
|
||||
public void onCreate(Bundle bundle) {
|
||||
this.masterSecret = getIntent().getParcelableExtra("master_secret");
|
||||
|
||||
getIntent().putExtra("identity_key", IdentityKeyUtil.getIdentityKey(this));
|
||||
getIntent().putExtra("title", getString(R.string.ViewIdentityActivity_my_identity_fingerprint));
|
||||
getIntent().putExtra(ViewIdentityActivity.IDENTITY_KEY,
|
||||
new IdentityKeyParcelable(IdentityKeyUtil.getIdentityKey(this)));
|
||||
getIntent().putExtra(ViewIdentityActivity.TITLE,
|
||||
getString(R.string.ViewIdentityActivity_my_identity_fingerprint));
|
||||
super.onCreate(bundle);
|
||||
}
|
||||
|
||||
@ -64,62 +56,9 @@ public class ViewLocalIdentityActivity extends ViewIdentityActivity {
|
||||
super.onOptionsItemSelected(item);
|
||||
|
||||
switch (item.getItemId()) {
|
||||
// case R.id.menu_regenerate_key: promptToRegenerateIdentityKey(); return true;
|
||||
case android.R.id.home: finish(); return true;
|
||||
case android.R.id.home:finish(); return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void promptToRegenerateIdentityKey() {
|
||||
AlertDialog.Builder dialog = new AlertDialog.Builder(this);
|
||||
dialog.setIcon(Dialogs.resolveIcon(this, R.attr.dialog_alert_icon));
|
||||
dialog.setTitle(getString(R.string.ViewLocalIdentityActivity_reset_identity_key));
|
||||
dialog.setMessage(getString(R.string.ViewLocalIdentityActivity_by_regenerating_your_identity_key_your_existing_contacts_will_receive_warnings));
|
||||
dialog.setNegativeButton(getString(R.string.ViewLocalIdentityActivity_cancel), null);
|
||||
dialog.setPositiveButton(getString(R.string.ViewLocalIdentityActivity_continue),
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
regenerateIdentityKey();
|
||||
}
|
||||
});
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
private void regenerateIdentityKey() {
|
||||
new AsyncTask<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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -17,7 +17,6 @@
|
||||
package org.thoughtcrime.securesms.contacts;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.MergeCursor;
|
||||
@ -25,7 +24,6 @@ import android.net.Uri;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.provider.ContactsContract;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Im;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Phone;
|
||||
import android.provider.ContactsContract.Contacts;
|
||||
import android.provider.ContactsContract.Data;
|
||||
@ -33,15 +31,9 @@ import android.provider.ContactsContract.PhoneLookup;
|
||||
import android.support.v4.content.CursorLoader;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.telephony.PhoneNumberUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import org.whispersystems.textsecure.crypto.IdentityKey;
|
||||
import org.whispersystems.textsecure.crypto.InvalidKeyException;
|
||||
import org.whispersystems.textsecure.directory.Directory;
|
||||
import org.whispersystems.textsecure.util.Base64;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.Long;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
@ -248,49 +240,6 @@ public class ContactAccessor {
|
||||
return Phone.getTypeLabel(mContext.getResources(), type, label);
|
||||
}
|
||||
|
||||
public void insertIdentityKey(Context context, List<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) {
|
||||
Cursor cursor = null;
|
||||
|
||||
|
@ -17,15 +17,15 @@
|
||||
*/
|
||||
package org.thoughtcrime.securesms.crypto;
|
||||
|
||||
import org.whispersystems.textsecure.crypto.InvalidKeyException;
|
||||
import org.whispersystems.textsecure.crypto.InvalidMessageException;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
import org.whispersystems.libaxolotl.InvalidMessageException;
|
||||
import org.whispersystems.libaxolotl.ecc.Curve;
|
||||
import org.whispersystems.libaxolotl.ecc.ECKeyPair;
|
||||
import org.whispersystems.libaxolotl.ecc.ECPrivateKey;
|
||||
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
|
||||
import org.whispersystems.textsecure.crypto.MasterCipher;
|
||||
import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||
import org.whispersystems.textsecure.crypto.PublicKey;
|
||||
import org.whispersystems.textsecure.crypto.ecc.Curve;
|
||||
import org.whispersystems.textsecure.crypto.ecc.ECKeyPair;
|
||||
import org.whispersystems.textsecure.crypto.ecc.ECPrivateKey;
|
||||
import org.whispersystems.textsecure.crypto.ecc.ECPublicKey;
|
||||
import org.whispersystems.textsecure.util.Base64;
|
||||
import org.whispersystems.textsecure.util.Conversions;
|
||||
import org.whispersystems.textsecure.util.Util;
|
||||
|
@ -17,9 +17,8 @@
|
||||
*/
|
||||
package org.thoughtcrime.securesms.crypto;
|
||||
|
||||
import org.whispersystems.textsecure.crypto.ecc.Curve;
|
||||
import org.whispersystems.textsecure.crypto.ecc.ECPrivateKey;
|
||||
import org.whispersystems.textsecure.crypto.ecc.ECPublicKey;
|
||||
import org.whispersystems.libaxolotl.ecc.ECPrivateKey;
|
||||
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
|
||||
|
||||
/**
|
||||
* When a user first initializes TextSecure, a few secrets
|
||||
@ -40,7 +39,7 @@ import org.whispersystems.textsecure.crypto.ecc.ECPublicKey;
|
||||
|
||||
public class AsymmetricMasterSecret {
|
||||
|
||||
private final ECPublicKey djbPublicKey;
|
||||
private final ECPublicKey djbPublicKey;
|
||||
private final ECPrivateKey djbPrivateKey;
|
||||
|
||||
|
||||
|
@ -23,7 +23,6 @@ import android.database.Cursor;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.protocol.KeyExchangeMessage;
|
||||
import org.whispersystems.textsecure.crypto.LegacyMessageException;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.EncryptingSmsDatabase;
|
||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||
@ -41,13 +40,15 @@ import org.thoughtcrime.securesms.service.PushReceiver;
|
||||
import org.thoughtcrime.securesms.service.SendReceiveService;
|
||||
import org.thoughtcrime.securesms.sms.SmsTransportDetails;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.textsecure.crypto.DuplicateMessageException;
|
||||
import org.whispersystems.textsecure.crypto.InvalidKeyException;
|
||||
import org.whispersystems.textsecure.crypto.InvalidMessageException;
|
||||
import org.whispersystems.textsecure.crypto.InvalidVersionException;
|
||||
import org.whispersystems.libaxolotl.DuplicateMessageException;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
import org.whispersystems.libaxolotl.InvalidMessageException;
|
||||
import org.whispersystems.libaxolotl.InvalidVersionException;
|
||||
import org.whispersystems.libaxolotl.LegacyMessageException;
|
||||
import org.whispersystems.libaxolotl.SessionCipher;
|
||||
import org.whispersystems.libaxolotl.protocol.WhisperMessage;
|
||||
import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||
import org.whispersystems.textsecure.crypto.SessionCipher;
|
||||
import org.whispersystems.textsecure.crypto.protocol.WhisperMessage;
|
||||
import org.whispersystems.textsecure.crypto.SessionCipherFactory;
|
||||
import org.whispersystems.textsecure.push.IncomingPushMessage;
|
||||
import org.whispersystems.textsecure.storage.RecipientDevice;
|
||||
import org.whispersystems.textsecure.storage.Session;
|
||||
@ -205,7 +206,7 @@ public class DecryptingQueue {
|
||||
return;
|
||||
}
|
||||
|
||||
SessionCipher sessionCipher = SessionCipher.createFor(context, masterSecret, recipientDevice);
|
||||
SessionCipher sessionCipher = SessionCipherFactory.getInstance(context, masterSecret, recipientDevice);
|
||||
byte[] plaintextBody = sessionCipher.decrypt(message.getBody());
|
||||
|
||||
message = message.withBody(plaintextBody);
|
||||
@ -290,7 +291,7 @@ public class DecryptingQueue {
|
||||
|
||||
Log.w("DecryptingQueue", "Decrypting: " + Hex.toString(ciphertextPduBytes));
|
||||
TextTransport transportDetails = new TextTransport();
|
||||
SessionCipher sessionCipher = SessionCipher.createFor(context, masterSecret, recipientDevice);
|
||||
SessionCipher sessionCipher = SessionCipherFactory.getInstance(context, masterSecret, recipientDevice);
|
||||
byte[] decodedCiphertext = transportDetails.getDecodedMessage(ciphertextPduBytes);
|
||||
|
||||
try {
|
||||
@ -385,7 +386,7 @@ public class DecryptingQueue {
|
||||
return;
|
||||
}
|
||||
|
||||
SessionCipher sessionCipher = SessionCipher.createFor(context, masterSecret, recipientDevice);
|
||||
SessionCipher sessionCipher = SessionCipherFactory.getInstance(context, masterSecret, recipientDevice);
|
||||
byte[] paddedPlaintext = sessionCipher.decrypt(decodedCiphertext);
|
||||
|
||||
plaintextBody = new String(transportDetails.getStrippedPaddingMessageBody(paddedPlaintext));
|
||||
|
@ -22,14 +22,14 @@ import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.Editor;
|
||||
import android.util.Log;
|
||||
|
||||
import org.whispersystems.textsecure.crypto.IdentityKey;
|
||||
import org.whispersystems.textsecure.crypto.IdentityKeyPair;
|
||||
import org.whispersystems.textsecure.crypto.InvalidKeyException;
|
||||
import org.whispersystems.libaxolotl.IdentityKey;
|
||||
import org.whispersystems.libaxolotl.IdentityKeyPair;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
import org.whispersystems.libaxolotl.ecc.Curve;
|
||||
import org.whispersystems.libaxolotl.ecc.ECKeyPair;
|
||||
import org.whispersystems.libaxolotl.ecc.ECPrivateKey;
|
||||
import org.whispersystems.textsecure.crypto.MasterCipher;
|
||||
import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||
import org.whispersystems.textsecure.crypto.ecc.Curve;
|
||||
import org.whispersystems.textsecure.crypto.ecc.ECKeyPair;
|
||||
import org.whispersystems.textsecure.crypto.ecc.ECPrivateKey;
|
||||
import org.whispersystems.textsecure.util.Base64;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -27,10 +27,10 @@ import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.sms.MessageSender;
|
||||
import org.thoughtcrime.securesms.sms.OutgoingKeyExchangeMessage;
|
||||
import org.thoughtcrime.securesms.util.Dialogs;
|
||||
import org.whispersystems.textsecure.crypto.IdentityKeyPair;
|
||||
import org.whispersystems.libaxolotl.IdentityKeyPair;
|
||||
import org.whispersystems.libaxolotl.ecc.Curve;
|
||||
import org.whispersystems.libaxolotl.ecc.ECKeyPair;
|
||||
import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||
import org.whispersystems.textsecure.crypto.ecc.Curve;
|
||||
import org.whispersystems.textsecure.crypto.ecc.ECKeyPair;
|
||||
import org.whispersystems.textsecure.storage.RecipientDevice;
|
||||
import org.whispersystems.textsecure.storage.SessionRecordV2;
|
||||
|
||||
|
@ -21,10 +21,8 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.protocol.KeyExchangeMessage;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||
import org.thoughtcrime.securesms.service.KeyCachingService;
|
||||
import org.whispersystems.textsecure.crypto.InvalidMessageException;
|
||||
import org.whispersystems.libaxolotl.InvalidMessageException;
|
||||
import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||
import org.whispersystems.textsecure.storage.RecipientDevice;
|
||||
|
||||
|
@ -12,16 +12,16 @@ import org.thoughtcrime.securesms.service.PreKeyService;
|
||||
import org.thoughtcrime.securesms.sms.MessageSender;
|
||||
import org.thoughtcrime.securesms.sms.OutgoingKeyExchangeMessage;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.textsecure.crypto.IdentityKey;
|
||||
import org.whispersystems.textsecure.crypto.IdentityKeyPair;
|
||||
import org.whispersystems.textsecure.crypto.InvalidKeyException;
|
||||
import org.whispersystems.textsecure.crypto.InvalidMessageException;
|
||||
import org.whispersystems.libaxolotl.IdentityKey;
|
||||
import org.whispersystems.libaxolotl.IdentityKeyPair;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
import org.whispersystems.libaxolotl.InvalidMessageException;
|
||||
import org.whispersystems.libaxolotl.ecc.Curve;
|
||||
import org.whispersystems.libaxolotl.ecc.ECKeyPair;
|
||||
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
|
||||
import org.whispersystems.libaxolotl.protocol.PreKeyWhisperMessage;
|
||||
import org.whispersystems.libaxolotl.ratchet.RatchetingSession;
|
||||
import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||
import org.whispersystems.textsecure.crypto.ecc.Curve;
|
||||
import org.whispersystems.textsecure.crypto.ecc.ECKeyPair;
|
||||
import org.whispersystems.textsecure.crypto.ecc.ECPublicKey;
|
||||
import org.whispersystems.textsecure.crypto.protocol.PreKeyWhisperMessage;
|
||||
import org.whispersystems.textsecure.crypto.ratchet.RatchetingSession;
|
||||
import org.whispersystems.textsecure.push.PreKeyEntity;
|
||||
import org.whispersystems.textsecure.storage.InvalidKeyIdException;
|
||||
import org.whispersystems.textsecure.storage.PreKeyRecord;
|
||||
|
@ -21,13 +21,13 @@ import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.util.Log;
|
||||
|
||||
import org.whispersystems.textsecure.crypto.InvalidKeyException;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
import org.whispersystems.libaxolotl.ecc.Curve;
|
||||
import org.whispersystems.libaxolotl.ecc.ECKeyPair;
|
||||
import org.whispersystems.libaxolotl.ecc.ECPrivateKey;
|
||||
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
|
||||
import org.whispersystems.textsecure.crypto.MasterCipher;
|
||||
import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||
import org.whispersystems.textsecure.crypto.ecc.Curve;
|
||||
import org.whispersystems.textsecure.crypto.ecc.ECKeyPair;
|
||||
import org.whispersystems.textsecure.crypto.ecc.ECPrivateKey;
|
||||
import org.whispersystems.textsecure.crypto.ecc.ECPublicKey;
|
||||
import org.whispersystems.textsecure.util.Base64;
|
||||
import org.whispersystems.textsecure.util.Util;
|
||||
|
||||
@ -129,8 +129,8 @@ public class MasterSecretUtil {
|
||||
byte[] djbPublicBytes = retrieve(context, ASYMMETRIC_LOCAL_PUBLIC_DJB);
|
||||
byte[] djbPrivateBytes = retrieve(context, ASYMMETRIC_LOCAL_PRIVATE_DJB);
|
||||
|
||||
ECPublicKey djbPublicKey = null;
|
||||
ECPrivateKey djbPrivateKey = null;
|
||||
ECPublicKey djbPublicKey = null;
|
||||
ECPrivateKey djbPrivateKey = null;
|
||||
|
||||
if (djbPublicBytes != null) {
|
||||
djbPublicKey = Curve.decodePoint(djbPublicBytes, 0);
|
||||
|
@ -17,12 +17,12 @@
|
||||
*/
|
||||
package org.thoughtcrime.securesms.crypto.protocol;
|
||||
|
||||
import org.whispersystems.textsecure.crypto.IdentityKey;
|
||||
import org.whispersystems.textsecure.crypto.InvalidKeyException;
|
||||
import org.whispersystems.textsecure.crypto.InvalidMessageException;
|
||||
import org.whispersystems.textsecure.crypto.InvalidVersionException;
|
||||
import org.whispersystems.textsecure.crypto.LegacyMessageException;
|
||||
|
||||
import org.whispersystems.libaxolotl.IdentityKey;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
import org.whispersystems.libaxolotl.InvalidMessageException;
|
||||
import org.whispersystems.libaxolotl.InvalidVersionException;
|
||||
import org.whispersystems.libaxolotl.LegacyMessageException;
|
||||
|
||||
public abstract class KeyExchangeMessage {
|
||||
public abstract IdentityKey getIdentityKey();
|
||||
|
@ -3,15 +3,15 @@ package org.thoughtcrime.securesms.crypto.protocol;
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
|
||||
import org.whispersystems.textsecure.crypto.IdentityKey;
|
||||
import org.whispersystems.textsecure.crypto.InvalidKeyException;
|
||||
import org.whispersystems.textsecure.crypto.InvalidMessageException;
|
||||
import org.whispersystems.textsecure.crypto.InvalidVersionException;
|
||||
import org.whispersystems.textsecure.crypto.LegacyMessageException;
|
||||
import org.whispersystems.textsecure.crypto.ecc.Curve;
|
||||
import org.whispersystems.textsecure.crypto.ecc.ECPublicKey;
|
||||
import org.whispersystems.textsecure.crypto.protocol.CiphertextMessage;
|
||||
import org.whispersystems.textsecure.crypto.protocol.WhisperProtos;
|
||||
import org.whispersystems.libaxolotl.IdentityKey;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
import org.whispersystems.libaxolotl.InvalidMessageException;
|
||||
import org.whispersystems.libaxolotl.InvalidVersionException;
|
||||
import org.whispersystems.libaxolotl.LegacyMessageException;
|
||||
import org.whispersystems.libaxolotl.ecc.Curve;
|
||||
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
|
||||
import org.whispersystems.libaxolotl.protocol.CiphertextMessage;
|
||||
import org.whispersystems.libaxolotl.protocol.WhisperProtos;
|
||||
import org.whispersystems.textsecure.util.Base64;
|
||||
import org.whispersystems.textsecure.util.Conversions;
|
||||
import org.whispersystems.textsecure.util.Util;
|
||||
|
@ -28,11 +28,11 @@ import org.thoughtcrime.securesms.DatabaseUpgradeActivity;
|
||||
import org.thoughtcrime.securesms.crypto.DecryptingPartInputStream;
|
||||
import org.thoughtcrime.securesms.crypto.DecryptingQueue;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
|
||||
import org.whispersystems.textsecure.crypto.IdentityKey;
|
||||
import org.whispersystems.textsecure.crypto.InvalidMessageException;
|
||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||
import org.whispersystems.libaxolotl.IdentityKey;
|
||||
import org.whispersystems.libaxolotl.InvalidMessageException;
|
||||
import org.whispersystems.textsecure.crypto.MasterCipher;
|
||||
import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||
import org.whispersystems.textsecure.storage.Session;
|
||||
import org.whispersystems.textsecure.util.Base64;
|
||||
import org.whispersystems.textsecure.util.Util;
|
||||
|
@ -7,7 +7,7 @@ import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.util.Log;
|
||||
|
||||
import org.whispersystems.textsecure.crypto.InvalidMessageException;
|
||||
import org.whispersystems.libaxolotl.InvalidMessageException;
|
||||
import org.whispersystems.textsecure.crypto.MasterCipher;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
@ -28,7 +28,7 @@ import org.thoughtcrime.securesms.database.model.DisplayRecord;
|
||||
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
|
||||
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
|
||||
import org.thoughtcrime.securesms.util.LRUCache;
|
||||
import org.whispersystems.textsecure.crypto.InvalidMessageException;
|
||||
import org.whispersystems.libaxolotl.InvalidMessageException;
|
||||
import org.whispersystems.textsecure.crypto.MasterCipher;
|
||||
import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||
|
||||
|
@ -24,14 +24,12 @@ import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
import org.whispersystems.textsecure.crypto.IdentityKey;
|
||||
import org.whispersystems.textsecure.crypto.InvalidKeyException;
|
||||
import org.whispersystems.libaxolotl.IdentityKey;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
import org.whispersystems.textsecure.crypto.MasterCipher;
|
||||
import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||
import org.whispersystems.textsecure.crypto.ecc.Curve;
|
||||
import org.whispersystems.textsecure.util.Base64;
|
||||
|
||||
import java.io.IOException;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user