├── settings.gradle
├── .gitignore
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── protobuf
├── Makefile
├── FingerprintProtocol.proto
├── WhisperTextProtocol.proto
└── LocalStorageProtocol.proto
├── android
├── src
│ ├── main
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── org
│ │ │ └── whispersystems
│ │ │ └── libsignal
│ │ │ └── util
│ │ │ └── AndroidSignalProtocolLogger.java
│ └── androidTest
│ │ └── java
│ │ └── org
│ │ └── whispersystems
│ │ └── libsignal
│ │ └── CurveTest.java
└── build.gradle
├── java
├── src
│ ├── main
│ │ └── java
│ │ │ └── org
│ │ │ └── whispersystems
│ │ │ └── libsignal
│ │ │ ├── StaleKeyExchangeException.java
│ │ │ ├── util
│ │ │ ├── Medium.java
│ │ │ ├── guava
│ │ │ │ ├── Supplier.java
│ │ │ │ ├── Function.java
│ │ │ │ ├── Absent.java
│ │ │ │ └── Present.java
│ │ │ ├── Pair.java
│ │ │ ├── Hex.java
│ │ │ └── KeyHelper.java
│ │ │ ├── DecryptionCallback.java
│ │ │ ├── kdf
│ │ │ ├── HKDFv2.java
│ │ │ ├── HKDFv3.java
│ │ │ ├── DerivedRootSecrets.java
│ │ │ ├── DerivedMessageSecrets.java
│ │ │ └── HKDF.java
│ │ │ ├── LegacyMessageException.java
│ │ │ ├── state
│ │ │ ├── SignalProtocolStore.java
│ │ │ ├── impl
│ │ │ │ ├── InMemoryPreKeyStore.java
│ │ │ │ ├── InMemoryIdentityKeyStore.java
│ │ │ │ ├── InMemorySignedPreKeyStore.java
│ │ │ │ ├── InMemorySessionStore.java
│ │ │ │ └── InMemorySignalProtocolStore.java
│ │ │ ├── PreKeyStore.java
│ │ │ ├── SignedPreKeyStore.java
│ │ │ ├── PreKeyRecord.java
│ │ │ ├── IdentityKeyStore.java
│ │ │ ├── SignedPreKeyRecord.java
│ │ │ ├── SessionStore.java
│ │ │ ├── PreKeyBundle.java
│ │ │ └── SessionRecord.java
│ │ │ ├── DuplicateMessageException.java
│ │ │ ├── fingerprint
│ │ │ ├── FingerprintParsingException.java
│ │ │ ├── FingerprintVersionMismatchException.java
│ │ │ ├── FingerprintGenerator.java
│ │ │ ├── DisplayableFingerprint.java
│ │ │ ├── Fingerprint.java
│ │ │ ├── FingerprintIdentifierMismatchException.java
│ │ │ ├── NumericFingerprintGenerator.java
│ │ │ └── ScannableFingerprint.java
│ │ │ ├── NoSessionException.java
│ │ │ ├── logging
│ │ │ ├── SignalProtocolLoggerProvider.java
│ │ │ ├── SignalProtocolLogger.java
│ │ │ └── Log.java
│ │ │ ├── UntrustedIdentityException.java
│ │ │ ├── ecc
│ │ │ ├── ECPrivateKey.java
│ │ │ ├── ECPublicKey.java
│ │ │ ├── ECKeyPair.java
│ │ │ ├── DjbECPrivateKey.java
│ │ │ ├── DjbECPublicKey.java
│ │ │ └── Curve.java
│ │ │ ├── InvalidVersionException.java
│ │ │ ├── SignalProtocolAddress.java
│ │ │ ├── InvalidMacException.java
│ │ │ ├── InvalidKeyIdException.java
│ │ │ ├── InvalidKeyException.java
│ │ │ ├── InvalidMessageException.java
│ │ │ ├── protocol
│ │ │ ├── CiphertextMessage.java
│ │ │ ├── SenderKeyDistributionMessage.java
│ │ │ ├── SenderKeyMessage.java
│ │ │ ├── KeyExchangeMessage.java
│ │ │ ├── PreKeySignalMessage.java
│ │ │ └── SignalMessage.java
│ │ │ ├── ratchet
│ │ │ ├── MessageKeys.java
│ │ │ ├── RootKey.java
│ │ │ ├── ChainKey.java
│ │ │ ├── SymmetricSignalProtocolParameters.java
│ │ │ ├── BobSignalProtocolParameters.java
│ │ │ └── AliceSignalProtocolParameters.java
│ │ │ ├── groups
│ │ │ ├── ratchet
│ │ │ │ ├── SenderMessageKey.java
│ │ │ │ └── SenderChainKey.java
│ │ │ ├── SenderKeyName.java
│ │ │ ├── state
│ │ │ │ ├── SenderKeyStore.java
│ │ │ │ ├── SenderKeyRecord.java
│ │ │ │ └── SenderKeyState.java
│ │ │ └── GroupSessionBuilder.java
│ │ │ ├── IdentityKey.java
│ │ │ └── IdentityKeyPair.java
│ └── test
│ │ └── java
│ │ └── org
│ │ └── whispersystems
│ │ └── libsignal
│ │ └── CurveTest.java
└── build.gradle
├── tests
├── build.gradle
└── src
│ └── test
│ └── java
│ └── org
│ └── whispersystems
│ └── libsignal
│ ├── TestInMemoryIdentityKeyStore.java
│ ├── TestInMemorySignalProtocolStore.java
│ ├── groups
│ └── InMemorySenderKeyStore.java
│ ├── fingerprint
│ └── NumericFingerprintGeneratorTest.java
│ └── ratchet
│ ├── RootKeyTest.java
│ └── ChainKeyTest.java
├── gradlew.bat
├── README.md
└── gradlew
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':java', ':android', ':tests'
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 | /obj
3 | *.iml
4 | .gradle
5 | .idea
6 | gradle.properties
7 | local.properties
8 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/angebagui/libsignal-protocol-java/master/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/protobuf/Makefile:
--------------------------------------------------------------------------------
1 |
2 | all:
3 | protoc --java_out=../java/src/main/java/ WhisperTextProtocol.proto LocalStorageProtocol.proto FingerprintProtocol.proto
4 |
--------------------------------------------------------------------------------
/android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/StaleKeyExchangeException.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libsignal;
2 |
3 | public class StaleKeyExchangeException extends Throwable {
4 | }
5 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/util/Medium.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libsignal.util;
2 |
3 | public class Medium {
4 | public static int MAX_VALUE = 0xFFFFFF;
5 | }
6 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/DecryptionCallback.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libsignal;
2 |
3 | public interface DecryptionCallback {
4 | public void handlePlaintext(byte[] plaintext);
5 | }
--------------------------------------------------------------------------------
/tests/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java'
2 |
3 | repositories {
4 | mavenCentral()
5 | mavenLocal()
6 | }
7 |
8 | dependencies {
9 | testCompile 'junit:junit:3.8.2'
10 |
11 | compile project(':java')
12 | }
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/kdf/HKDFv2.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libsignal.kdf;
2 |
3 | public class HKDFv2 extends HKDF {
4 | @Override
5 | protected int getIterationStartOffset() {
6 | return 0;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/kdf/HKDFv3.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libsignal.kdf;
2 |
3 | public class HKDFv3 extends HKDF {
4 | @Override
5 | protected int getIterationStartOffset() {
6 | return 1;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/LegacyMessageException.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libsignal;
2 |
3 | public class LegacyMessageException extends Exception {
4 | public LegacyMessageException(String s) {
5 | super(s);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/state/SignalProtocolStore.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libsignal.state;
2 |
3 | public interface SignalProtocolStore
4 | extends IdentityKeyStore, PreKeyStore, SessionStore, SignedPreKeyStore
5 | {
6 | }
7 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/DuplicateMessageException.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libsignal;
2 |
3 | public class DuplicateMessageException extends Exception {
4 | public DuplicateMessageException(String s) {
5 | super(s);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Dec 09 10:15:39 PST 2014
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
7 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/fingerprint/FingerprintParsingException.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libsignal.fingerprint;
2 |
3 | public class FingerprintParsingException extends Exception {
4 |
5 | public FingerprintParsingException(Exception nested) {
6 | super(nested);
7 | }
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/NoSessionException.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libsignal;
2 |
3 | public class NoSessionException extends Exception {
4 | public NoSessionException(String s) {
5 | super(s);
6 | }
7 |
8 | public NoSessionException(Exception nested) {
9 | super(nested);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/fingerprint/FingerprintVersionMismatchException.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libsignal.fingerprint;
2 |
3 | public class FingerprintVersionMismatchException extends Exception {
4 |
5 | public FingerprintVersionMismatchException() {
6 | super();
7 | }
8 |
9 | public FingerprintVersionMismatchException(Exception e) {
10 | super(e);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/fingerprint/FingerprintGenerator.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libsignal.fingerprint;
2 |
3 | import org.whispersystems.libsignal.IdentityKey;
4 |
5 | public interface FingerprintGenerator {
6 | public Fingerprint createFor(String localStableIdentifier, IdentityKey localIdentityKey,
7 | String remoteStableIdentifier, IdentityKey remoteIdentityKey);
8 | }
9 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/logging/SignalProtocolLoggerProvider.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libsignal.logging;
2 |
3 | public class SignalProtocolLoggerProvider {
4 |
5 | private static SignalProtocolLogger provider;
6 |
7 | public static SignalProtocolLogger getProvider() {
8 | return provider;
9 | }
10 |
11 | public static void setProvider(SignalProtocolLogger provider) {
12 | SignalProtocolLoggerProvider.provider = provider;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/protobuf/FingerprintProtocol.proto:
--------------------------------------------------------------------------------
1 | package textsecure;
2 |
3 | option java_package = "org.whispersystems.libsignal.fingerprint";
4 | option java_outer_classname = "FingerprintProtos";
5 |
6 | message FingerprintData {
7 | optional bytes publicKey = 1;
8 | optional bytes identifier = 2;
9 | }
10 |
11 | message CombinedFingerprint {
12 | optional uint32 version = 1;
13 | optional FingerprintData localFingerprint = 2;
14 | optional FingerprintData remoteFingerprint = 3;
15 | }
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/logging/SignalProtocolLogger.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libsignal.logging;
2 |
3 | public interface SignalProtocolLogger {
4 |
5 | public static final int VERBOSE = 2;
6 | public static final int DEBUG = 3;
7 | public static final int INFO = 4;
8 | public static final int WARN = 5;
9 | public static final int ERROR = 6;
10 | public static final int ASSERT = 7;
11 |
12 | public void log(int priority, String tag, String message);
13 | }
14 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/UntrustedIdentityException.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libsignal;
2 |
3 | public class UntrustedIdentityException extends Exception {
4 |
5 | private final String name;
6 | private final IdentityKey key;
7 |
8 | public UntrustedIdentityException(String name, IdentityKey key) {
9 | this.name = name;
10 | this.key = key;
11 | }
12 |
13 | public IdentityKey getUntrustedIdentity() {
14 | return key;
15 | }
16 |
17 | public String getName() {
18 | return name;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/kdf/DerivedRootSecrets.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libsignal.kdf;
2 |
3 | import org.whispersystems.libsignal.util.ByteUtil;
4 |
5 | public class DerivedRootSecrets {
6 |
7 | public static final int SIZE = 64;
8 |
9 | private final byte[] rootKey;
10 | private final byte[] chainKey;
11 |
12 | public DerivedRootSecrets(byte[] okm) {
13 | byte[][] keys = ByteUtil.split(okm, 32, 32);
14 | this.rootKey = keys[0];
15 | this.chainKey = keys[1];
16 | }
17 |
18 | public byte[] getRootKey() {
19 | return rootKey;
20 | }
21 |
22 | public byte[] getChainKey() {
23 | return chainKey;
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/fingerprint/DisplayableFingerprint.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libsignal.fingerprint;
2 |
3 | public class DisplayableFingerprint {
4 |
5 | private final String localFingerprint;
6 | private final String remoteFingerprint;
7 |
8 | public DisplayableFingerprint(String localFingerprint, String remoteFingerprint) {
9 | this.localFingerprint = localFingerprint;
10 | this.remoteFingerprint = remoteFingerprint;
11 | }
12 |
13 | public String getDisplayText() {
14 | if (localFingerprint.compareTo(remoteFingerprint) <= 0) {
15 | return localFingerprint + remoteFingerprint;
16 | } else {
17 | return remoteFingerprint + localFingerprint;
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/java/src/test/java/org/whispersystems/libsignal/CurveTest.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libsignal;
2 |
3 | import junit.framework.TestCase;
4 |
5 | import org.whispersystems.libsignal.ecc.Curve;
6 | import org.whispersystems.libsignal.ecc.ECKeyPair;
7 |
8 | public class CurveTest extends TestCase {
9 |
10 | public void testPureJava() {
11 | assertFalse(Curve.isNative());
12 | }
13 |
14 | public void testLargeSignatures() throws InvalidKeyException {
15 | ECKeyPair keys = Curve.generateKeyPair();
16 | byte[] message = new byte[1024 * 1024];
17 | byte[] signature = Curve.calculateSignature(keys.getPrivateKey(), message);
18 |
19 | assertTrue(Curve.verifySignature(keys.getPublicKey(), message, signature));
20 |
21 | message[0] ^= 0x01;
22 |
23 | assertFalse(Curve.verifySignature(keys.getPublicKey(), message, signature));
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/android/src/androidTest/java/org/whispersystems/libsignal/CurveTest.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libsignal;
2 |
3 | import junit.framework.TestCase;
4 |
5 | import org.whispersystems.libsignal.ecc.Curve;
6 | import org.whispersystems.libsignal.ecc.ECKeyPair;
7 |
8 | public class CurveTest extends TestCase {
9 |
10 | public void testPureJava() {
11 | assertTrue(Curve.isNative());
12 | }
13 |
14 | public void testLargeSignatures() throws InvalidKeyException {
15 | ECKeyPair keys = Curve.generateKeyPair();
16 | byte[] message = new byte[1024 * 1024];
17 | byte[] signature = Curve.calculateSignature(keys.getPrivateKey(), message);
18 |
19 | assertTrue(Curve.verifySignature(keys.getPublicKey(), message, signature));
20 |
21 | message[0] ^= 0x01;
22 |
23 | assertFalse(Curve.verifySignature(keys.getPublicKey(), message, signature));
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/android/src/main/java/org/whispersystems/libsignal/util/AndroidSignalProtocolLogger.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libsignal.util;
2 |
3 | import android.util.Log;
4 | import android.util.SparseIntArray;
5 |
6 | import org.whispersystems.libsignal.logging.SignalProtocolLogger;
7 |
8 | public class AndroidSignalProtocolLogger implements SignalProtocolLogger {
9 |
10 | private static final SparseIntArray PRIORITY_MAP = new SparseIntArray(5) {{
11 | put(SignalProtocolLogger.INFO, Log.INFO);
12 | put(SignalProtocolLogger.ASSERT, Log.ASSERT);
13 | put(SignalProtocolLogger.DEBUG, Log.DEBUG);
14 | put(SignalProtocolLogger.VERBOSE, Log.VERBOSE);
15 | put(SignalProtocolLogger.WARN, Log.WARN);
16 |
17 | }};
18 |
19 | @Override
20 | public void log(int priority, String tag, String message) {
21 | int androidPriority = PRIORITY_MAP.get(priority, Log.WARN);
22 | Log.println(androidPriority, tag, message);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/tests/src/test/java/org/whispersystems/libsignal/TestInMemoryIdentityKeyStore.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libsignal;
2 |
3 | import org.whispersystems.libsignal.ecc.Curve;
4 | import org.whispersystems.libsignal.ecc.ECKeyPair;
5 | import org.whispersystems.libsignal.util.KeyHelper;
6 |
7 | public class TestInMemoryIdentityKeyStore extends org.whispersystems.libsignal.state.impl.InMemoryIdentityKeyStore {
8 | public TestInMemoryIdentityKeyStore() {
9 | super(generateIdentityKeyPair(), generateRegistrationId());
10 | }
11 |
12 | private static IdentityKeyPair generateIdentityKeyPair() {
13 | ECKeyPair identityKeyPairKeys = Curve.generateKeyPair();
14 |
15 | return new IdentityKeyPair(new IdentityKey(identityKeyPairKeys.getPublicKey()),
16 | identityKeyPairKeys.getPrivateKey());
17 | }
18 |
19 | private static int generateRegistrationId() {
20 | return KeyHelper.generateRegistrationId(false);
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/ecc/ECPrivateKey.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2013 Open Whisper Systems
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package org.whispersystems.libsignal.ecc;
19 |
20 | public interface ECPrivateKey {
21 | public byte[] serialize();
22 | public int getType();
23 | }
24 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/fingerprint/Fingerprint.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libsignal.fingerprint;
2 |
3 | public class Fingerprint {
4 |
5 | private final DisplayableFingerprint displayableFingerprint;
6 | private final ScannableFingerprint scannableFingerprint;
7 |
8 | public Fingerprint(DisplayableFingerprint displayableFingerprint,
9 | ScannableFingerprint scannableFingerprint)
10 | {
11 | this.displayableFingerprint = displayableFingerprint;
12 | this.scannableFingerprint = scannableFingerprint;
13 | }
14 |
15 | /**
16 | * @return A text fingerprint that can be displayed and compared remotely.
17 | */
18 | public DisplayableFingerprint getDisplayableFingerprint() {
19 | return displayableFingerprint;
20 | }
21 |
22 | /**
23 | * @return A scannable fingerprint that can be scanned anc compared locally.
24 | */
25 | public ScannableFingerprint getScannableFingerprint() {
26 | return scannableFingerprint;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/tests/src/test/java/org/whispersystems/libsignal/TestInMemorySignalProtocolStore.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libsignal;
2 |
3 | import org.whispersystems.libsignal.ecc.Curve;
4 | import org.whispersystems.libsignal.ecc.ECKeyPair;
5 | import org.whispersystems.libsignal.state.impl.InMemorySignalProtocolStore;
6 | import org.whispersystems.libsignal.util.KeyHelper;
7 |
8 | public class TestInMemorySignalProtocolStore extends InMemorySignalProtocolStore {
9 | public TestInMemorySignalProtocolStore() {
10 | super(generateIdentityKeyPair(), generateRegistrationId());
11 | }
12 |
13 | private static IdentityKeyPair generateIdentityKeyPair() {
14 | ECKeyPair identityKeyPairKeys = Curve.generateKeyPair();
15 |
16 | return new IdentityKeyPair(new IdentityKey(identityKeyPairKeys.getPublicKey()),
17 | identityKeyPairKeys.getPrivateKey());
18 | }
19 |
20 | private static int generateRegistrationId() {
21 | return KeyHelper.generateRegistrationId(false);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/InvalidVersionException.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2014 Open Whisper Systems
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package org.whispersystems.libsignal;
18 |
19 | public class InvalidVersionException extends Exception {
20 | public InvalidVersionException(String detailMessage) {
21 | super(detailMessage);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/ecc/ECPublicKey.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2013 Open Whisper Systems
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package org.whispersystems.libsignal.ecc;
19 |
20 | public interface ECPublicKey extends Comparable {
21 |
22 | public static final int KEY_SIZE = 33;
23 |
24 | public byte[] serialize();
25 |
26 | public int getType();
27 | }
28 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/SignalProtocolAddress.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libsignal;
2 |
3 | public class SignalProtocolAddress {
4 |
5 | private final String name;
6 | private final int deviceId;
7 |
8 | public SignalProtocolAddress(String name, int deviceId) {
9 | this.name = name;
10 | this.deviceId = deviceId;
11 | }
12 |
13 | public String getName() {
14 | return name;
15 | }
16 |
17 | public int getDeviceId() {
18 | return deviceId;
19 | }
20 |
21 | @Override
22 | public String toString() {
23 | return name + ":" + deviceId;
24 | }
25 |
26 | @Override
27 | public boolean equals(Object other) {
28 | if (other == null) return false;
29 | if (!(other instanceof SignalProtocolAddress)) return false;
30 |
31 | SignalProtocolAddress that = (SignalProtocolAddress)other;
32 | return this.name.equals(that.name) && this.deviceId == that.deviceId;
33 | }
34 |
35 | @Override
36 | public int hashCode() {
37 | return this.name.hashCode() ^ this.deviceId;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/tests/src/test/java/org/whispersystems/libsignal/groups/InMemorySenderKeyStore.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libsignal.groups;
2 |
3 | import org.whispersystems.libsignal.groups.state.SenderKeyRecord;
4 | import org.whispersystems.libsignal.groups.state.SenderKeyStore;
5 |
6 | import java.io.IOException;
7 | import java.util.HashMap;
8 | import java.util.Map;
9 |
10 | public class InMemorySenderKeyStore implements SenderKeyStore {
11 |
12 | private final Map store = new HashMap<>();
13 |
14 | @Override
15 | public void storeSenderKey(SenderKeyName senderKeyName, SenderKeyRecord record) {
16 | store.put(senderKeyName, record);
17 | }
18 |
19 | @Override
20 | public SenderKeyRecord loadSenderKey(SenderKeyName senderKeyName) {
21 | try {
22 | SenderKeyRecord record = store.get(senderKeyName);
23 |
24 | if (record == null) {
25 | return new SenderKeyRecord();
26 | } else {
27 | return new SenderKeyRecord(record.serialize());
28 | }
29 | } catch (IOException e) {
30 | throw new AssertionError(e);
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/InvalidMacException.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2014 Open Whisper Systems
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package org.whispersystems.libsignal;
18 |
19 | public class InvalidMacException extends Exception {
20 |
21 | public InvalidMacException(String detailMessage) {
22 | super(detailMessage);
23 | }
24 |
25 | public InvalidMacException(Throwable throwable) {
26 | super(throwable);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/InvalidKeyIdException.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2014 Open Whisper Systems
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package org.whispersystems.libsignal;
18 |
19 | public class InvalidKeyIdException extends Exception {
20 | public InvalidKeyIdException(String detailMessage) {
21 | super(detailMessage);
22 | }
23 |
24 | public InvalidKeyIdException(Throwable throwable) {
25 | super(throwable);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/fingerprint/FingerprintIdentifierMismatchException.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libsignal.fingerprint;
2 |
3 | public class FingerprintIdentifierMismatchException extends Exception {
4 |
5 | private final String localIdentifier;
6 | private final String remoteIdentifier;
7 | private final String scannedLocalIdentifier;
8 | private final String scannedRemoteIdentifier;
9 |
10 | public FingerprintIdentifierMismatchException(String localIdentifier, String remoteIdentifier,
11 | String scannedLocalIdentifier, String scannedRemoteIdentifier)
12 | {
13 | this.localIdentifier = localIdentifier;
14 | this.remoteIdentifier = remoteIdentifier;
15 | this.scannedLocalIdentifier = scannedLocalIdentifier;
16 | this.scannedRemoteIdentifier = scannedRemoteIdentifier;
17 | }
18 |
19 | public String getScannedRemoteIdentifier() {
20 | return scannedRemoteIdentifier;
21 | }
22 |
23 | public String getScannedLocalIdentifier() {
24 | return scannedLocalIdentifier;
25 | }
26 |
27 | public String getRemoteIdentifier() {
28 | return remoteIdentifier;
29 | }
30 |
31 | public String getLocalIdentifier() {
32 | return localIdentifier;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/InvalidKeyException.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2014 Open Whisper Systems
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package org.whispersystems.libsignal;
18 |
19 | public class InvalidKeyException extends Exception {
20 |
21 | public InvalidKeyException() {}
22 |
23 | public InvalidKeyException(String detailMessage) {
24 | super(detailMessage);
25 | }
26 |
27 | public InvalidKeyException(Throwable throwable) {
28 | super(throwable);
29 | }
30 |
31 | public InvalidKeyException(String detailMessage, Throwable throwable) {
32 | super(detailMessage, throwable);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/protobuf/WhisperTextProtocol.proto:
--------------------------------------------------------------------------------
1 | package textsecure;
2 |
3 | option java_package = "org.whispersystems.libsignal.protocol";
4 | option java_outer_classname = "SignalProtos";
5 |
6 | message SignalMessage {
7 | optional bytes ratchetKey = 1;
8 | optional uint32 counter = 2;
9 | optional uint32 previousCounter = 3;
10 | optional bytes ciphertext = 4;
11 | }
12 |
13 | message PreKeySignalMessage {
14 | optional uint32 registrationId = 5;
15 | optional uint32 preKeyId = 1;
16 | optional uint32 signedPreKeyId = 6;
17 | optional bytes baseKey = 2;
18 | optional bytes identityKey = 3;
19 | optional bytes message = 4; // WhisperMessage
20 | }
21 |
22 | message KeyExchangeMessage {
23 | optional uint32 id = 1;
24 | optional bytes baseKey = 2;
25 | optional bytes ratchetKey = 3;
26 | optional bytes identityKey = 4;
27 | optional bytes baseKeySignature = 5;
28 | }
29 |
30 | message SenderKeyMessage {
31 | optional uint32 id = 1;
32 | optional uint32 iteration = 2;
33 | optional bytes ciphertext = 3;
34 | }
35 |
36 | message SenderKeyDistributionMessage {
37 | optional uint32 id = 1;
38 | optional uint32 iteration = 2;
39 | optional bytes chainKey = 3;
40 | optional bytes signingKey = 4;
41 | }
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/ecc/ECKeyPair.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2013 Open Whisper Systems
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package org.whispersystems.libsignal.ecc;
19 |
20 | public class ECKeyPair {
21 |
22 | private final ECPublicKey publicKey;
23 | private final ECPrivateKey privateKey;
24 |
25 | public ECKeyPair(ECPublicKey publicKey, ECPrivateKey privateKey) {
26 | this.publicKey = publicKey;
27 | this.privateKey = privateKey;
28 | }
29 |
30 | public ECPublicKey getPublicKey() {
31 | return publicKey;
32 | }
33 |
34 | public ECPrivateKey getPrivateKey() {
35 | return privateKey;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/state/impl/InMemoryPreKeyStore.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libsignal.state.impl;
2 |
3 | import org.whispersystems.libsignal.InvalidKeyIdException;
4 | import org.whispersystems.libsignal.state.PreKeyRecord;
5 | import org.whispersystems.libsignal.state.PreKeyStore;
6 |
7 | import java.io.IOException;
8 | import java.util.HashMap;
9 | import java.util.Map;
10 |
11 | public class InMemoryPreKeyStore implements PreKeyStore {
12 |
13 | private final Map store = new HashMap<>();
14 |
15 | @Override
16 | public PreKeyRecord loadPreKey(int preKeyId) throws InvalidKeyIdException {
17 | try {
18 | if (!store.containsKey(preKeyId)) {
19 | throw new InvalidKeyIdException("No such prekeyrecord!");
20 | }
21 |
22 | return new PreKeyRecord(store.get(preKeyId));
23 | } catch (IOException e) {
24 | throw new AssertionError(e);
25 | }
26 | }
27 |
28 | @Override
29 | public void storePreKey(int preKeyId, PreKeyRecord record) {
30 | store.put(preKeyId, record.serialize());
31 | }
32 |
33 | @Override
34 | public boolean containsPreKey(int preKeyId) {
35 | return store.containsKey(preKeyId);
36 | }
37 |
38 | @Override
39 | public void removePreKey(int preKeyId) {
40 | store.remove(preKeyId);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/ecc/DjbECPrivateKey.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2013 Open Whisper Systems
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package org.whispersystems.libsignal.ecc;
19 |
20 | public class DjbECPrivateKey implements ECPrivateKey {
21 |
22 | private final byte[] privateKey;
23 |
24 | DjbECPrivateKey(byte[] privateKey) {
25 | this.privateKey = privateKey;
26 | }
27 |
28 | @Override
29 | public byte[] serialize() {
30 | return privateKey;
31 | }
32 |
33 | @Override
34 | public int getType() {
35 | return Curve.DJB_TYPE;
36 | }
37 |
38 | public byte[] getPrivateKey() {
39 | return privateKey;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/state/PreKeyStore.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libsignal.state;
2 |
3 | import org.whispersystems.libsignal.InvalidKeyIdException;
4 |
5 | /**
6 | * An interface describing the local storage of {@link PreKeyRecord}s.
7 | *
8 | * @author Moxie Marlinspike
9 | */
10 | public interface PreKeyStore {
11 |
12 | /**
13 | * Load a local PreKeyRecord.
14 | *
15 | * @param preKeyId the ID of the local PreKeyRecord.
16 | * @return the corresponding PreKeyRecord.
17 | * @throws InvalidKeyIdException when there is no corresponding PreKeyRecord.
18 | */
19 | public PreKeyRecord loadPreKey(int preKeyId) throws InvalidKeyIdException;
20 |
21 | /**
22 | * Store a local PreKeyRecord.
23 | *
24 | * @param preKeyId the ID of the PreKeyRecord to store.
25 | * @param record the PreKeyRecord.
26 | */
27 | public void storePreKey(int preKeyId, PreKeyRecord record);
28 |
29 | /**
30 | * @param preKeyId A PreKeyRecord ID.
31 | * @return true if the store has a record for the preKeyId, otherwise false.
32 | */
33 | public boolean containsPreKey(int preKeyId);
34 |
35 | /**
36 | * Delete a PreKeyRecord from local storage.
37 | *
38 | * @param preKeyId The ID of the PreKeyRecord to remove.
39 | */
40 | public void removePreKey(int preKeyId);
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/util/guava/Supplier.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2007 The Guava Authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.whispersystems.libsignal.util.guava;
18 |
19 |
20 | /**
21 | * A class that can supply objects of a single type. Semantically, this could
22 | * be a factory, generator, builder, closure, or something else entirely. No
23 | * guarantees are implied by this interface.
24 | *
25 | * @author Harry Heymann
26 | * @since 2.0 (imported from Google Collections Library)
27 | */
28 | public interface Supplier {
29 | /**
30 | * Retrieves an instance of the appropriate type. The returned object may or
31 | * may not be a new instance, depending on the implementation.
32 | *
33 | * @return an instance of the appropriate type
34 | */
35 | T get();
36 | }
37 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/InvalidMessageException.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2014 Open Whisper Systems
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package org.whispersystems.libsignal;
18 |
19 | import java.util.List;
20 |
21 | public class InvalidMessageException extends Exception {
22 |
23 | public InvalidMessageException() {}
24 |
25 | public InvalidMessageException(String detailMessage) {
26 | super(detailMessage);
27 | }
28 |
29 | public InvalidMessageException(Throwable throwable) {
30 | super(throwable);
31 | }
32 |
33 | public InvalidMessageException(String detailMessage, Throwable throwable) {
34 | super(detailMessage, throwable);
35 | }
36 |
37 | public InvalidMessageException(String detailMessage, List exceptions) {
38 | super(detailMessage, exceptions.get(0));
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/protocol/CiphertextMessage.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2014 Open Whisper Systems
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package org.whispersystems.libsignal.protocol;
18 |
19 | public interface CiphertextMessage {
20 |
21 | public static final int UNSUPPORTED_VERSION = 1;
22 | public static final int CURRENT_VERSION = 3;
23 |
24 | public static final int WHISPER_TYPE = 2;
25 | public static final int PREKEY_TYPE = 3;
26 | public static final int SENDERKEY_TYPE = 4;
27 | public static final int SENDERKEY_DISTRIBUTION_TYPE = 5;
28 |
29 | // This should be the worst case (worse than V2). So not always accurate, but good enough for padding.
30 | public static final int ENCRYPTED_MESSAGE_OVERHEAD = 53;
31 |
32 | public byte[] serialize();
33 | public int getType();
34 |
35 | }
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/state/SignedPreKeyStore.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libsignal.state;
2 |
3 | import org.whispersystems.libsignal.InvalidKeyIdException;
4 |
5 | import java.util.List;
6 |
7 | public interface SignedPreKeyStore {
8 |
9 |
10 | /**
11 | * Load a local SignedPreKeyRecord.
12 | *
13 | * @param signedPreKeyId the ID of the local SignedPreKeyRecord.
14 | * @return the corresponding SignedPreKeyRecord.
15 | * @throws InvalidKeyIdException when there is no corresponding SignedPreKeyRecord.
16 | */
17 | public SignedPreKeyRecord loadSignedPreKey(int signedPreKeyId) throws InvalidKeyIdException;
18 |
19 | /**
20 | * Load all local SignedPreKeyRecords.
21 | *
22 | * @return All stored SignedPreKeyRecords.
23 | */
24 | public List loadSignedPreKeys();
25 |
26 | /**
27 | * Store a local SignedPreKeyRecord.
28 | *
29 | * @param signedPreKeyId the ID of the SignedPreKeyRecord to store.
30 | * @param record the SignedPreKeyRecord.
31 | */
32 | public void storeSignedPreKey(int signedPreKeyId, SignedPreKeyRecord record);
33 |
34 | /**
35 | * @param signedPreKeyId A SignedPreKeyRecord ID.
36 | * @return true if the store has a record for the signedPreKeyId, otherwise false.
37 | */
38 | public boolean containsSignedPreKey(int signedPreKeyId);
39 |
40 | /**
41 | * Delete a SignedPreKeyRecord from local storage.
42 | *
43 | * @param signedPreKeyId The ID of the SignedPreKeyRecord to remove.
44 | */
45 | public void removeSignedPreKey(int signedPreKeyId);
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/state/impl/InMemoryIdentityKeyStore.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libsignal.state.impl;
2 |
3 | import org.whispersystems.libsignal.IdentityKey;
4 | import org.whispersystems.libsignal.IdentityKeyPair;
5 | import org.whispersystems.libsignal.ecc.Curve;
6 | import org.whispersystems.libsignal.ecc.ECKeyPair;
7 | import org.whispersystems.libsignal.state.IdentityKeyStore;
8 |
9 | import java.security.NoSuchAlgorithmException;
10 | import java.security.SecureRandom;
11 | import java.util.HashMap;
12 | import java.util.Map;
13 |
14 | public class InMemoryIdentityKeyStore implements IdentityKeyStore {
15 |
16 | private final Map trustedKeys = new HashMap<>();
17 |
18 | private final IdentityKeyPair identityKeyPair;
19 | private final int localRegistrationId;
20 |
21 | public InMemoryIdentityKeyStore(IdentityKeyPair identityKeyPair, int localRegistrationId) {
22 | this.identityKeyPair = identityKeyPair;
23 | this.localRegistrationId = localRegistrationId;
24 | }
25 |
26 | @Override
27 | public IdentityKeyPair getIdentityKeyPair() {
28 | return identityKeyPair;
29 | }
30 |
31 | @Override
32 | public int getLocalRegistrationId() {
33 | return localRegistrationId;
34 | }
35 |
36 | @Override
37 | public void saveIdentity(String name, IdentityKey identityKey) {
38 | trustedKeys.put(name, identityKey);
39 | }
40 |
41 | @Override
42 | public boolean isTrustedIdentity(String name, IdentityKey identityKey) {
43 | IdentityKey trusted = trustedKeys.get(name);
44 | return (trusted == null || trusted.equals(identityKey));
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/util/Pair.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2014 Open WhisperSystems
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package org.whispersystems.libsignal.util;
18 |
19 | public class Pair {
20 | private final T1 v1;
21 | private final T2 v2;
22 |
23 | public Pair(T1 v1, T2 v2) {
24 | this.v1 = v1;
25 | this.v2 = v2;
26 | }
27 |
28 | public T1 first(){
29 | return v1;
30 | }
31 |
32 | public T2 second(){
33 | return v2;
34 | }
35 |
36 | public boolean equals(Object o) {
37 | return o instanceof Pair &&
38 | equal(((Pair) o).first(), first()) &&
39 | equal(((Pair) o).second(), second());
40 | }
41 |
42 | public int hashCode() {
43 | return first().hashCode() ^ second().hashCode();
44 | }
45 |
46 | private boolean equal(Object first, Object second) {
47 | if (first == null && second == null) return true;
48 | if (first == null || second == null) return false;
49 | return first.equals(second);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/ratchet/MessageKeys.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2014 Open Whisper Systems
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package org.whispersystems.libsignal.ratchet;
18 |
19 | import javax.crypto.spec.IvParameterSpec;
20 | import javax.crypto.spec.SecretKeySpec;
21 |
22 | public class MessageKeys {
23 |
24 | private final SecretKeySpec cipherKey;
25 | private final SecretKeySpec macKey;
26 | private final IvParameterSpec iv;
27 | private final int counter;
28 |
29 | public MessageKeys(SecretKeySpec cipherKey, SecretKeySpec macKey, IvParameterSpec iv, int counter) {
30 | this.cipherKey = cipherKey;
31 | this.macKey = macKey;
32 | this.iv = iv;
33 | this.counter = counter;
34 | }
35 |
36 | public SecretKeySpec getCipherKey() {
37 | return cipherKey;
38 | }
39 |
40 | public SecretKeySpec getMacKey() {
41 | return macKey;
42 | }
43 |
44 | public IvParameterSpec getIv() {
45 | return iv;
46 | }
47 |
48 | public int getCounter() {
49 | return counter;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/state/impl/InMemorySignedPreKeyStore.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libsignal.state.impl;
2 |
3 | import org.whispersystems.libsignal.InvalidKeyIdException;
4 | import org.whispersystems.libsignal.state.SignedPreKeyRecord;
5 | import org.whispersystems.libsignal.state.SignedPreKeyStore;
6 |
7 | import java.io.IOException;
8 | import java.util.HashMap;
9 | import java.util.LinkedList;
10 | import java.util.List;
11 | import java.util.Map;
12 |
13 | public class InMemorySignedPreKeyStore implements SignedPreKeyStore {
14 |
15 | private final Map store = new HashMap<>();
16 |
17 | @Override
18 | public SignedPreKeyRecord loadSignedPreKey(int signedPreKeyId) throws InvalidKeyIdException {
19 | try {
20 | if (!store.containsKey(signedPreKeyId)) {
21 | throw new InvalidKeyIdException("No such signedprekeyrecord! " + signedPreKeyId);
22 | }
23 |
24 | return new SignedPreKeyRecord(store.get(signedPreKeyId));
25 | } catch (IOException e) {
26 | throw new AssertionError(e);
27 | }
28 | }
29 |
30 | @Override
31 | public List loadSignedPreKeys() {
32 | try {
33 | List results = new LinkedList<>();
34 |
35 | for (byte[] serialized : store.values()) {
36 | results.add(new SignedPreKeyRecord(serialized));
37 | }
38 |
39 | return results;
40 | } catch (IOException e) {
41 | throw new AssertionError(e);
42 | }
43 | }
44 |
45 | @Override
46 | public void storeSignedPreKey(int signedPreKeyId, SignedPreKeyRecord record) {
47 | store.put(signedPreKeyId, record.serialize());
48 | }
49 |
50 | @Override
51 | public boolean containsSignedPreKey(int signedPreKeyId) {
52 | return store.containsKey(signedPreKeyId);
53 | }
54 |
55 | @Override
56 | public void removeSignedPreKey(int signedPreKeyId) {
57 | store.remove(signedPreKeyId);
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/groups/ratchet/SenderMessageKey.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2014-2015 Open Whisper Systems
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package org.whispersystems.libsignal.groups.ratchet;
19 |
20 | import org.whispersystems.libsignal.kdf.HKDFv3;
21 | import org.whispersystems.libsignal.util.ByteUtil;
22 |
23 | /**
24 | * The final symmetric material (IV and Cipher Key) used for encrypting
25 | * individual SenderKey messages.
26 | *
27 | * @author Moxie Marlinspike
28 | */
29 | public class SenderMessageKey {
30 |
31 | private final int iteration;
32 | private final byte[] iv;
33 | private final byte[] cipherKey;
34 | private final byte[] seed;
35 |
36 | public SenderMessageKey(int iteration, byte[] seed) {
37 | byte[] derivative = new HKDFv3().deriveSecrets(seed, "WhisperGroup".getBytes(), 48);
38 | byte[][] parts = ByteUtil.split(derivative, 16, 32);
39 |
40 | this.iteration = iteration;
41 | this.seed = seed;
42 | this.iv = parts[0];
43 | this.cipherKey = parts[1];
44 | }
45 |
46 | public int getIteration() {
47 | return iteration;
48 | }
49 |
50 | public byte[] getIv() {
51 | return iv;
52 | }
53 |
54 | public byte[] getCipherKey() {
55 | return cipherKey;
56 | }
57 |
58 | public byte[] getSeed() {
59 | return seed;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/state/PreKeyRecord.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libsignal.state;
2 |
3 | import com.google.protobuf.ByteString;
4 |
5 | import org.whispersystems.libsignal.InvalidKeyException;
6 | import org.whispersystems.libsignal.ecc.Curve;
7 | import org.whispersystems.libsignal.ecc.ECKeyPair;
8 | import org.whispersystems.libsignal.ecc.ECPrivateKey;
9 | import org.whispersystems.libsignal.ecc.ECPublicKey;
10 |
11 | import java.io.IOException;
12 |
13 | import static org.whispersystems.libsignal.state.StorageProtos.PreKeyRecordStructure;
14 |
15 | public class PreKeyRecord {
16 |
17 | private PreKeyRecordStructure structure;
18 |
19 | public PreKeyRecord(int id, ECKeyPair keyPair) {
20 | this.structure = PreKeyRecordStructure.newBuilder()
21 | .setId(id)
22 | .setPublicKey(ByteString.copyFrom(keyPair.getPublicKey()
23 | .serialize()))
24 | .setPrivateKey(ByteString.copyFrom(keyPair.getPrivateKey()
25 | .serialize()))
26 | .build();
27 | }
28 |
29 | public PreKeyRecord(byte[] serialized) throws IOException {
30 | this.structure = PreKeyRecordStructure.parseFrom(serialized);
31 | }
32 |
33 | public int getId() {
34 | return this.structure.getId();
35 | }
36 |
37 | public ECKeyPair getKeyPair() {
38 | try {
39 | ECPublicKey publicKey = Curve.decodePoint(this.structure.getPublicKey().toByteArray(), 0);
40 | ECPrivateKey privateKey = Curve.decodePrivatePoint(this.structure.getPrivateKey().toByteArray());
41 |
42 | return new ECKeyPair(publicKey, privateKey);
43 | } catch (InvalidKeyException e) {
44 | throw new AssertionError(e);
45 | }
46 | }
47 |
48 | public byte[] serialize() {
49 | return this.structure.toByteArray();
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/state/IdentityKeyStore.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libsignal.state;
2 |
3 | import org.whispersystems.libsignal.IdentityKey;
4 | import org.whispersystems.libsignal.IdentityKeyPair;
5 |
6 | /**
7 | * Provides an interface to identity information.
8 | *
9 | * @author Moxie Marlinspike
10 | */
11 | public interface IdentityKeyStore {
12 |
13 | /**
14 | * Get the local client's identity key pair.
15 | *
16 | * @return The local client's persistent identity key pair.
17 | */
18 | public IdentityKeyPair getIdentityKeyPair();
19 |
20 | /**
21 | * Return the local client's registration ID.
22 | *
23 | * Clients should maintain a registration ID, a random number
24 | * between 1 and 16380 that's generated once at install time.
25 | *
26 | * @return the local client's registration ID.
27 | */
28 | public int getLocalRegistrationId();
29 |
30 | /**
31 | * Save a remote client's identity key
32 | *
33 | * Store a remote client's identity key as trusted.
34 | *
35 | * @param name The name of the remote client.
36 | * @param identityKey The remote client's identity key.
37 | */
38 | public void saveIdentity(String name, IdentityKey identityKey);
39 |
40 |
41 | /**
42 | * Verify a remote client's identity key.
43 | *
44 | * Determine whether a remote client's identity is trusted. Convention is
45 | * that the TextSecure protocol is 'trust on first use.' This means that
46 | * an identity key is considered 'trusted' if there is no entry for the recipient
47 | * in the local store, or if it matches the saved key for a recipient in the local
48 | * store. Only if it mismatches an entry in the local store is it considered
49 | * 'untrusted.'
50 | *
51 | * @param name The name of the remote client.
52 | * @param identityKey The identity key to verify.
53 | * @return true if trusted, false if untrusted.
54 | */
55 | public boolean isTrustedIdentity(String name, IdentityKey identityKey);
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/IdentityKey.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2014 Open Whisper Systems
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package org.whispersystems.libsignal;
18 |
19 |
20 | import org.whispersystems.libsignal.ecc.Curve;
21 | import org.whispersystems.libsignal.ecc.ECPublicKey;
22 | import org.whispersystems.libsignal.util.Hex;
23 |
24 | /**
25 | * A class for representing an identity key.
26 | *
27 | * @author Moxie Marlinspike
28 | */
29 |
30 | public class IdentityKey {
31 |
32 | private final ECPublicKey publicKey;
33 |
34 | public IdentityKey(ECPublicKey publicKey) {
35 | this.publicKey = publicKey;
36 | }
37 |
38 | public IdentityKey(byte[] bytes, int offset) throws InvalidKeyException {
39 | this.publicKey = Curve.decodePoint(bytes, offset);
40 | }
41 |
42 | public ECPublicKey getPublicKey() {
43 | return publicKey;
44 | }
45 |
46 | public byte[] serialize() {
47 | return publicKey.serialize();
48 | }
49 |
50 | public String getFingerprint() {
51 | return Hex.toString(publicKey.serialize());
52 | }
53 |
54 | @Override
55 | public boolean equals(Object other) {
56 | if (other == null) return false;
57 | if (!(other instanceof IdentityKey)) return false;
58 |
59 | return publicKey.equals(((IdentityKey) other).getPublicKey());
60 | }
61 |
62 | @Override
63 | public int hashCode() {
64 | return publicKey.hashCode();
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/ecc/DjbECPublicKey.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2013 Open Whisper Systems
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package org.whispersystems.libsignal.ecc;
19 |
20 | import org.whispersystems.libsignal.util.ByteUtil;
21 |
22 | import java.math.BigInteger;
23 | import java.util.Arrays;
24 |
25 | public class DjbECPublicKey implements ECPublicKey {
26 |
27 | private final byte[] publicKey;
28 |
29 | DjbECPublicKey(byte[] publicKey) {
30 | this.publicKey = publicKey;
31 | }
32 |
33 | @Override
34 | public byte[] serialize() {
35 | byte[] type = {Curve.DJB_TYPE};
36 | return ByteUtil.combine(type, publicKey);
37 | }
38 |
39 | @Override
40 | public int getType() {
41 | return Curve.DJB_TYPE;
42 | }
43 |
44 | @Override
45 | public boolean equals(Object other) {
46 | if (other == null) return false;
47 | if (!(other instanceof DjbECPublicKey)) return false;
48 |
49 | DjbECPublicKey that = (DjbECPublicKey)other;
50 | return Arrays.equals(this.publicKey, that.publicKey);
51 | }
52 |
53 | @Override
54 | public int hashCode() {
55 | return Arrays.hashCode(publicKey);
56 | }
57 |
58 | @Override
59 | public int compareTo(ECPublicKey another) {
60 | return new BigInteger(publicKey).compareTo(new BigInteger(((DjbECPublicKey)another).publicKey));
61 | }
62 |
63 | public byte[] getPublicKey() {
64 | return publicKey;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/groups/SenderKeyName.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2014-2015 Open Whisper Systems
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package org.whispersystems.libsignal.groups;
18 |
19 | import org.whispersystems.libsignal.SignalProtocolAddress;
20 |
21 | /**
22 | * A representation of a (groupId + senderId + deviceId) tuple.
23 | */
24 | public class SenderKeyName {
25 |
26 | private final String groupId;
27 | private final SignalProtocolAddress sender;
28 |
29 | public SenderKeyName(String groupId, SignalProtocolAddress sender) {
30 | this.groupId = groupId;
31 | this.sender = sender;
32 | }
33 |
34 | public String getGroupId() {
35 | return groupId;
36 | }
37 |
38 | public SignalProtocolAddress getSender() {
39 | return sender;
40 | }
41 |
42 | public String serialize() {
43 | return groupId + "::" + sender.getName() + "::" + String.valueOf(sender.getDeviceId());
44 | }
45 |
46 | @Override
47 | public boolean equals(Object other) {
48 | if (other == null) return false;
49 | if (!(other instanceof SenderKeyName)) return false;
50 |
51 | SenderKeyName that = (SenderKeyName)other;
52 |
53 | return
54 | this.groupId.equals(that.groupId) &&
55 | this.sender.equals(that.sender);
56 | }
57 |
58 | @Override
59 | public int hashCode() {
60 | return this.groupId.hashCode() ^ this.sender.hashCode();
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/kdf/DerivedMessageSecrets.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2014 Open Whisper Systems
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package org.whispersystems.libsignal.kdf;
19 |
20 | import org.whispersystems.libsignal.util.ByteUtil;
21 |
22 | import java.text.ParseException;
23 |
24 | import javax.crypto.spec.IvParameterSpec;
25 | import javax.crypto.spec.SecretKeySpec;
26 |
27 | public class DerivedMessageSecrets {
28 |
29 | public static final int SIZE = 80;
30 | private static final int CIPHER_KEY_LENGTH = 32;
31 | private static final int MAC_KEY_LENGTH = 32;
32 | private static final int IV_LENGTH = 16;
33 |
34 | private final SecretKeySpec cipherKey;
35 | private final SecretKeySpec macKey;
36 | private final IvParameterSpec iv;
37 |
38 | public DerivedMessageSecrets(byte[] okm) {
39 | try {
40 | byte[][] keys = ByteUtil.split(okm, CIPHER_KEY_LENGTH, MAC_KEY_LENGTH, IV_LENGTH);
41 |
42 | this.cipherKey = new SecretKeySpec(keys[0], "AES");
43 | this.macKey = new SecretKeySpec(keys[1], "HmacSHA256");
44 | this.iv = new IvParameterSpec(keys[2]);
45 | } catch (ParseException e) {
46 | throw new AssertionError(e);
47 | }
48 | }
49 |
50 | public SecretKeySpec getCipherKey() {
51 | return cipherKey;
52 | }
53 |
54 | public SecretKeySpec getMacKey() {
55 | return macKey;
56 | }
57 |
58 | public IvParameterSpec getIv() {
59 | return iv;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/state/impl/InMemorySessionStore.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libsignal.state.impl;
2 |
3 | import org.whispersystems.libsignal.SignalProtocolAddress;
4 | import org.whispersystems.libsignal.state.SessionRecord;
5 | import org.whispersystems.libsignal.state.SessionStore;
6 |
7 | import java.io.IOException;
8 | import java.util.HashMap;
9 | import java.util.LinkedList;
10 | import java.util.List;
11 | import java.util.Map;
12 |
13 | public class InMemorySessionStore implements SessionStore {
14 |
15 | private Map sessions = new HashMap<>();
16 |
17 | public InMemorySessionStore() {}
18 |
19 | @Override
20 | public synchronized SessionRecord loadSession(SignalProtocolAddress remoteAddress) {
21 | try {
22 | if (containsSession(remoteAddress)) {
23 | return new SessionRecord(sessions.get(remoteAddress));
24 | } else {
25 | return new SessionRecord();
26 | }
27 | } catch (IOException e) {
28 | throw new AssertionError(e);
29 | }
30 | }
31 |
32 | @Override
33 | public synchronized List getSubDeviceSessions(String name) {
34 | List deviceIds = new LinkedList<>();
35 |
36 | for (SignalProtocolAddress key : sessions.keySet()) {
37 | if (key.getName().equals(name) &&
38 | key.getDeviceId() != 1)
39 | {
40 | deviceIds.add(key.getDeviceId());
41 | }
42 | }
43 |
44 | return deviceIds;
45 | }
46 |
47 | @Override
48 | public synchronized void storeSession(SignalProtocolAddress address, SessionRecord record) {
49 | sessions.put(address, record.serialize());
50 | }
51 |
52 | @Override
53 | public synchronized boolean containsSession(SignalProtocolAddress address) {
54 | return sessions.containsKey(address);
55 | }
56 |
57 | @Override
58 | public synchronized void deleteSession(SignalProtocolAddress address) {
59 | sessions.remove(address);
60 | }
61 |
62 | @Override
63 | public synchronized void deleteAllSessions(String name) {
64 | for (SignalProtocolAddress key : sessions.keySet()) {
65 | if (key.getName().equals(name)) {
66 | sessions.remove(key);
67 | }
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/ratchet/RootKey.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2014 Open Whisper Systems
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package org.whispersystems.libsignal.ratchet;
18 |
19 | import org.whispersystems.libsignal.InvalidKeyException;
20 | import org.whispersystems.libsignal.ecc.Curve;
21 | import org.whispersystems.libsignal.ecc.ECKeyPair;
22 | import org.whispersystems.libsignal.ecc.ECPublicKey;
23 | import org.whispersystems.libsignal.kdf.DerivedRootSecrets;
24 | import org.whispersystems.libsignal.kdf.HKDF;
25 | import org.whispersystems.libsignal.util.ByteUtil;
26 | import org.whispersystems.libsignal.util.Pair;
27 |
28 | public class RootKey {
29 |
30 | private final HKDF kdf;
31 | private final byte[] key;
32 |
33 | public RootKey(HKDF kdf, byte[] key) {
34 | this.kdf = kdf;
35 | this.key = key;
36 | }
37 |
38 | public byte[] getKeyBytes() {
39 | return key;
40 | }
41 |
42 | public Pair createChain(ECPublicKey theirRatchetKey, ECKeyPair ourRatchetKey)
43 | throws InvalidKeyException
44 | {
45 | byte[] sharedSecret = Curve.calculateAgreement(theirRatchetKey, ourRatchetKey.getPrivateKey());
46 | byte[] derivedSecretBytes = kdf.deriveSecrets(sharedSecret, key, "WhisperRatchet".getBytes(), DerivedRootSecrets.SIZE);
47 | DerivedRootSecrets derivedSecrets = new DerivedRootSecrets(derivedSecretBytes);
48 |
49 | RootKey newRootKey = new RootKey(kdf, derivedSecrets.getRootKey());
50 | ChainKey newChainKey = new ChainKey(kdf, derivedSecrets.getChainKey(), 0);
51 |
52 | return new Pair<>(newRootKey, newChainKey);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/groups/state/SenderKeyStore.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2014-2015 Open Whisper Systems
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package org.whispersystems.libsignal.groups.state;
18 |
19 | import org.whispersystems.libsignal.groups.SenderKeyName;
20 |
21 | public interface SenderKeyStore {
22 |
23 | /**
24 | * Commit to storage the {@link org.whispersystems.libsignal.groups.state.SenderKeyRecord} for a
25 | * given (groupId + senderId + deviceId) tuple.
26 | *
27 | * @param senderKeyName the (groupId + senderId + deviceId) tuple.
28 | * @param record the current SenderKeyRecord for the specified senderKeyName.
29 | */
30 | public void storeSenderKey(SenderKeyName senderKeyName, SenderKeyRecord record);
31 |
32 | /**
33 | * Returns a copy of the {@link org.whispersystems.libsignal.groups.state.SenderKeyRecord}
34 | * corresponding to the (groupId + senderId + deviceId) tuple, or a new SenderKeyRecord if
35 | * one does not currently exist.
36 | *
37 | * It is important that implementations return a copy of the current durable information. The
38 | * returned SenderKeyRecord may be modified, but those changes should not have an effect on the
39 | * durable session state (what is returned by subsequent calls to this method) without the
40 | * store method being called here first.
41 | *
42 | * @param senderKeyName The (groupId + senderId + deviceId) tuple.
43 | * @return a copy of the SenderKeyRecord corresponding to the (groupId + senderId + deviceId tuple, or
44 | * a new SenderKeyRecord if one does not currently exist.
45 | */
46 |
47 | public SenderKeyRecord loadSenderKey(SenderKeyName senderKeyName);
48 | }
49 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/state/SignedPreKeyRecord.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libsignal.state;
2 |
3 | import com.google.protobuf.ByteString;
4 |
5 | import org.whispersystems.libsignal.InvalidKeyException;
6 | import org.whispersystems.libsignal.ecc.Curve;
7 | import org.whispersystems.libsignal.ecc.ECKeyPair;
8 | import org.whispersystems.libsignal.ecc.ECPrivateKey;
9 | import org.whispersystems.libsignal.ecc.ECPublicKey;
10 |
11 | import java.io.IOException;
12 |
13 | import static org.whispersystems.libsignal.state.StorageProtos.SignedPreKeyRecordStructure;
14 |
15 | public class SignedPreKeyRecord {
16 |
17 | private SignedPreKeyRecordStructure structure;
18 |
19 | public SignedPreKeyRecord(int id, long timestamp, ECKeyPair keyPair, byte[] signature) {
20 | this.structure = SignedPreKeyRecordStructure.newBuilder()
21 | .setId(id)
22 | .setPublicKey(ByteString.copyFrom(keyPair.getPublicKey()
23 | .serialize()))
24 | .setPrivateKey(ByteString.copyFrom(keyPair.getPrivateKey()
25 | .serialize()))
26 | .setSignature(ByteString.copyFrom(signature))
27 | .setTimestamp(timestamp)
28 | .build();
29 | }
30 |
31 | public SignedPreKeyRecord(byte[] serialized) throws IOException {
32 | this.structure = SignedPreKeyRecordStructure.parseFrom(serialized);
33 | }
34 |
35 | public int getId() {
36 | return this.structure.getId();
37 | }
38 |
39 | public long getTimestamp() {
40 | return this.structure.getTimestamp();
41 | }
42 |
43 | public ECKeyPair getKeyPair() {
44 | try {
45 | ECPublicKey publicKey = Curve.decodePoint(this.structure.getPublicKey().toByteArray(), 0);
46 | ECPrivateKey privateKey = Curve.decodePrivatePoint(this.structure.getPrivateKey().toByteArray());
47 |
48 | return new ECKeyPair(publicKey, privateKey);
49 | } catch (InvalidKeyException e) {
50 | throw new AssertionError(e);
51 | }
52 | }
53 |
54 | public byte[] getSignature() {
55 | return this.structure.getSignature().toByteArray();
56 | }
57 |
58 | public byte[] serialize() {
59 | return this.structure.toByteArray();
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/IdentityKeyPair.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2013 Open Whisper Systems
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package org.whispersystems.libsignal;
18 |
19 | import com.google.protobuf.ByteString;
20 | import com.google.protobuf.InvalidProtocolBufferException;
21 |
22 | import org.whispersystems.libsignal.ecc.Curve;
23 | import org.whispersystems.libsignal.ecc.ECPrivateKey;
24 |
25 | import static org.whispersystems.libsignal.state.StorageProtos.IdentityKeyPairStructure;
26 |
27 | /**
28 | * Holder for public and private identity key pair.
29 | *
30 | * @author Moxie Marlinspike
31 | */
32 | public class IdentityKeyPair {
33 |
34 | private final IdentityKey publicKey;
35 | private final ECPrivateKey privateKey;
36 |
37 | public IdentityKeyPair(IdentityKey publicKey, ECPrivateKey privateKey) {
38 | this.publicKey = publicKey;
39 | this.privateKey = privateKey;
40 | }
41 |
42 | public IdentityKeyPair(byte[] serialized) throws InvalidKeyException {
43 | try {
44 | IdentityKeyPairStructure structure = IdentityKeyPairStructure.parseFrom(serialized);
45 | this.publicKey = new IdentityKey(structure.getPublicKey().toByteArray(), 0);
46 | this.privateKey = Curve.decodePrivatePoint(structure.getPrivateKey().toByteArray());
47 | } catch (InvalidProtocolBufferException e) {
48 | throw new InvalidKeyException(e);
49 | }
50 | }
51 |
52 | public IdentityKey getPublicKey() {
53 | return publicKey;
54 | }
55 |
56 | public ECPrivateKey getPrivateKey() {
57 | return privateKey;
58 | }
59 |
60 | public byte[] serialize() {
61 | return IdentityKeyPairStructure.newBuilder()
62 | .setPublicKey(ByteString.copyFrom(publicKey.serialize()))
63 | .setPrivateKey(ByteString.copyFrom(privateKey.serialize()))
64 | .build().toByteArray();
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/util/Hex.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2014 Open Whisper Systems
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package org.whispersystems.libsignal.util;
18 |
19 | import java.io.IOException;
20 |
21 | /**
22 | * Utility for generating hex dumps.
23 | */
24 | public class Hex {
25 |
26 | private final static char[] HEX_DIGITS = {
27 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
28 | };
29 |
30 | public static String toString(byte[] bytes) {
31 | return toString(bytes, 0, bytes.length);
32 | }
33 |
34 | public static String toString(byte[] bytes, int offset, int length) {
35 | StringBuffer buf = new StringBuffer();
36 | for (int i = 0; i < length; i++) {
37 | appendHexChar(buf, bytes[offset + i]);
38 | buf.append(", ");
39 | }
40 | return buf.toString();
41 | }
42 |
43 | public static String toStringCondensed(byte[] bytes) {
44 | StringBuffer buf = new StringBuffer();
45 | for (int i=0;i> 1];
60 |
61 | for (int i = 0, j = 0; j < len; i++) {
62 | int f = Character.digit(data[j], 16) << 4;
63 | j++;
64 | f = f | Character.digit(data[j], 16);
65 | j++;
66 | out[i] = (byte) (f & 0xFF);
67 | }
68 |
69 | return out;
70 | }
71 |
72 | private static void appendHexChar(StringBuffer buf, int b) {
73 | buf.append("(byte)0x");
74 | buf.append(HEX_DIGITS[(b >> 4) & 0xf]);
75 | buf.append(HEX_DIGITS[b & 0xf]);
76 | }
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/util/guava/Function.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2007 The Guava Authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.whispersystems.libsignal.util.guava;
18 |
19 |
20 |
21 | /**
22 | * Determines an output value based on an input value.
23 | *
24 | *
See the Guava User Guide article on the use of {@code
26 | * Function}.
27 | *
28 | * @author Kevin Bourrillion
29 | * @since 2.0 (imported from Google Collections Library)
30 | */
31 |
32 | public interface Function {
33 | /**
34 | * Returns the result of applying this function to {@code input}. This method is generally
35 | * expected, but not absolutely required, to have the following properties:
36 | *
37 | *
38 | *
Its execution does not cause any observable side effects.
39 | *
The computation is consistent with equals; that is, {@link Objects#equal
40 | * Objects.equal}{@code (a, b)} implies that {@code Objects.equal(function.apply(a),
41 | * function.apply(b))}.
42 | *
43 | *
44 | * @throws NullPointerException if {@code input} is null and this function does not accept null
45 | * arguments
46 | */
47 | T apply(F input);
48 |
49 | /**
50 | * Indicates whether another object is equal to this function.
51 | *
52 | *
Most implementations will have no reason to override the behavior of {@link Object#equals}.
53 | * However, an implementation may also choose to return {@code true} whenever {@code object} is a
54 | * {@link Function} that it considers interchangeable with this one. "Interchangeable"
55 | * typically means that {@code Objects.equal(this.apply(f), that.apply(f))} is true for all
56 | * {@code f} of type {@code F}. Note that a {@code false} result from this method does not imply
57 | * that the functions are known not to be interchangeable.
58 | */
59 | @Override
60 | boolean equals(Object object);
61 | }
62 |
--------------------------------------------------------------------------------
/java/src/main/java/org/whispersystems/libsignal/util/guava/Absent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2011 The Guava Authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.whispersystems.libsignal.util.guava;
18 |
19 | import static org.whispersystems.libsignal.util.guava.Preconditions.checkNotNull;
20 |
21 |
22 |
23 | import java.util.Collections;
24 | import java.util.Set;
25 |
26 |
27 | /**
28 | * Implementation of an {@link Optional} not containing a reference.
29 | */
30 |
31 | final class Absent extends Optional