├── .gitignore
├── README.md
├── libs
└── com
│ └── ponderingpanda
│ └── protobuf
│ └── protobuf-mobile
│ ├── 1.0
│ ├── protobuf-mobile-1.0.jar
│ └── protobuf-mobile-1.0.pom
│ └── maven-metadata-local.xml
├── pom.xml
├── protobuf
├── LocalStorageProtocol.proto
├── Makefile
└── WhisperTextProtocol.proto
└── src
├── main
└── java
│ └── org
│ └── whispersystems
│ └── libaxolotl
│ ├── AxolotlAddress.java
│ ├── DecryptionCallback.java
│ ├── DuplicateMessageException.java
│ ├── IdentityKey.java
│ ├── IdentityKeyPair.java
│ ├── InvalidKeyException.java
│ ├── InvalidKeyIdException.java
│ ├── InvalidMacException.java
│ ├── InvalidMessageException.java
│ ├── InvalidVersionException.java
│ ├── LegacyMessageException.java
│ ├── NoSessionException.java
│ ├── SessionBuilder.java
│ ├── SessionCipher.java
│ ├── StaleKeyExchangeException.java
│ ├── UntrustedIdentityException.java
│ ├── ecc
│ ├── Curve.java
│ ├── DjbECPrivateKey.java
│ ├── DjbECPublicKey.java
│ ├── ECKeyPair.java
│ ├── ECPrivateKey.java
│ └── ECPublicKey.java
│ ├── groups
│ ├── GroupCipher.java
│ ├── GroupSessionBuilder.java
│ ├── SenderKeyName.java
│ ├── ratchet
│ │ ├── SenderChainKey.java
│ │ └── SenderMessageKey.java
│ └── state
│ │ ├── SenderKeyRecord.java
│ │ ├── SenderKeyState.java
│ │ └── SenderKeyStore.java
│ ├── j2me
│ ├── Arrays.java
│ ├── AssertionError.java
│ ├── BigInteger.java
│ ├── MessageDigest.java
│ ├── NestedException.java
│ ├── ParseException.java
│ └── jce
│ │ ├── BCJmeSecurityProvider.java
│ │ ├── JmeSecurity.java
│ │ ├── JmeSecurityProvider.java
│ │ ├── ciphers
│ │ ├── BlockCipher.java
│ │ ├── BouncyCBCBlockCipher.java
│ │ └── BouncyCTRBlockCipher.java
│ │ └── mac
│ │ ├── BouncyMacSha256.java
│ │ └── Mac.java
│ ├── kdf
│ ├── DerivedMessageSecrets.java
│ ├── DerivedRootSecrets.java
│ ├── HKDF.java
│ ├── HKDFv2.java
│ └── HKDFv3.java
│ ├── logging
│ ├── AxolotlLogger.java
│ ├── AxolotlLoggerProvider.java
│ └── Log.java
│ ├── protocol
│ ├── CiphertextMessage.java
│ ├── KeyExchangeMessage.java
│ ├── PreKeyWhisperMessage.java
│ ├── SenderKeyDistributionMessage.java
│ ├── SenderKeyMessage.java
│ ├── WhisperMessage.java
│ └── protos
│ │ ├── KeyExchangeMessage.java
│ │ ├── PreKeyWhisperMessage.java
│ │ ├── SenderKeyDistributionMessage.java
│ │ ├── SenderKeyMessage.java
│ │ └── WhisperMessage.java
│ ├── ratchet
│ ├── AliceAxolotlParameters.java
│ ├── BobAxolotlParameters.java
│ ├── ChainKey.java
│ ├── MessageKeys.java
│ ├── RatchetingSession.java
│ ├── RootKey.java
│ └── SymmetricAxolotlParameters.java
│ ├── state
│ ├── AxolotlStore.java
│ ├── IdentityKeyStore.java
│ ├── PreKeyBundle.java
│ ├── PreKeyRecord.java
│ ├── PreKeyStore.java
│ ├── SessionRecord.java
│ ├── SessionState.java
│ ├── SessionStore.java
│ ├── SignedPreKeyRecord.java
│ ├── SignedPreKeyStore.java
│ └── protos
│ │ ├── IdentityKeyPairStructure.java
│ │ ├── PreKeyRecordStructure.java
│ │ ├── RecordStructure.java
│ │ ├── SenderKeyRecordStructure.java
│ │ ├── SenderKeyStateStructure.java
│ │ ├── SessionStructure.java
│ │ └── SignedPreKeyRecordStructure.java
│ └── util
│ ├── ByteUtil.java
│ ├── Hex.java
│ ├── KeyHelper.java
│ ├── Medium.java
│ ├── Pair.java
│ └── guava
│ ├── Absent.java
│ ├── Optional.java
│ ├── Preconditions.java
│ ├── Present.java
│ └── Supplier.java
└── test
└── java
└── org
└── whispersystems
└── libaxolotl
├── AxolotlBaseTestCase.java
├── InMemoryAxolotlStore.java
├── InMemoryIdentityKeyStore.java
├── InMemoryPreKeyStore.java
├── InMemorySessionStore.java
├── InMemorySignedPreKeyStore.java
├── SessionBuilderTest.java
├── SessionCipherTest.java
├── SimultaneousInitiateTest.java
├── ecc
└── Curve25519Test.java
├── groups
├── GroupCipherTest.java
└── InMemorySenderKeyStore.java
├── j2me
├── Collections.java
└── FakeSecureRandomProvider.java
├── kdf
└── HKDFTest.java
└── ratchet
├── ChainKeyTest.java
├── RatchetingSessionTest.java
└── RootKeyTest.java
/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 | /obj
3 | *.iml
4 | .gradle
5 | .idea
6 | gradle.properties
7 | local.properties
8 | target/
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # In Progress
3 |
4 |
--------------------------------------------------------------------------------
/libs/com/ponderingpanda/protobuf/protobuf-mobile/1.0/protobuf-mobile-1.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/signalapp/libaxolotl-j2me/8842511ee123c6ee6568f9bd098ecab32ab01f16/libs/com/ponderingpanda/protobuf/protobuf-mobile/1.0/protobuf-mobile-1.0.jar
--------------------------------------------------------------------------------
/libs/com/ponderingpanda/protobuf/protobuf-mobile/1.0/protobuf-mobile-1.0.pom:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 | com.ponderingpanda.protobuf
6 | protobuf-mobile
7 | 1.0
8 | POM was created from install:install-file
9 |
10 |
--------------------------------------------------------------------------------
/libs/com/ponderingpanda/protobuf/protobuf-mobile/maven-metadata-local.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | com.ponderingpanda.protobuf
4 | protobuf-mobile
5 |
6 | 1.0
7 |
8 | 1.0
9 |
10 | 20150209194159
11 |
12 |
13 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | 3.0.0
8 |
9 |
10 | org.whispersystems
11 | axolotl-j2me
12 | 0.2.0
13 |
14 | axolotl-j2me
15 | A J2ME compatible Axolotl impolementation
16 | https://github.com/WhisperSystems/libaxolotl-j2me
17 |
18 |
19 |
20 | GPLv3
21 | https://www.gnu.org/licenses/gpl-3.0.html
22 | repo
23 |
24 |
25 |
26 |
27 |
28 | Moxie Marlinspike
29 |
30 |
31 |
32 |
33 | https://github.com/WhisperSystems/libaxolotl-j2me
34 | scm:git:https://github.com/WhisperSystems/libaxolotl-j2me.git
35 | scm:git:https://github.com/WhisperSystems/libaxolotl-j2me.git
36 |
37 |
38 |
39 |
40 | libs
41 | file://${basedir}/libs
42 |
43 |
44 | central
45 | Maven Repository Switchboard
46 | default
47 | http://repo1.maven.org/maven2
48 |
49 |
50 |
51 |
52 |
53 | com.google.protobuf
54 | protobuf-java
55 | 2.5.0
56 |
57 |
58 | org.whispersystems
59 | curve25519-j2me
60 | 0.2.3
61 |
62 |
63 | org.bouncycastle
64 | bcprov-jdk12
65 | 130
66 |
67 |
68 | com.ponderingpanda.protobuf
69 | protobuf-mobile
70 | 1.0
71 |
72 |
73 | junit
74 | junit
75 | 3.7
76 |
77 |
78 |
79 |
80 |
81 |
82 | org.apache.maven.plugins
83 | maven-compiler-plugin
84 |
85 | 1.2
86 | 1.2
87 |
88 |
89 |
90 | org.apache.maven.plugins
91 | maven-source-plugin
92 | 2.2.1
93 |
94 |
95 | attach-sources
96 |
97 | jar
98 |
99 |
100 |
101 |
102 |
103 | org.apache.maven.plugins
104 | maven-jar-plugin
105 | 2.4
106 |
107 |
108 |
109 | true
110 |
111 |
112 |
113 |
114 |
115 | org.apache.maven.plugins
116 | maven-gpg-plugin
117 |
118 |
119 | sign-artifacts
120 | verify
121 |
122 | sign
123 |
124 |
125 | 101BFC88
126 |
127 |
128 |
129 |
130 |
131 | org.apache.maven.plugins
132 | maven-javadoc-plugin
133 | 2.8.1
134 |
135 | -Xdoclint:none
136 |
137 |
138 |
139 | attach-javadocs
140 |
141 | jar
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 | ossrh
152 | https://oss.sonatype.org/content/repositories/snapshots
153 |
154 |
155 | ossrh
156 | https://oss.sonatype.org/service/local/staging/deploy/maven2/
157 |
158 |
159 |
160 |
161 |
162 |
--------------------------------------------------------------------------------
/protobuf/LocalStorageProtocol.proto:
--------------------------------------------------------------------------------
1 | package textsecure;
2 |
3 | option java_package = "org.whispersystems.libaxolotl.state.protos";
4 | option java_outer_classname = "StorageProtos";
5 |
6 | message SessionStructure {
7 | message Chain {
8 | optional bytes senderRatchetKey = 1;
9 | optional bytes senderRatchetKeyPrivate = 2;
10 |
11 | message ChainKey {
12 | optional uint32 index = 1;
13 | optional bytes key = 2;
14 | }
15 |
16 | optional ChainKey chainKey = 3;
17 |
18 | message MessageKey {
19 | optional uint32 index = 1;
20 | optional bytes cipherKey = 2;
21 | optional bytes macKey = 3;
22 | optional bytes iv = 4;
23 | }
24 |
25 | repeated MessageKey messageKeys = 4;
26 | }
27 |
28 | message PendingKeyExchange {
29 | optional uint32 sequence = 1;
30 | optional bytes localBaseKey = 2;
31 | optional bytes localBaseKeyPrivate = 3;
32 | optional bytes localRatchetKey = 4;
33 | optional bytes localRatchetKeyPrivate = 5;
34 | optional bytes localIdentityKey = 7;
35 | optional bytes localIdentityKeyPrivate = 8;
36 | }
37 |
38 | message PendingPreKey {
39 | optional uint32 preKeyId = 1;
40 | optional int32 signedPreKeyId = 3;
41 | optional bytes baseKey = 2;
42 | }
43 |
44 | optional uint32 sessionVersion = 1;
45 | optional bytes localIdentityPublic = 2;
46 | optional bytes remoteIdentityPublic = 3;
47 |
48 | optional bytes rootKey = 4;
49 | optional uint32 previousCounter = 5;
50 |
51 | optional Chain senderChain = 6;
52 | repeated Chain receiverChains = 7;
53 |
54 | optional PendingKeyExchange pendingKeyExchange = 8;
55 | optional PendingPreKey pendingPreKey = 9;
56 |
57 | optional uint32 remoteRegistrationId = 10;
58 | optional uint32 localRegistrationId = 11;
59 |
60 | optional bool needsRefresh = 12;
61 | optional bytes aliceBaseKey = 13;
62 | }
63 |
64 | message RecordStructure {
65 | optional SessionStructure currentSession = 1;
66 | repeated SessionStructure previousSessions = 2;
67 | }
68 |
69 | message PreKeyRecordStructure {
70 | optional uint32 id = 1;
71 | optional bytes publicKey = 2;
72 | optional bytes privateKey = 3;
73 | }
74 |
75 | message SignedPreKeyRecordStructure {
76 | optional uint32 id = 1;
77 | optional bytes publicKey = 2;
78 | optional bytes privateKey = 3;
79 | optional bytes signature = 4;
80 | optional fixed64 timestamp = 5;
81 | }
82 |
83 | message IdentityKeyPairStructure {
84 | optional bytes publicKey = 1;
85 | optional bytes privateKey = 2;
86 | }
87 |
88 | message SenderKeyStateStructure {
89 | message SenderChainKey {
90 | optional uint32 iteration = 1;
91 | optional bytes seed = 2;
92 | }
93 |
94 | message SenderMessageKey {
95 | optional uint32 iteration = 1;
96 | optional bytes seed = 2;
97 | }
98 |
99 | message SenderSigningKey {
100 | optional bytes public = 1;
101 | optional bytes private = 2;
102 | }
103 |
104 | optional uint32 senderKeyId = 1;
105 | optional SenderChainKey senderChainKey = 2;
106 | optional SenderSigningKey senderSigningKey = 3;
107 | repeated SenderMessageKey senderMessageKeys = 4;
108 | }
109 |
110 | message SenderKeyRecordStructure {
111 | repeated SenderKeyStateStructure senderKeyStates = 1;
112 | }
--------------------------------------------------------------------------------
/protobuf/Makefile:
--------------------------------------------------------------------------------
1 |
2 | all:
3 | protoc --java_out=../src/main/java/ WhisperTextProtocol.proto LocalStorageProtocol.proto
4 |
--------------------------------------------------------------------------------
/protobuf/WhisperTextProtocol.proto:
--------------------------------------------------------------------------------
1 | package textsecure;
2 |
3 | option java_package = "org.whispersystems.libaxolotl.protocol.protos";
4 | option java_outer_classname = "WhisperProtos";
5 |
6 | message WhisperMessage {
7 | optional bytes ratchetKey = 1;
8 | optional uint32 counter = 2;
9 | optional uint32 previousCounter = 3;
10 | optional bytes ciphertext = 4;
11 | }
12 |
13 | message PreKeyWhisperMessage {
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 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/AxolotlAddress.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libaxolotl;
2 |
3 | public class AxolotlAddress {
4 |
5 | private final String name;
6 | private final int deviceId;
7 |
8 | public AxolotlAddress(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 AxolotlAddress)) return false;
30 |
31 | AxolotlAddress that = (AxolotlAddress)other;
32 | return this.name.equals(that.name) && this.deviceId == that.deviceId;
33 | }
34 |
35 | // @Override
36 | public int hashCode() {
37 | int hash = 7;
38 | hash = 31 * hash + deviceId;
39 | hash = 31 * hash + name.hashCode();
40 | return hash;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/DecryptionCallback.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libaxolotl;
2 |
3 | public interface DecryptionCallback {
4 | public void handlePlaintext(byte[] plaintext);
5 | }
6 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/DuplicateMessageException.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libaxolotl;
2 |
3 | public class DuplicateMessageException extends Exception {
4 | public DuplicateMessageException(String s) {
5 | super(s);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/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.libaxolotl;
18 |
19 |
20 | import org.whispersystems.libaxolotl.ecc.Curve;
21 | import org.whispersystems.libaxolotl.ecc.ECPublicKey;
22 | import org.whispersystems.libaxolotl.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 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/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.libaxolotl;
18 |
19 | import org.whispersystems.libaxolotl.ecc.Curve;
20 | import org.whispersystems.libaxolotl.ecc.ECPrivateKey;
21 | import org.whispersystems.libaxolotl.state.protos.IdentityKeyPairStructure;
22 |
23 |
24 | /**
25 | * Holder for public and private identity key pair.
26 | *
27 | * @author Moxie Marlinspike
28 | */
29 | public class IdentityKeyPair {
30 |
31 | private final IdentityKey publicKey;
32 | private final ECPrivateKey privateKey;
33 |
34 | public IdentityKeyPair(IdentityKey publicKey, ECPrivateKey privateKey) {
35 | this.publicKey = publicKey;
36 | this.privateKey = privateKey;
37 | }
38 |
39 | public IdentityKeyPair(byte[] serialized) throws InvalidKeyException {
40 | IdentityKeyPairStructure structure = IdentityKeyPairStructure.fromBytes(serialized);
41 | this.publicKey = new IdentityKey(structure.getPublickey(), 0);
42 | this.privateKey = Curve.decodePrivatePoint(structure.getPrivatekey());
43 | }
44 |
45 | public IdentityKey getPublicKey() {
46 | return publicKey;
47 | }
48 |
49 | public ECPrivateKey getPrivateKey() {
50 | return privateKey;
51 | }
52 |
53 | public byte[] serialize() {
54 | IdentityKeyPairStructure structure = new IdentityKeyPairStructure();
55 | structure.setPublickey(publicKey.serialize());
56 | structure.setPrivatekey(privateKey.serialize());
57 |
58 | return structure.toBytes();
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/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.libaxolotl;
18 |
19 | import org.whispersystems.libaxolotl.j2me.NestedException;
20 |
21 | public class InvalidKeyException extends NestedException {
22 |
23 | public InvalidKeyException() {}
24 |
25 | public InvalidKeyException(String detailMessage) {
26 | super(detailMessage);
27 | }
28 |
29 | public InvalidKeyException(Throwable throwable) {
30 | super(throwable);
31 | }
32 |
33 | public InvalidKeyException(String detailMessage, Throwable throwable) {
34 | super(detailMessage, throwable);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/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.libaxolotl;
18 |
19 | import org.whispersystems.libaxolotl.j2me.NestedException;
20 |
21 | public class InvalidKeyIdException extends NestedException {
22 | public InvalidKeyIdException(String detailMessage) {
23 | super(detailMessage);
24 | }
25 |
26 | public InvalidKeyIdException(Throwable throwable) {
27 | super(throwable);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/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.libaxolotl;
18 |
19 | import org.whispersystems.libaxolotl.j2me.NestedException;
20 |
21 | public class InvalidMacException extends NestedException {
22 |
23 | public InvalidMacException(String detailMessage) {
24 | super(detailMessage);
25 | }
26 |
27 | public InvalidMacException(Throwable throwable) {
28 | super(throwable);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/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.libaxolotl;
18 |
19 | import org.whispersystems.libaxolotl.j2me.NestedException;
20 |
21 | import java.util.Vector;
22 |
23 | public class InvalidMessageException extends NestedException {
24 |
25 | public InvalidMessageException() {}
26 |
27 | public InvalidMessageException(String detailMessage) {
28 | super(detailMessage);
29 | }
30 |
31 | public InvalidMessageException(Throwable throwable) {
32 | super(throwable);
33 | }
34 |
35 | public InvalidMessageException(String detailMessage, Throwable throwable) {
36 | super(detailMessage, throwable);
37 | }
38 |
39 | public InvalidMessageException(String detailMessage, Vector exceptions) {
40 | super(detailMessage, (Throwable)exceptions.elementAt(0));
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/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.libaxolotl;
18 |
19 | public class InvalidVersionException extends Exception {
20 | public InvalidVersionException(String detailMessage) {
21 | super(detailMessage);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/LegacyMessageException.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libaxolotl;
2 |
3 | public class LegacyMessageException extends Exception {
4 | public LegacyMessageException(String s) {
5 | super(s);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/NoSessionException.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libaxolotl;
2 |
3 | import org.whispersystems.libaxolotl.j2me.NestedException;
4 |
5 | public class NoSessionException extends NestedException {
6 | public NoSessionException(String s) {
7 | super(s);
8 | }
9 |
10 | public NoSessionException(Exception nested) {
11 | super(nested);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/StaleKeyExchangeException.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libaxolotl;
2 |
3 | public class StaleKeyExchangeException extends Throwable {
4 | }
5 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/UntrustedIdentityException.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libaxolotl;
2 |
3 | public class UntrustedIdentityException extends Exception {
4 | }
5 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/ecc/Curve.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.libaxolotl.ecc;
18 |
19 | import org.whispersystems.curve25519.Curve25519;
20 | import org.whispersystems.curve25519.Curve25519KeyPair;
21 | import org.whispersystems.curve25519.SecureRandomProvider;
22 | import org.whispersystems.libaxolotl.InvalidKeyException;
23 |
24 | public class Curve {
25 |
26 | public static final int DJB_TYPE = 0x05;
27 |
28 | public static boolean isNative() {
29 | return Curve25519.getInstance(Curve25519.J2ME).isNative();
30 | }
31 |
32 | public static ECKeyPair generateKeyPair(SecureRandomProvider secureRandom) {
33 | Curve25519KeyPair keyPair = Curve25519.getInstance(Curve25519.J2ME, secureRandom).generateKeyPair();
34 |
35 | return new ECKeyPair(new DjbECPublicKey(keyPair.getPublicKey()),
36 | new DjbECPrivateKey(keyPair.getPrivateKey()));
37 | }
38 |
39 | public static ECPublicKey decodePoint(byte[] bytes, int offset)
40 | throws InvalidKeyException
41 | {
42 | int type = bytes[offset] & 0xFF;
43 |
44 | switch (type) {
45 | case Curve.DJB_TYPE:
46 | byte[] keyBytes = new byte[32];
47 | System.arraycopy(bytes, offset+1, keyBytes, 0, keyBytes.length);
48 | return new DjbECPublicKey(keyBytes);
49 | default:
50 | throw new InvalidKeyException("Bad key type: " + type);
51 | }
52 | }
53 |
54 | public static ECPrivateKey decodePrivatePoint(byte[] bytes) {
55 | return new DjbECPrivateKey(bytes);
56 | }
57 |
58 | public static byte[] calculateAgreement(ECPublicKey publicKey, ECPrivateKey privateKey)
59 | throws InvalidKeyException
60 | {
61 | if (publicKey.getType() != privateKey.getType()) {
62 | throw new InvalidKeyException("Public and private keys must be of the same type!");
63 | }
64 |
65 | if (publicKey.getType() == DJB_TYPE) {
66 | return Curve25519.getInstance(Curve25519.J2ME)
67 | .calculateAgreement(((DjbECPublicKey) publicKey).getPublicKey(),
68 | ((DjbECPrivateKey) privateKey).getPrivateKey());
69 | } else {
70 | throw new InvalidKeyException("Unknown type: " + publicKey.getType());
71 | }
72 | }
73 |
74 | public static boolean verifySignature(ECPublicKey signingKey, byte[] message, byte[] signature)
75 | throws InvalidKeyException
76 | {
77 | if (signingKey.getType() == DJB_TYPE) {
78 | return Curve25519.getInstance(Curve25519.J2ME)
79 | .verifySignature(((DjbECPublicKey) signingKey).getPublicKey(), message, signature);
80 | } else {
81 | throw new InvalidKeyException("Unknown type: " + signingKey.getType());
82 | }
83 | }
84 |
85 | public static byte[] calculateSignature(SecureRandomProvider secureRandom,
86 | ECPrivateKey signingKey, byte[] message)
87 | throws InvalidKeyException
88 | {
89 | if (signingKey.getType() == DJB_TYPE) {
90 | return Curve25519.getInstance(Curve25519.J2ME, secureRandom)
91 | .calculateSignature(((DjbECPrivateKey) signingKey).getPrivateKey(), message);
92 | } else {
93 | throw new InvalidKeyException("Unknown type: " + signingKey.getType());
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/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.libaxolotl.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 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/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.libaxolotl.ecc;
19 |
20 | import org.whispersystems.libaxolotl.j2me.Arrays;
21 | import org.whispersystems.libaxolotl.j2me.BigInteger;
22 | import org.whispersystems.libaxolotl.util.ByteUtil;
23 |
24 | public class DjbECPublicKey implements ECPublicKey {
25 |
26 | private final byte[] publicKey;
27 |
28 | DjbECPublicKey(byte[] publicKey) {
29 | this.publicKey = publicKey;
30 | }
31 |
32 | // @Override
33 | public byte[] serialize() {
34 | byte[] type = {Curve.DJB_TYPE};
35 | return ByteUtil.combine(type, publicKey);
36 | }
37 |
38 | // @Override
39 | public int getType() {
40 | return Curve.DJB_TYPE;
41 | }
42 |
43 | // @Override
44 | public boolean equals(Object other) {
45 | if (other == null) return false;
46 | if (!(other instanceof DjbECPublicKey)) return false;
47 |
48 | DjbECPublicKey that = (DjbECPublicKey)other;
49 | return Arrays.equals(this.publicKey, that.publicKey);
50 | }
51 |
52 | // @Override
53 | public int hashCode() {
54 | return Arrays.hashCode(publicKey);
55 | }
56 |
57 | // @Override
58 | public int compareTo(ECPublicKey another) {
59 | return new BigInteger(publicKey).compareTo(new BigInteger(((DjbECPublicKey)another).publicKey));
60 | }
61 |
62 | public byte[] getPublicKey() {
63 | return publicKey;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/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.libaxolotl.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 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/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.libaxolotl.ecc;
19 |
20 | public interface ECPrivateKey {
21 | public byte[] serialize();
22 | public int getType();
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/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.libaxolotl.ecc;
19 |
20 | public interface ECPublicKey {
21 |
22 | public static final int KEY_SIZE = 33;
23 |
24 | public byte[] serialize();
25 |
26 | public int getType();
27 |
28 | public int compareTo(ECPublicKey other);
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/groups/GroupSessionBuilder.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.libaxolotl.groups;
19 |
20 | import org.whispersystems.curve25519.SecureRandomProvider;
21 | import org.whispersystems.libaxolotl.InvalidKeyException;
22 | import org.whispersystems.libaxolotl.InvalidKeyIdException;
23 | import org.whispersystems.libaxolotl.groups.state.SenderKeyRecord;
24 | import org.whispersystems.libaxolotl.groups.state.SenderKeyState;
25 | import org.whispersystems.libaxolotl.groups.state.SenderKeyStore;
26 | import org.whispersystems.libaxolotl.j2me.AssertionError;
27 | import org.whispersystems.libaxolotl.protocol.SenderKeyDistributionMessage;
28 | import org.whispersystems.libaxolotl.util.KeyHelper;
29 |
30 | /**
31 | * GroupSessionBuilder is responsible for setting up group SenderKey encrypted sessions.
32 | *
33 | * Once a session has been established, {@link org.whispersystems.libaxolotl.groups.GroupCipher}
34 | * can be used to encrypt/decrypt messages in that session.
35 | *
36 | * The built sessions are unidirectional: they can be used either for sending or for receiving,
37 | * but not both.
38 | *
39 | * Sessions are constructed per (groupId senderId deviceId) tuple. Remote logical users
40 | * are identified by their senderId, and each logical recipientId can have multiple physical
41 | * devices.
42 | *
43 | * @author Moxie Marlinspike
44 | */
45 | public class GroupSessionBuilder {
46 |
47 | private final SenderKeyStore senderKeyStore;
48 |
49 | public GroupSessionBuilder(SenderKeyStore senderKeyStore) {
50 | this.senderKeyStore = senderKeyStore;
51 | }
52 |
53 | /**
54 | * Construct a group session for receiving messages from senderKeyName.
55 | *
56 | * @param senderKeyName The (groupId, senderId, deviceId) tuple associated with the SenderKeyDistributionMessage.
57 | * @param senderKeyDistributionMessage A received SenderKeyDistributionMessage.
58 | */
59 | public void process(SenderKeyName senderKeyName, SenderKeyDistributionMessage senderKeyDistributionMessage) {
60 | synchronized (GroupCipher.LOCK) {
61 | SenderKeyRecord senderKeyRecord = senderKeyStore.loadSenderKey(senderKeyName);
62 | senderKeyRecord.addSenderKeyState(senderKeyDistributionMessage.getId(),
63 | senderKeyDistributionMessage.getIteration(),
64 | senderKeyDistributionMessage.getChainKey(),
65 | senderKeyDistributionMessage.getSignatureKey());
66 | senderKeyStore.storeSenderKey(senderKeyName, senderKeyRecord);
67 | }
68 | }
69 |
70 | /**
71 | * Construct a group session for sending messages.
72 | *
73 | * @param senderKeyName The (groupId, senderId, deviceId) tuple. In this case, 'senderId' should be the caller.
74 | * @return A SenderKeyDistributionMessage that is individually distributed to each member of the group.
75 | */
76 | public SenderKeyDistributionMessage create(SenderKeyName senderKeyName, SecureRandomProvider secureRandomProvider) {
77 | synchronized (GroupCipher.LOCK) {
78 |
79 | try {
80 | SenderKeyRecord senderKeyRecord = senderKeyStore.loadSenderKey(senderKeyName);
81 |
82 | if (senderKeyRecord.isEmpty()) {
83 | senderKeyRecord.setSenderKeyState(KeyHelper.generateSenderKeyId(secureRandomProvider),
84 | 0,
85 | KeyHelper.generateSenderKey(secureRandomProvider),
86 | KeyHelper.generateSenderSigningKey(secureRandomProvider));
87 | senderKeyStore.storeSenderKey(senderKeyName, senderKeyRecord);
88 | }
89 |
90 | SenderKeyState state = senderKeyRecord.getSenderKeyState();
91 |
92 | return new SenderKeyDistributionMessage(state.getKeyId(),
93 | state.getSenderChainKey().getIteration(),
94 | state.getSenderChainKey().getSeed(),
95 | state.getSigningKeyPublic());
96 | } catch (InvalidKeyIdException e) {
97 | throw new AssertionError(e);
98 | } catch (InvalidKeyException e) {
99 | throw new AssertionError(e);
100 | }
101 | }
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/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.libaxolotl.groups;
18 |
19 | import org.whispersystems.libaxolotl.AxolotlAddress;
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 AxolotlAddress sender;
28 |
29 | public SenderKeyName(String groupId, AxolotlAddress sender) {
30 | this.groupId = groupId;
31 | this.sender = sender;
32 | }
33 |
34 | public String getGroupId() {
35 | return groupId;
36 | }
37 |
38 | public AxolotlAddress getSender() {
39 | return sender;
40 | }
41 |
42 | public String serialize() {
43 | return groupId + "::" + sender.getName() + "::" + String.valueOf(sender.getDeviceId());
44 | }
45 |
46 | public boolean equals(Object other) {
47 | if (other == null) return false;
48 | if (!(other instanceof SenderKeyName)) return false;
49 |
50 | SenderKeyName that = (SenderKeyName)other;
51 |
52 | return
53 | this.groupId.equals(that.groupId) &&
54 | this.sender.equals(that.sender);
55 | }
56 |
57 | public int hashCode() {
58 | int hash = 7;
59 | hash = 31 * hash + groupId.hashCode();
60 | hash = 31 * hash + sender.hashCode();
61 | return hash;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/groups/ratchet/SenderChainKey.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.libaxolotl.groups.ratchet;
18 |
19 | import org.whispersystems.libaxolotl.j2me.jce.JmeSecurity;
20 | import org.whispersystems.libaxolotl.j2me.jce.mac.Mac;
21 |
22 | /**
23 | * Each SenderKey is a "chain" of keys, each derived from the previous.
24 | *
25 | * At any given point in time, the state of a SenderKey can be represented
26 | * as the current chain key value, along with its iteration count. From there,
27 | * subsequent iterations can be derived, as well as individual message keys from
28 | * each chain key.
29 | *
30 | * @author Moxie Marlinspike
31 | */
32 | public class SenderChainKey {
33 |
34 | private static final byte[] MESSAGE_KEY_SEED = {0x01};
35 | private static final byte[] CHAIN_KEY_SEED = {0x02};
36 |
37 | private final int iteration;
38 | private final byte[] chainKey;
39 |
40 | public SenderChainKey(int iteration, byte[] chainKey) {
41 | this.iteration = iteration;
42 | this.chainKey = chainKey;
43 | }
44 |
45 | public int getIteration() {
46 | return iteration;
47 | }
48 |
49 | public SenderMessageKey getSenderMessageKey() {
50 | return new SenderMessageKey(iteration, getDerivative(MESSAGE_KEY_SEED, chainKey));
51 | }
52 |
53 | public SenderChainKey getNext() {
54 | return new SenderChainKey(iteration + 1, getDerivative(CHAIN_KEY_SEED, chainKey));
55 | }
56 |
57 | public byte[] getSeed() {
58 | return chainKey;
59 | }
60 |
61 | private byte[] getDerivative(byte[] seed, byte[] key) {
62 | Mac mac = JmeSecurity.getProvider().createMacSha256(key);
63 | byte[] output = new byte[32];
64 |
65 | mac.update(seed, 0, seed.length);
66 | mac.doFinal(output, 0);
67 |
68 | return output;
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/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 | package org.whispersystems.libaxolotl.groups.ratchet;
18 |
19 | import org.whispersystems.libaxolotl.kdf.HKDFv3;
20 | import org.whispersystems.libaxolotl.util.ByteUtil;
21 |
22 | /**
23 | * The final symmetric material (IV and Cipher Key) used for encrypting
24 | * individual SenderKey messages.
25 | *
26 | * @author Moxie Marlinspike
27 | */
28 | public class SenderMessageKey {
29 |
30 | private final int iteration;
31 | private final byte[] iv;
32 | private final byte[] cipherKey;
33 | private final byte[] seed;
34 |
35 | public SenderMessageKey(int iteration, byte[] seed) {
36 | byte[] derivative = new HKDFv3().deriveSecrets(seed, "WhisperGroup".getBytes(), 48);
37 | byte[][] parts = ByteUtil.split(derivative, 16, 32);
38 |
39 | this.iteration = iteration;
40 | this.seed = seed;
41 | this.iv = parts[0];
42 | this.cipherKey = parts[1];
43 | }
44 |
45 | public int getIteration() {
46 | return iteration;
47 | }
48 |
49 | public byte[] getIv() {
50 | return iv;
51 | }
52 |
53 | public byte[] getCipherKey() {
54 | return cipherKey;
55 | }
56 |
57 | public byte[] getSeed() {
58 | return seed;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/groups/state/SenderKeyRecord.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.libaxolotl.groups.state;
18 |
19 | import org.whispersystems.libaxolotl.InvalidKeyIdException;
20 | import org.whispersystems.libaxolotl.ecc.ECKeyPair;
21 | import org.whispersystems.libaxolotl.ecc.ECPublicKey;
22 | import org.whispersystems.libaxolotl.state.protos.SenderKeyRecordStructure;
23 | import org.whispersystems.libaxolotl.state.protos.SenderKeyStateStructure;
24 |
25 | import java.io.IOException;
26 | import java.util.Vector;
27 |
28 | /**
29 | * A durable representation of a set of SenderKeyStates for a specific
30 | * SenderKeyName.
31 | *
32 | * @author Moxie Marlisnpike
33 | */
34 | public class SenderKeyRecord {
35 |
36 | // SenderKeyState
37 | private Vector senderKeyStates = new Vector();
38 |
39 | private static final int MAX_STATES = 5;
40 |
41 | public SenderKeyRecord() {}
42 |
43 | public SenderKeyRecord(byte[] serialized) throws IOException {
44 | SenderKeyRecordStructure senderKeyRecordStructure = SenderKeyRecordStructure.fromBytes(serialized);
45 | Vector senderKeyStates = senderKeyRecordStructure.getSenderkeystatesVector();
46 |
47 | for (int i=0;i MAX_STATES) {
78 | senderKeyStates.removeElementAt(senderKeyStates.size()-1);
79 | }
80 | }
81 |
82 | public void setSenderKeyState(int id, int iteration, byte[] chainKey, ECKeyPair signatureKey) {
83 | senderKeyStates.removeAllElements();
84 | senderKeyStates.addElement(new SenderKeyState(id, iteration, chainKey, signatureKey));
85 | }
86 |
87 | public byte[] serialize() {
88 | SenderKeyRecordStructure recordStructure = new SenderKeyRecordStructure();
89 |
90 | for (int i=0;i.
16 | */
17 | package org.whispersystems.libaxolotl.groups.state;
18 |
19 | import org.whispersystems.libaxolotl.groups.SenderKeyName;
20 |
21 | public interface SenderKeyStore {
22 | /**
23 | * Commit to storage the {@link org.whispersystems.libaxolotl.groups.state.SenderKeyRecord} for a
24 | * given (groupId + senderId + deviceId) tuple.
25 | *
26 | * @param senderKeyName the (groupId + senderId + deviceId) tuple.
27 | * @param record the current SenderKeyRecord for the specified senderKeyName.
28 | */
29 | public void storeSenderKey(SenderKeyName senderKeyName, SenderKeyRecord record);
30 |
31 | /**
32 | * Returns a copy of the {@link org.whispersystems.libaxolotl.groups.state.SenderKeyRecord}
33 | * corresponding to the (groupId + senderId + deviceId) tuple, or a new SenderKeyRecord if
34 | * one does not currently exist.
35 | *
36 | * It is important that implementations return a copy of the current durable information. The
37 | * returned SenderKeyRecord may be modified, but those changes should not have an effect on the
38 | * durable session state (what is returned by subsequent calls to this method) without the
39 | * store method being called here first.
40 | *
41 | * @param senderKeyName The (groupId + senderId + deviceId) tuple.
42 | * @return a copy of the SenderKeyRecord corresponding to the (groupId + senderId + deviceId tuple, or
43 | * a new SenderKeyRecord if one does not currently exist.
44 | */
45 |
46 | public SenderKeyRecord loadSenderKey(SenderKeyName senderKeyName);
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/j2me/Arrays.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libaxolotl.j2me;
2 |
3 | public class Arrays {
4 |
5 | public static boolean equals(byte[] a, byte[] a2) {
6 | if (a==a2)
7 | return true;
8 | if (a==null || a2==null)
9 | return false;
10 |
11 | int length = a.length;
12 | if (a2.length != length)
13 | return false;
14 |
15 | for (int i=0; i.
16 | */
17 |
18 | package org.whispersystems.libaxolotl.kdf;
19 |
20 | import org.bouncycastle.crypto.params.KeyParameter;
21 | import org.bouncycastle.crypto.params.ParametersWithIV;
22 | import org.whispersystems.libaxolotl.j2me.AssertionError;
23 | import org.whispersystems.libaxolotl.util.ByteUtil;
24 | import org.whispersystems.libaxolotl.j2me.ParseException;
25 |
26 | public class DerivedMessageSecrets {
27 |
28 | public static final int SIZE = 80;
29 | private static final int CIPHER_KEY_LENGTH = 32;
30 | private static final int MAC_KEY_LENGTH = 32;
31 | private static final int IV_LENGTH = 16;
32 |
33 | private final KeyParameter cipherKey;
34 | private final KeyParameter macKey;
35 | private final ParametersWithIV iv;
36 |
37 | public DerivedMessageSecrets(byte[] okm) {
38 | try {
39 | byte[][] keys = ByteUtil.split(okm, CIPHER_KEY_LENGTH, MAC_KEY_LENGTH, IV_LENGTH);
40 |
41 | this.cipherKey = new KeyParameter(keys[0], 0, keys[0].length);
42 | this.macKey = new KeyParameter(keys[1], 0, keys[1].length);
43 | this.iv = new ParametersWithIV(null, keys[2], 0, keys[2].length);
44 | } catch (ParseException e) {
45 | throw new AssertionError(e);
46 | }
47 | }
48 |
49 | public KeyParameter getCipherKey() {
50 | return cipherKey;
51 | }
52 |
53 | public KeyParameter getMacKey() {
54 | return macKey;
55 | }
56 |
57 | public ParametersWithIV getIv() {
58 | return iv;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/kdf/DerivedRootSecrets.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libaxolotl.kdf;
2 |
3 | import org.whispersystems.libaxolotl.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 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/kdf/HKDF.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.libaxolotl.kdf;
19 |
20 | import org.whispersystems.libaxolotl.j2me.AssertionError;
21 | import org.whispersystems.libaxolotl.j2me.jce.JmeSecurity;
22 | import org.whispersystems.libaxolotl.j2me.jce.mac.Mac;
23 |
24 | import java.io.ByteArrayOutputStream;
25 |
26 | public abstract class HKDF {
27 |
28 | private static final int HASH_OUTPUT_SIZE = 32;
29 |
30 | public static HKDF createFor(int messageVersion) {
31 | switch (messageVersion) {
32 | case 2: return new HKDFv2();
33 | case 3: return new HKDFv3();
34 | default: throw new AssertionError("Unknown version: " + messageVersion);
35 | }
36 | }
37 |
38 | public byte[] deriveSecrets(byte[] inputKeyMaterial, byte[] info, int outputLength) {
39 | byte[] salt = new byte[HASH_OUTPUT_SIZE];
40 | return deriveSecrets(inputKeyMaterial, salt, info, outputLength);
41 | }
42 |
43 | public byte[] deriveSecrets(byte[] inputKeyMaterial, byte[] salt, byte[] info, int outputLength) {
44 | byte[] prk = extract(salt, inputKeyMaterial);
45 | return expand(prk, info, outputLength);
46 | }
47 |
48 | private byte[] extract(byte[] salt, byte[] inputKeyMaterial) {
49 | Mac mac = JmeSecurity.getProvider().createMacSha256(salt);
50 | byte[] output = new byte[32];
51 |
52 | mac.update(inputKeyMaterial, 0, inputKeyMaterial.length);
53 | mac.doFinal(output, 0);
54 |
55 | return output;
56 | }
57 |
58 | private byte[] expand(byte[] prk, byte[] info, int outputSize) {
59 | int iterations = (int) Math.ceil((double) outputSize / (double) HASH_OUTPUT_SIZE);
60 | byte[] mixin = new byte[0];
61 | ByteArrayOutputStream results = new ByteArrayOutputStream();
62 | int remainingBytes = outputSize;
63 |
64 | for (int i= getIterationStartOffset();i.
16 | */
17 | package org.whispersystems.libaxolotl.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 | }
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/protocol/KeyExchangeMessage.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libaxolotl.protocol;
2 |
3 |
4 | import org.whispersystems.libaxolotl.IdentityKey;
5 | import org.whispersystems.libaxolotl.InvalidKeyException;
6 | import org.whispersystems.libaxolotl.InvalidMessageException;
7 | import org.whispersystems.libaxolotl.InvalidVersionException;
8 | import org.whispersystems.libaxolotl.LegacyMessageException;
9 | import org.whispersystems.libaxolotl.ecc.Curve;
10 | import org.whispersystems.libaxolotl.ecc.ECPublicKey;
11 | import org.whispersystems.libaxolotl.util.ByteUtil;
12 |
13 |
14 | public class KeyExchangeMessage {
15 |
16 | public static final int INITIATE_FLAG = 0x01;
17 | public static final int RESPONSE_FLAG = 0X02;
18 | public static final int SIMULTAENOUS_INITIATE_FLAG = 0x04;
19 |
20 | private final int version;
21 | private final int supportedVersion;
22 | private final int sequence;
23 | private final int flags;
24 |
25 | private final ECPublicKey baseKey;
26 | private final byte[] baseKeySignature;
27 | private final ECPublicKey ratchetKey;
28 | private final IdentityKey identityKey;
29 | private final byte[] serialized;
30 |
31 | public KeyExchangeMessage(int messageVersion, int sequence, int flags,
32 | ECPublicKey baseKey, byte[] baseKeySignature,
33 | ECPublicKey ratchetKey,
34 | IdentityKey identityKey)
35 | {
36 | this.supportedVersion = CiphertextMessage.CURRENT_VERSION;
37 | this.version = messageVersion;
38 | this.sequence = sequence;
39 | this.flags = flags;
40 | this.baseKey = baseKey;
41 | this.baseKeySignature = baseKeySignature;
42 | this.ratchetKey = ratchetKey;
43 | this.identityKey = identityKey;
44 |
45 | byte[] version = {ByteUtil.intsToByteHighAndLow(this.version, this.supportedVersion)};
46 |
47 | org.whispersystems.libaxolotl.protocol.protos.KeyExchangeMessage structure = new org.whispersystems.libaxolotl.protocol.protos.KeyExchangeMessage();
48 | structure.setId((sequence << 5) | flags);
49 | structure.setBasekey(baseKey.serialize());
50 | structure.setRatchetkey(ratchetKey.serialize());
51 | structure.setIdentitykey(identityKey.serialize());
52 |
53 | if (messageVersion >= 3) {
54 | structure.setBasekeysignature(baseKeySignature);
55 | }
56 |
57 | this.serialized = ByteUtil.combine(version, structure.toBytes());
58 | }
59 |
60 | public KeyExchangeMessage(byte[] serialized)
61 | throws InvalidMessageException, InvalidVersionException, LegacyMessageException
62 | {
63 | try {
64 | byte[][] parts = ByteUtil.split(serialized, 1, serialized.length - 1);
65 | this.version = ByteUtil.highBitsToInt(parts[0][0]);
66 | this.supportedVersion = ByteUtil.lowBitsToInt(parts[0][0]);
67 |
68 | if (this.version <= CiphertextMessage.UNSUPPORTED_VERSION) {
69 | throw new LegacyMessageException("Unsupported legacy version: " + this.version);
70 | }
71 |
72 | if (this.version > CiphertextMessage.CURRENT_VERSION) {
73 | throw new InvalidVersionException("Unknown version: " + this.version);
74 | }
75 |
76 | org.whispersystems.libaxolotl.protocol.protos.KeyExchangeMessage message =
77 | org.whispersystems.libaxolotl.protocol.protos.KeyExchangeMessage.fromBytes(parts[1]);
78 |
79 | if (!message.hasId() || !message.hasBasekey() ||
80 | !message.hasRatchetkey() || !message.hasIdentitykey() ||
81 | (this.version >=3 && message.getBasekeysignature() == null))
82 | {
83 | throw new InvalidMessageException("Some required fields missing!");
84 | }
85 |
86 | this.sequence = message.getId() >> 5;
87 | this.flags = message.getId() & 0x1f;
88 | this.serialized = serialized;
89 | this.baseKey = Curve.decodePoint(message.getBasekey(), 0);
90 | this.baseKeySignature = message.getBasekeysignature();
91 | this.ratchetKey = Curve.decodePoint(message.getRatchetkey(), 0);
92 | this.identityKey = new IdentityKey(message.getIdentitykey(), 0);
93 | } catch (InvalidKeyException ike) {
94 | throw new InvalidMessageException(ike);
95 | }
96 | }
97 |
98 | public int getVersion() {
99 | return version;
100 | }
101 |
102 | public ECPublicKey getBaseKey() {
103 | return baseKey;
104 | }
105 |
106 | public byte[] getBaseKeySignature() {
107 | return baseKeySignature;
108 | }
109 |
110 | public ECPublicKey getRatchetKey() {
111 | return ratchetKey;
112 | }
113 |
114 | public IdentityKey getIdentityKey() {
115 | return identityKey;
116 | }
117 |
118 | public boolean hasIdentityKey() {
119 | return true;
120 | }
121 |
122 | public int getMaxVersion() {
123 | return supportedVersion;
124 | }
125 |
126 | public boolean isResponse() {
127 | return ((flags & RESPONSE_FLAG) != 0);
128 | }
129 |
130 | public boolean isInitiate() {
131 | return (flags & INITIATE_FLAG) != 0;
132 | }
133 |
134 | public boolean isResponseForSimultaneousInitiate() {
135 | return (flags & SIMULTAENOUS_INITIATE_FLAG) != 0;
136 | }
137 |
138 | public int getFlags() {
139 | return flags;
140 | }
141 |
142 | public int getSequence() {
143 | return sequence;
144 | }
145 |
146 | public byte[] serialize() {
147 | return serialized;
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/protocol/PreKeyWhisperMessage.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.libaxolotl.protocol;
18 |
19 | import org.whispersystems.libaxolotl.IdentityKey;
20 | import org.whispersystems.libaxolotl.InvalidKeyException;
21 | import org.whispersystems.libaxolotl.InvalidMessageException;
22 | import org.whispersystems.libaxolotl.InvalidVersionException;
23 | import org.whispersystems.libaxolotl.LegacyMessageException;
24 | import org.whispersystems.libaxolotl.ecc.Curve;
25 | import org.whispersystems.libaxolotl.ecc.ECPublicKey;
26 | import org.whispersystems.libaxolotl.util.ByteUtil;
27 | import org.whispersystems.libaxolotl.util.guava.Optional;
28 |
29 |
30 | public class PreKeyWhisperMessage implements CiphertextMessage {
31 |
32 | private final int version;
33 | private final int registrationId;
34 | private final Optional preKeyId;
35 | private final int signedPreKeyId;
36 | private final ECPublicKey baseKey;
37 | private final IdentityKey identityKey;
38 | private final WhisperMessage message;
39 | private final byte[] serialized;
40 |
41 | public PreKeyWhisperMessage(byte[] serialized)
42 | throws InvalidMessageException, InvalidVersionException
43 | {
44 | try {
45 | this.version = ByteUtil.highBitsToInt(serialized[0]);
46 |
47 | if (this.version > CiphertextMessage.CURRENT_VERSION) {
48 | throw new InvalidVersionException("Unknown version: " + this.version);
49 | }
50 |
51 | byte[] structureBytes = new byte[serialized.length - 1];
52 | System.arraycopy(serialized, 1, structureBytes, 0, structureBytes.length);
53 |
54 | org.whispersystems.libaxolotl.protocol.protos.PreKeyWhisperMessage structure
55 | = org.whispersystems.libaxolotl.protocol.protos.PreKeyWhisperMessage.fromBytes(structureBytes);
56 |
57 | if ((version == 2 && !structure.hasPrekeyid()) ||
58 | (version == 3 && !structure.hasSignedprekeyid()) ||
59 | !structure.hasBasekey() ||
60 | !structure.hasIdentitykey() ||
61 | !structure.hasMessage())
62 | {
63 | throw new InvalidMessageException("Incomplete message.");
64 | }
65 |
66 | this.serialized = serialized;
67 | this.registrationId = structure.getRegistrationid();
68 | this.preKeyId = structure.hasPrekeyid() ? Optional.of(new Integer(structure.getPrekeyid())) : Optional.absent();
69 | this.signedPreKeyId = structure.hasSignedprekeyid() ? structure.getSignedprekeyid() : -1;
70 | this.baseKey = Curve.decodePoint(structure.getBasekey(), 0);
71 | this.identityKey = new IdentityKey(Curve.decodePoint(structure.getIdentitykey(), 0));
72 | this.message = new WhisperMessage(structure.getMessage());
73 | } catch (InvalidKeyException ike) {
74 | throw new InvalidMessageException(ike);
75 | } catch (LegacyMessageException e) {
76 | throw new InvalidMessageException(e);
77 | }
78 | }
79 |
80 | public PreKeyWhisperMessage(int messageVersion, int registrationId, Optional preKeyId,
81 | int signedPreKeyId, ECPublicKey baseKey, IdentityKey identityKey,
82 | WhisperMessage message)
83 | {
84 | this.version = messageVersion;
85 | this.registrationId = registrationId;
86 | this.preKeyId = preKeyId;
87 | this.signedPreKeyId = signedPreKeyId;
88 | this.baseKey = baseKey;
89 | this.identityKey = identityKey;
90 | this.message = message;
91 |
92 | org.whispersystems.libaxolotl.protocol.protos.PreKeyWhisperMessage builder =
93 | new org.whispersystems.libaxolotl.protocol.protos.PreKeyWhisperMessage();
94 | builder.setSignedprekeyid(signedPreKeyId);
95 | builder.setBasekey(baseKey.serialize());
96 | builder.setIdentitykey(identityKey.serialize());
97 | builder.setMessage(message.serialize());
98 | builder.setRegistrationid(registrationId);
99 |
100 | if (preKeyId.isPresent()) {
101 | builder.setPrekeyid(((Integer) preKeyId.get()).intValue());
102 | }
103 |
104 | byte[] versionBytes = {ByteUtil.intsToByteHighAndLow(this.version, CURRENT_VERSION)};
105 | byte[] messageBytes = builder.toBytes();
106 |
107 | this.serialized = ByteUtil.combine(versionBytes, messageBytes);
108 | }
109 |
110 | public int getMessageVersion() {
111 | return version;
112 | }
113 |
114 | public IdentityKey getIdentityKey() {
115 | return identityKey;
116 | }
117 |
118 | public int getRegistrationId() {
119 | return registrationId;
120 | }
121 |
122 | public Optional getPreKeyId() {
123 | return preKeyId;
124 | }
125 |
126 | public int getSignedPreKeyId() {
127 | return signedPreKeyId;
128 | }
129 |
130 | public ECPublicKey getBaseKey() {
131 | return baseKey;
132 | }
133 |
134 | public WhisperMessage getWhisperMessage() {
135 | return message;
136 | }
137 |
138 | // @Override
139 | public byte[] serialize() {
140 | return serialized;
141 | }
142 |
143 | // @Override
144 | public int getType() {
145 | return CiphertextMessage.PREKEY_TYPE;
146 | }
147 |
148 | }
149 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/protocol/SenderKeyDistributionMessage.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libaxolotl.protocol;
2 |
3 | import org.whispersystems.libaxolotl.InvalidKeyException;
4 | import org.whispersystems.libaxolotl.InvalidMessageException;
5 | import org.whispersystems.libaxolotl.LegacyMessageException;
6 | import org.whispersystems.libaxolotl.ecc.Curve;
7 | import org.whispersystems.libaxolotl.ecc.ECPublicKey;
8 | import org.whispersystems.libaxolotl.util.ByteUtil;
9 |
10 | public class SenderKeyDistributionMessage implements CiphertextMessage {
11 |
12 | private final int id;
13 | private final int iteration;
14 | private final byte[] chainKey;
15 | private final ECPublicKey signatureKey;
16 | private final byte[] serialized;
17 |
18 | public SenderKeyDistributionMessage(int id, int iteration, byte[] chainKey, ECPublicKey signatureKey) {
19 | byte[] version = {ByteUtil.intsToByteHighAndLow(CURRENT_VERSION, CURRENT_VERSION)};
20 |
21 | this.id = id;
22 | this.iteration = iteration;
23 | this.chainKey = chainKey;
24 | this.signatureKey = signatureKey;
25 |
26 | org.whispersystems.libaxolotl.protocol.protos.SenderKeyDistributionMessage structure =
27 | new org.whispersystems.libaxolotl.protocol.protos.SenderKeyDistributionMessage();
28 |
29 | structure.setId(id);
30 | structure.setIteration(iteration);
31 | structure.setChainkey(chainKey);
32 | structure.setSigningkey(signatureKey.serialize());
33 |
34 | this.serialized = ByteUtil.combine(version, structure.toBytes());
35 | }
36 |
37 | public SenderKeyDistributionMessage(byte[] serialized) throws LegacyMessageException, InvalidMessageException {
38 | try {
39 | byte[][] messageParts = ByteUtil.split(serialized, 1, serialized.length - 1);
40 | byte version = messageParts[0][0];
41 | byte[] message = messageParts[1];
42 |
43 | if (ByteUtil.highBitsToInt(version) < CiphertextMessage.CURRENT_VERSION) {
44 | throw new LegacyMessageException("Legacy message: " + ByteUtil.highBitsToInt(version));
45 | }
46 |
47 | if (ByteUtil.highBitsToInt(version) > CURRENT_VERSION) {
48 | throw new InvalidMessageException("Unknown version: " + ByteUtil.highBitsToInt(version));
49 | }
50 |
51 | org.whispersystems.libaxolotl.protocol.protos.SenderKeyDistributionMessage distributionMessage =
52 | org.whispersystems.libaxolotl.protocol.protos.SenderKeyDistributionMessage.fromBytes(message);
53 |
54 | if (!distributionMessage.hasId() ||
55 | !distributionMessage.hasIteration() ||
56 | !distributionMessage.hasChainkey() ||
57 | !distributionMessage.hasSigningkey())
58 | {
59 | throw new InvalidMessageException("Incomplete message.");
60 | }
61 |
62 | this.serialized = serialized;
63 | this.id = distributionMessage.getId();
64 | this.iteration = distributionMessage.getIteration();
65 | this.chainKey = distributionMessage.getChainkey();
66 | this.signatureKey = Curve.decodePoint(distributionMessage.getSigningkey(), 0);
67 | } catch (InvalidKeyException e) {
68 | throw new InvalidMessageException(e);
69 | }
70 | }
71 |
72 | // @Override
73 | public byte[] serialize() {
74 | return serialized;
75 | }
76 |
77 | // @Override
78 | public int getType() {
79 | return SENDERKEY_DISTRIBUTION_TYPE;
80 | }
81 |
82 | public int getIteration() {
83 | return iteration;
84 | }
85 |
86 | public byte[] getChainKey() {
87 | return chainKey;
88 | }
89 |
90 | public ECPublicKey getSignatureKey() {
91 | return signatureKey;
92 | }
93 |
94 | public int getId() {
95 | return id;
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/protocol/SenderKeyMessage.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libaxolotl.protocol;
2 |
3 | import org.whispersystems.curve25519.SecureRandomProvider;
4 | import org.whispersystems.libaxolotl.InvalidKeyException;
5 | import org.whispersystems.libaxolotl.InvalidMessageException;
6 | import org.whispersystems.libaxolotl.LegacyMessageException;
7 | import org.whispersystems.libaxolotl.ecc.Curve;
8 | import org.whispersystems.libaxolotl.ecc.ECPrivateKey;
9 | import org.whispersystems.libaxolotl.ecc.ECPublicKey;
10 | import org.whispersystems.libaxolotl.j2me.AssertionError;
11 | import org.whispersystems.libaxolotl.util.ByteUtil;
12 | import org.whispersystems.libaxolotl.j2me.ParseException;
13 |
14 |
15 | public class SenderKeyMessage implements CiphertextMessage {
16 |
17 | private static final int SIGNATURE_LENGTH = 64;
18 |
19 | private final int messageVersion;
20 | private final int keyId;
21 | private final int iteration;
22 | private final byte[] ciphertext;
23 | private final byte[] serialized;
24 |
25 | public SenderKeyMessage(byte[] serialized) throws InvalidMessageException, LegacyMessageException {
26 | try {
27 | byte[][] messageParts = ByteUtil.split(serialized, 1, serialized.length - 1 - SIGNATURE_LENGTH, SIGNATURE_LENGTH);
28 | byte version = messageParts[0][0];
29 | byte[] message = messageParts[1];
30 | byte[] signature = messageParts[2];
31 |
32 | if (ByteUtil.highBitsToInt(version) < 3) {
33 | throw new LegacyMessageException("Legacy message: " + ByteUtil.highBitsToInt(version));
34 | }
35 |
36 | if (ByteUtil.highBitsToInt(version) > CURRENT_VERSION) {
37 | throw new InvalidMessageException("Unknown version: " + ByteUtil.highBitsToInt(version));
38 | }
39 |
40 | org.whispersystems.libaxolotl.protocol.protos.SenderKeyMessage structure =
41 | org.whispersystems.libaxolotl.protocol.protos.SenderKeyMessage.fromBytes(message);
42 |
43 | if (!structure.hasId() ||
44 | !structure.hasIteration() ||
45 | !structure.hasCiphertext())
46 | {
47 | throw new InvalidMessageException("Incomplete message.");
48 | }
49 |
50 | this.serialized = serialized;
51 | this.messageVersion = ByteUtil.highBitsToInt(version);
52 | this.keyId = structure.getId();
53 | this.iteration = structure.getIteration();
54 | this.ciphertext = structure.getCiphertext();
55 | } catch (ParseException e) {
56 | throw new InvalidMessageException(e);
57 | }
58 | }
59 |
60 | public SenderKeyMessage(SecureRandomProvider secureRandom,
61 | int keyId, int iteration, byte[] ciphertext, ECPrivateKey signatureKey)
62 | {
63 | org.whispersystems.libaxolotl.protocol.protos.SenderKeyMessage structure =
64 | new org.whispersystems.libaxolotl.protocol.protos.SenderKeyMessage();
65 |
66 | structure.setId(keyId);
67 | structure.setIteration(iteration);
68 | structure.setCiphertext(ciphertext);
69 |
70 | byte[] version = {ByteUtil.intsToByteHighAndLow(CURRENT_VERSION, CURRENT_VERSION)};
71 | byte[] message = structure.toBytes();
72 | byte[] signature = getSignature(secureRandom, signatureKey, ByteUtil.combine(version, message));
73 |
74 | this.serialized = ByteUtil.combine(version, message, signature);
75 | this.messageVersion = CURRENT_VERSION;
76 | this.keyId = keyId;
77 | this.iteration = iteration;
78 | this.ciphertext = ciphertext;
79 | }
80 |
81 | public int getKeyId() {
82 | return keyId;
83 | }
84 |
85 | public int getIteration() {
86 | return iteration;
87 | }
88 |
89 | public byte[] getCipherText() {
90 | return ciphertext;
91 | }
92 |
93 | public void verifySignature(ECPublicKey signatureKey)
94 | throws InvalidMessageException
95 | {
96 | try {
97 | byte[][] parts = ByteUtil.split(serialized, serialized.length - SIGNATURE_LENGTH, SIGNATURE_LENGTH);
98 |
99 | if (!Curve.verifySignature(signatureKey, parts[0], parts[1])) {
100 | throw new InvalidMessageException("Invalid signature!");
101 | }
102 |
103 | } catch (InvalidKeyException e) {
104 | throw new InvalidMessageException(e);
105 | }
106 | }
107 |
108 | private byte[] getSignature(SecureRandomProvider secureRandom, ECPrivateKey signatureKey, byte[] serialized) {
109 | try {
110 | return Curve.calculateSignature(secureRandom, signatureKey, serialized);
111 | } catch (InvalidKeyException e) {
112 | throw new AssertionError(e);
113 | }
114 | }
115 |
116 | // @Override
117 | public byte[] serialize() {
118 | return serialized;
119 | }
120 |
121 | // @Override
122 | public int getType() {
123 | return CiphertextMessage.SENDERKEY_TYPE;
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/protocol/WhisperMessage.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.libaxolotl.protocol;
18 |
19 | import org.bouncycastle.crypto.params.KeyParameter;
20 | import org.whispersystems.libaxolotl.IdentityKey;
21 | import org.whispersystems.libaxolotl.InvalidKeyException;
22 | import org.whispersystems.libaxolotl.InvalidMessageException;
23 | import org.whispersystems.libaxolotl.LegacyMessageException;
24 | import org.whispersystems.libaxolotl.ecc.Curve;
25 | import org.whispersystems.libaxolotl.ecc.ECPublicKey;
26 | import org.whispersystems.libaxolotl.j2me.MessageDigest;
27 | import org.whispersystems.libaxolotl.j2me.ParseException;
28 | import org.whispersystems.libaxolotl.j2me.jce.JmeSecurity;
29 | import org.whispersystems.libaxolotl.j2me.jce.mac.Mac;
30 | import org.whispersystems.libaxolotl.util.ByteUtil;
31 |
32 | public class WhisperMessage implements CiphertextMessage {
33 |
34 | private static final int MAC_LENGTH = 8;
35 |
36 | private final int messageVersion;
37 | private final ECPublicKey senderRatchetKey;
38 | private final int counter;
39 | private final int previousCounter;
40 | private final byte[] ciphertext;
41 | private final byte[] serialized;
42 |
43 | public WhisperMessage(byte[] serialized) throws InvalidMessageException, LegacyMessageException {
44 | try {
45 | byte[][] messageParts = ByteUtil.split(serialized, 1, serialized.length - 1 - MAC_LENGTH, MAC_LENGTH);
46 | byte version = messageParts[0][0];
47 | byte[] message = messageParts[1];
48 | byte[] mac = messageParts[2];
49 |
50 | if (ByteUtil.highBitsToInt(version) <= CiphertextMessage.UNSUPPORTED_VERSION) {
51 | throw new LegacyMessageException("Legacy message: " + ByteUtil.highBitsToInt(version));
52 | }
53 |
54 | if (ByteUtil.highBitsToInt(version) > CURRENT_VERSION) {
55 | throw new InvalidMessageException("Unknown version: " + ByteUtil.highBitsToInt(version));
56 | }
57 |
58 | org.whispersystems.libaxolotl.protocol.protos.WhisperMessage structure =
59 | org.whispersystems.libaxolotl.protocol.protos.WhisperMessage.fromBytes(message);
60 |
61 | if (!structure.hasCiphertext() ||
62 | !structure.hasCounter() ||
63 | !structure.hasRatchetkey())
64 | {
65 | throw new InvalidMessageException("Incomplete message.");
66 | }
67 |
68 | this.serialized = serialized;
69 | this.senderRatchetKey = Curve.decodePoint(structure.getRatchetkey(), 0);
70 | this.messageVersion = ByteUtil.highBitsToInt(version);
71 | this.counter = structure.getCounter();
72 | this.previousCounter = structure.getPreviouscounter();
73 | this.ciphertext = structure.getCiphertext();
74 | } catch (InvalidKeyException ike) {
75 | throw new InvalidMessageException(ike);
76 | } catch (ParseException e) {
77 | throw new InvalidMessageException(e);
78 | }
79 | }
80 |
81 | public WhisperMessage(int messageVersion, KeyParameter macKey, ECPublicKey senderRatchetKey,
82 | int counter, int previousCounter, byte[] ciphertext,
83 | IdentityKey senderIdentityKey,
84 | IdentityKey receiverIdentityKey)
85 | {
86 | org.whispersystems.libaxolotl.protocol.protos.WhisperMessage structure =
87 | new org.whispersystems.libaxolotl.protocol.protos.WhisperMessage();
88 |
89 | structure.setRatchetkey(senderRatchetKey.serialize());
90 | structure.setCounter(counter);
91 | structure.setPreviouscounter(previousCounter);
92 | structure.setCiphertext(ciphertext);
93 |
94 | byte[] version = {ByteUtil.intsToByteHighAndLow(messageVersion, CURRENT_VERSION)};
95 | byte[] message = structure.toBytes();
96 | byte[] mac = getMac(messageVersion, senderIdentityKey, receiverIdentityKey, macKey,
97 | ByteUtil.combine(version, message));
98 |
99 | this.serialized = ByteUtil.combine(version, message, mac);
100 | this.senderRatchetKey = senderRatchetKey;
101 | this.counter = counter;
102 | this.previousCounter = previousCounter;
103 | this.ciphertext = ciphertext;
104 | this.messageVersion = messageVersion;
105 | }
106 |
107 | public ECPublicKey getSenderRatchetKey() {
108 | return senderRatchetKey;
109 | }
110 |
111 | public int getMessageVersion() {
112 | return messageVersion;
113 | }
114 |
115 | public int getCounter() {
116 | return counter;
117 | }
118 |
119 | public byte[] getBody() {
120 | return ciphertext;
121 | }
122 |
123 | public void verifyMac(int messageVersion, IdentityKey senderIdentityKey,
124 | IdentityKey receiverIdentityKey, KeyParameter macKey)
125 | throws InvalidMessageException
126 | {
127 | byte[][] parts = ByteUtil.split(serialized, serialized.length - MAC_LENGTH, MAC_LENGTH);
128 | byte[] ourMac = getMac(messageVersion, senderIdentityKey, receiverIdentityKey, macKey, parts[0]);
129 | byte[] theirMac = parts[1];
130 |
131 | if (!MessageDigest.isEqual(ourMac, theirMac)) {
132 | throw new InvalidMessageException("Bad Mac!");
133 | }
134 | }
135 |
136 | private byte[] getMac(int messageVersion,
137 | IdentityKey senderIdentityKey,
138 | IdentityKey receiverIdentityKey,
139 | KeyParameter macKey, byte[] serialized)
140 | {
141 | Mac mac = JmeSecurity.getProvider().createMacSha256(macKey.getKey());
142 | byte[] output = new byte[32];
143 |
144 | if (messageVersion >= 3) {
145 | byte[] senderIdentity = senderIdentityKey.getPublicKey().serialize();
146 | byte[] receiverIdentity = receiverIdentityKey.getPublicKey().serialize();
147 |
148 | mac.update(senderIdentity, 0, senderIdentity.length);
149 | mac.update(receiverIdentity, 0, receiverIdentity.length);
150 | }
151 |
152 | mac.update(serialized, 0, serialized.length);
153 | mac.doFinal(output, 0);
154 |
155 | return ByteUtil.trim(output, MAC_LENGTH);
156 | }
157 |
158 | // @Override
159 | public byte[] serialize() {
160 | return serialized;
161 | }
162 |
163 | // @Override
164 | public int getType() {
165 | return CiphertextMessage.WHISPER_TYPE;
166 | }
167 |
168 | public static boolean isLegacy(byte[] message) {
169 | return message != null && message.length >= 1 &&
170 | ByteUtil.highBitsToInt(message[0]) <= CiphertextMessage.UNSUPPORTED_VERSION;
171 | }
172 |
173 | }
174 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/protocol/protos/KeyExchangeMessage.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libaxolotl.protocol.protos;
2 |
3 | import java.util.Vector;
4 | import java.io.IOException;
5 |
6 | import com.ponderingpanda.protobuf.*;
7 |
8 |
9 | public class KeyExchangeMessage implements Message {
10 |
11 |
12 |
13 | protected int id; // 1
14 | protected boolean _hasId;
15 | protected byte[] basekey; // 2
16 | protected boolean _hasBasekey;
17 | protected byte[] ratchetkey; // 3
18 | protected boolean _hasRatchetkey;
19 | protected byte[] identitykey; // 4
20 | protected boolean _hasIdentitykey;
21 | protected byte[] basekeysignature; // 5
22 | protected boolean _hasBasekeysignature;
23 |
24 | public int getId() {
25 | return id;
26 | }
27 |
28 | public void setId(int id) {
29 | this.id = id;
30 | this._hasId = true;
31 | }
32 |
33 | public void clearId() {
34 | _hasId = false;
35 | }
36 |
37 | public boolean hasId() {
38 | return _hasId;
39 | }
40 | public byte[] getBasekey() {
41 | return basekey;
42 | }
43 |
44 | public void setBasekey(byte[] basekey) {
45 | this.basekey = basekey;
46 | this._hasBasekey = true;
47 | }
48 |
49 | public void clearBasekey() {
50 | _hasBasekey = false;
51 | }
52 |
53 | public boolean hasBasekey() {
54 | return _hasBasekey;
55 | }
56 | public byte[] getRatchetkey() {
57 | return ratchetkey;
58 | }
59 |
60 | public void setRatchetkey(byte[] ratchetkey) {
61 | this.ratchetkey = ratchetkey;
62 | this._hasRatchetkey = true;
63 | }
64 |
65 | public void clearRatchetkey() {
66 | _hasRatchetkey = false;
67 | }
68 |
69 | public boolean hasRatchetkey() {
70 | return _hasRatchetkey;
71 | }
72 | public byte[] getIdentitykey() {
73 | return identitykey;
74 | }
75 |
76 | public void setIdentitykey(byte[] identitykey) {
77 | this.identitykey = identitykey;
78 | this._hasIdentitykey = true;
79 | }
80 |
81 | public void clearIdentitykey() {
82 | _hasIdentitykey = false;
83 | }
84 |
85 | public boolean hasIdentitykey() {
86 | return _hasIdentitykey;
87 | }
88 | public byte[] getBasekeysignature() {
89 | return basekeysignature;
90 | }
91 |
92 | public void setBasekeysignature(byte[] basekeysignature) {
93 | this.basekeysignature = basekeysignature;
94 | this._hasBasekeysignature = true;
95 | }
96 |
97 | public void clearBasekeysignature() {
98 | _hasBasekeysignature = false;
99 | }
100 |
101 | public boolean hasBasekeysignature() {
102 | return _hasBasekeysignature;
103 | }
104 |
105 | public final void serialize(CodedOutputStream out) throws IOException {
106 | if(_hasId)
107 | out.writeUInt32(1, id);
108 |
109 | if(_hasBasekey)
110 | out.writeBytes(2, basekey);
111 |
112 | if(_hasRatchetkey)
113 | out.writeBytes(3, ratchetkey);
114 |
115 | if(_hasIdentitykey)
116 | out.writeBytes(4, identitykey);
117 |
118 | if(_hasBasekeysignature)
119 | out.writeBytes(5, basekeysignature);
120 |
121 | }
122 |
123 | public final void deserialize(CodedInputStream in) throws IOException {
124 | while(true) {
125 | int tag = in.readTag();
126 | switch(tag) {
127 | case 0:
128 | return;
129 | case 8: {
130 | id = in.readUInt32();
131 | _hasId = true;
132 | break; }
133 | case 18: {
134 | basekey = in.readBytes();
135 | _hasBasekey = true;
136 | break; }
137 | case 26: {
138 | ratchetkey = in.readBytes();
139 | _hasRatchetkey = true;
140 | break; }
141 | case 34: {
142 | identitykey = in.readBytes();
143 | _hasIdentitykey = true;
144 | break; }
145 | case 42: {
146 | basekeysignature = in.readBytes();
147 | _hasBasekeysignature = true;
148 | break; }
149 | default:
150 | in.skipTag(tag);
151 | }
152 | }
153 | }
154 |
155 | public static KeyExchangeMessage fromBytes(byte[] in) throws EncodingException {
156 | KeyExchangeMessage message = new KeyExchangeMessage();
157 | ProtoUtil.messageFromBytes(in, message);
158 | return message;
159 | }
160 |
161 | public byte[] toBytes() throws EncodingException {
162 | return ProtoUtil.messageToBytes(this);
163 | }
164 |
165 |
166 | }
167 |
168 |
169 |
170 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/protocol/protos/PreKeyWhisperMessage.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libaxolotl.protocol.protos;
2 |
3 | import java.util.Vector;
4 | import java.io.IOException;
5 |
6 | import com.ponderingpanda.protobuf.*;
7 |
8 |
9 | public class PreKeyWhisperMessage implements Message {
10 |
11 |
12 |
13 | protected int registrationid; // 5
14 | protected boolean _hasRegistrationid;
15 | protected int prekeyid; // 1
16 | protected boolean _hasPrekeyid;
17 | protected int signedprekeyid; // 6
18 | protected boolean _hasSignedprekeyid;
19 | protected byte[] basekey; // 2
20 | protected boolean _hasBasekey;
21 | protected byte[] identitykey; // 3
22 | protected boolean _hasIdentitykey;
23 | protected byte[] message; // 4
24 | protected boolean _hasMessage;
25 |
26 | public int getRegistrationid() {
27 | return registrationid;
28 | }
29 |
30 | public void setRegistrationid(int registrationid) {
31 | this.registrationid = registrationid;
32 | this._hasRegistrationid = true;
33 | }
34 |
35 | public void clearRegistrationid() {
36 | _hasRegistrationid = false;
37 | }
38 |
39 | public boolean hasRegistrationid() {
40 | return _hasRegistrationid;
41 | }
42 | public int getPrekeyid() {
43 | return prekeyid;
44 | }
45 |
46 | public void setPrekeyid(int prekeyid) {
47 | this.prekeyid = prekeyid;
48 | this._hasPrekeyid = true;
49 | }
50 |
51 | public void clearPrekeyid() {
52 | _hasPrekeyid = false;
53 | }
54 |
55 | public boolean hasPrekeyid() {
56 | return _hasPrekeyid;
57 | }
58 | public int getSignedprekeyid() {
59 | return signedprekeyid;
60 | }
61 |
62 | public void setSignedprekeyid(int signedprekeyid) {
63 | this.signedprekeyid = signedprekeyid;
64 | this._hasSignedprekeyid = true;
65 | }
66 |
67 | public void clearSignedprekeyid() {
68 | _hasSignedprekeyid = false;
69 | }
70 |
71 | public boolean hasSignedprekeyid() {
72 | return _hasSignedprekeyid;
73 | }
74 | public byte[] getBasekey() {
75 | return basekey;
76 | }
77 |
78 | public void setBasekey(byte[] basekey) {
79 | this.basekey = basekey;
80 | this._hasBasekey = true;
81 | }
82 |
83 | public void clearBasekey() {
84 | _hasBasekey = false;
85 | }
86 |
87 | public boolean hasBasekey() {
88 | return _hasBasekey;
89 | }
90 | public byte[] getIdentitykey() {
91 | return identitykey;
92 | }
93 |
94 | public void setIdentitykey(byte[] identitykey) {
95 | this.identitykey = identitykey;
96 | this._hasIdentitykey = true;
97 | }
98 |
99 | public void clearIdentitykey() {
100 | _hasIdentitykey = false;
101 | }
102 |
103 | public boolean hasIdentitykey() {
104 | return _hasIdentitykey;
105 | }
106 | public byte[] getMessage() {
107 | return message;
108 | }
109 |
110 | public void setMessage(byte[] message) {
111 | this.message = message;
112 | this._hasMessage = true;
113 | }
114 |
115 | public void clearMessage() {
116 | _hasMessage = false;
117 | }
118 |
119 | public boolean hasMessage() {
120 | return _hasMessage;
121 | }
122 |
123 | public final void serialize(CodedOutputStream out) throws IOException {
124 | if(_hasRegistrationid)
125 | out.writeUInt32(5, registrationid);
126 |
127 | if(_hasPrekeyid)
128 | out.writeUInt32(1, prekeyid);
129 |
130 | if(_hasSignedprekeyid)
131 | out.writeUInt32(6, signedprekeyid);
132 |
133 | if(_hasBasekey)
134 | out.writeBytes(2, basekey);
135 |
136 | if(_hasIdentitykey)
137 | out.writeBytes(3, identitykey);
138 |
139 | if(_hasMessage)
140 | out.writeBytes(4, message);
141 |
142 | }
143 |
144 | public final void deserialize(CodedInputStream in) throws IOException {
145 | while(true) {
146 | int tag = in.readTag();
147 | switch(tag) {
148 | case 0:
149 | return;
150 | case 40: {
151 | registrationid = in.readUInt32();
152 | _hasRegistrationid = true;
153 | break; }
154 | case 8: {
155 | prekeyid = in.readUInt32();
156 | _hasPrekeyid = true;
157 | break; }
158 | case 48: {
159 | signedprekeyid = in.readUInt32();
160 | _hasSignedprekeyid = true;
161 | break; }
162 | case 18: {
163 | basekey = in.readBytes();
164 | _hasBasekey = true;
165 | break; }
166 | case 26: {
167 | identitykey = in.readBytes();
168 | _hasIdentitykey = true;
169 | break; }
170 | case 34: {
171 | message = in.readBytes();
172 | _hasMessage = true;
173 | break; }
174 | default:
175 | in.skipTag(tag);
176 | }
177 | }
178 | }
179 |
180 | public static PreKeyWhisperMessage fromBytes(byte[] in) throws EncodingException {
181 | PreKeyWhisperMessage message = new PreKeyWhisperMessage();
182 | ProtoUtil.messageFromBytes(in, message);
183 | return message;
184 | }
185 |
186 | public byte[] toBytes() throws EncodingException {
187 | return ProtoUtil.messageToBytes(this);
188 | }
189 |
190 |
191 | }
192 |
193 |
194 |
195 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/protocol/protos/SenderKeyDistributionMessage.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libaxolotl.protocol.protos;
2 |
3 | import java.util.Vector;
4 | import java.io.IOException;
5 |
6 | import com.ponderingpanda.protobuf.*;
7 |
8 |
9 | public class SenderKeyDistributionMessage implements Message {
10 |
11 |
12 |
13 | protected int id; // 1
14 | protected boolean _hasId;
15 | protected int iteration; // 2
16 | protected boolean _hasIteration;
17 | protected byte[] chainkey; // 3
18 | protected boolean _hasChainkey;
19 | protected byte[] signingkey; // 4
20 | protected boolean _hasSigningkey;
21 |
22 | public int getId() {
23 | return id;
24 | }
25 |
26 | public void setId(int id) {
27 | this.id = id;
28 | this._hasId = true;
29 | }
30 |
31 | public void clearId() {
32 | _hasId = false;
33 | }
34 |
35 | public boolean hasId() {
36 | return _hasId;
37 | }
38 | public int getIteration() {
39 | return iteration;
40 | }
41 |
42 | public void setIteration(int iteration) {
43 | this.iteration = iteration;
44 | this._hasIteration = true;
45 | }
46 |
47 | public void clearIteration() {
48 | _hasIteration = false;
49 | }
50 |
51 | public boolean hasIteration() {
52 | return _hasIteration;
53 | }
54 | public byte[] getChainkey() {
55 | return chainkey;
56 | }
57 |
58 | public void setChainkey(byte[] chainkey) {
59 | this.chainkey = chainkey;
60 | this._hasChainkey = true;
61 | }
62 |
63 | public void clearChainkey() {
64 | _hasChainkey = false;
65 | }
66 |
67 | public boolean hasChainkey() {
68 | return _hasChainkey;
69 | }
70 | public byte[] getSigningkey() {
71 | return signingkey;
72 | }
73 |
74 | public void setSigningkey(byte[] signingkey) {
75 | this.signingkey = signingkey;
76 | this._hasSigningkey = true;
77 | }
78 |
79 | public void clearSigningkey() {
80 | _hasSigningkey = false;
81 | }
82 |
83 | public boolean hasSigningkey() {
84 | return _hasSigningkey;
85 | }
86 |
87 | public final void serialize(CodedOutputStream out) throws IOException {
88 | if(_hasId)
89 | out.writeUInt32(1, id);
90 |
91 | if(_hasIteration)
92 | out.writeUInt32(2, iteration);
93 |
94 | if(_hasChainkey)
95 | out.writeBytes(3, chainkey);
96 |
97 | if(_hasSigningkey)
98 | out.writeBytes(4, signingkey);
99 |
100 | }
101 |
102 | public final void deserialize(CodedInputStream in) throws IOException {
103 | while(true) {
104 | int tag = in.readTag();
105 | switch(tag) {
106 | case 0:
107 | return;
108 | case 8: {
109 | id = in.readUInt32();
110 | _hasId = true;
111 | break; }
112 | case 16: {
113 | iteration = in.readUInt32();
114 | _hasIteration = true;
115 | break; }
116 | case 26: {
117 | chainkey = in.readBytes();
118 | _hasChainkey = true;
119 | break; }
120 | case 34: {
121 | signingkey = in.readBytes();
122 | _hasSigningkey = true;
123 | break; }
124 | default:
125 | in.skipTag(tag);
126 | }
127 | }
128 | }
129 |
130 | public static SenderKeyDistributionMessage fromBytes(byte[] in) throws EncodingException {
131 | SenderKeyDistributionMessage message = new SenderKeyDistributionMessage();
132 | ProtoUtil.messageFromBytes(in, message);
133 | return message;
134 | }
135 |
136 | public byte[] toBytes() throws EncodingException {
137 | return ProtoUtil.messageToBytes(this);
138 | }
139 |
140 |
141 | }
142 |
143 |
144 |
145 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/protocol/protos/SenderKeyMessage.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libaxolotl.protocol.protos;
2 |
3 | import java.util.Vector;
4 | import java.io.IOException;
5 |
6 | import com.ponderingpanda.protobuf.*;
7 |
8 |
9 | public class SenderKeyMessage implements Message {
10 |
11 |
12 |
13 | protected int id; // 1
14 | protected boolean _hasId;
15 | protected int iteration; // 2
16 | protected boolean _hasIteration;
17 | protected byte[] ciphertext; // 3
18 | protected boolean _hasCiphertext;
19 |
20 | public int getId() {
21 | return id;
22 | }
23 |
24 | public void setId(int id) {
25 | this.id = id;
26 | this._hasId = true;
27 | }
28 |
29 | public void clearId() {
30 | _hasId = false;
31 | }
32 |
33 | public boolean hasId() {
34 | return _hasId;
35 | }
36 | public int getIteration() {
37 | return iteration;
38 | }
39 |
40 | public void setIteration(int iteration) {
41 | this.iteration = iteration;
42 | this._hasIteration = true;
43 | }
44 |
45 | public void clearIteration() {
46 | _hasIteration = false;
47 | }
48 |
49 | public boolean hasIteration() {
50 | return _hasIteration;
51 | }
52 | public byte[] getCiphertext() {
53 | return ciphertext;
54 | }
55 |
56 | public void setCiphertext(byte[] ciphertext) {
57 | this.ciphertext = ciphertext;
58 | this._hasCiphertext = true;
59 | }
60 |
61 | public void clearCiphertext() {
62 | _hasCiphertext = false;
63 | }
64 |
65 | public boolean hasCiphertext() {
66 | return _hasCiphertext;
67 | }
68 |
69 | public final void serialize(CodedOutputStream out) throws IOException {
70 | if(_hasId)
71 | out.writeUInt32(1, id);
72 |
73 | if(_hasIteration)
74 | out.writeUInt32(2, iteration);
75 |
76 | if(_hasCiphertext)
77 | out.writeBytes(3, ciphertext);
78 |
79 | }
80 |
81 | public final void deserialize(CodedInputStream in) throws IOException {
82 | while(true) {
83 | int tag = in.readTag();
84 | switch(tag) {
85 | case 0:
86 | return;
87 | case 8: {
88 | id = in.readUInt32();
89 | _hasId = true;
90 | break; }
91 | case 16: {
92 | iteration = in.readUInt32();
93 | _hasIteration = true;
94 | break; }
95 | case 26: {
96 | ciphertext = in.readBytes();
97 | _hasCiphertext = true;
98 | break; }
99 | default:
100 | in.skipTag(tag);
101 | }
102 | }
103 | }
104 |
105 | public static SenderKeyMessage fromBytes(byte[] in) throws EncodingException {
106 | SenderKeyMessage message = new SenderKeyMessage();
107 | ProtoUtil.messageFromBytes(in, message);
108 | return message;
109 | }
110 |
111 | public byte[] toBytes() throws EncodingException {
112 | return ProtoUtil.messageToBytes(this);
113 | }
114 |
115 |
116 | }
117 |
118 |
119 |
120 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/protocol/protos/WhisperMessage.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libaxolotl.protocol.protos;
2 |
3 | import java.util.Vector;
4 | import java.io.IOException;
5 |
6 | import com.ponderingpanda.protobuf.*;
7 |
8 |
9 | public class WhisperMessage implements Message {
10 |
11 |
12 |
13 | protected byte[] ratchetkey; // 1
14 | protected boolean _hasRatchetkey;
15 | protected int counter; // 2
16 | protected boolean _hasCounter;
17 | protected int previouscounter; // 3
18 | protected boolean _hasPreviouscounter;
19 | protected byte[] ciphertext; // 4
20 | protected boolean _hasCiphertext;
21 |
22 | public byte[] getRatchetkey() {
23 | return ratchetkey;
24 | }
25 |
26 | public void setRatchetkey(byte[] ratchetkey) {
27 | this.ratchetkey = ratchetkey;
28 | this._hasRatchetkey = true;
29 | }
30 |
31 | public void clearRatchetkey() {
32 | _hasRatchetkey = false;
33 | }
34 |
35 | public boolean hasRatchetkey() {
36 | return _hasRatchetkey;
37 | }
38 | public int getCounter() {
39 | return counter;
40 | }
41 |
42 | public void setCounter(int counter) {
43 | this.counter = counter;
44 | this._hasCounter = true;
45 | }
46 |
47 | public void clearCounter() {
48 | _hasCounter = false;
49 | }
50 |
51 | public boolean hasCounter() {
52 | return _hasCounter;
53 | }
54 | public int getPreviouscounter() {
55 | return previouscounter;
56 | }
57 |
58 | public void setPreviouscounter(int previouscounter) {
59 | this.previouscounter = previouscounter;
60 | this._hasPreviouscounter = true;
61 | }
62 |
63 | public void clearPreviouscounter() {
64 | _hasPreviouscounter = false;
65 | }
66 |
67 | public boolean hasPreviouscounter() {
68 | return _hasPreviouscounter;
69 | }
70 | public byte[] getCiphertext() {
71 | return ciphertext;
72 | }
73 |
74 | public void setCiphertext(byte[] ciphertext) {
75 | this.ciphertext = ciphertext;
76 | this._hasCiphertext = true;
77 | }
78 |
79 | public void clearCiphertext() {
80 | _hasCiphertext = false;
81 | }
82 |
83 | public boolean hasCiphertext() {
84 | return _hasCiphertext;
85 | }
86 |
87 | public final void serialize(CodedOutputStream out) throws IOException {
88 | if(_hasRatchetkey)
89 | out.writeBytes(1, ratchetkey);
90 |
91 | if(_hasCounter)
92 | out.writeUInt32(2, counter);
93 |
94 | if(_hasPreviouscounter)
95 | out.writeUInt32(3, previouscounter);
96 |
97 | if(_hasCiphertext)
98 | out.writeBytes(4, ciphertext);
99 |
100 | }
101 |
102 | public final void deserialize(CodedInputStream in) throws IOException {
103 | while(true) {
104 | int tag = in.readTag();
105 | switch(tag) {
106 | case 0:
107 | return;
108 | case 10: {
109 | ratchetkey = in.readBytes();
110 | _hasRatchetkey = true;
111 | break; }
112 | case 16: {
113 | counter = in.readUInt32();
114 | _hasCounter = true;
115 | break; }
116 | case 24: {
117 | previouscounter = in.readUInt32();
118 | _hasPreviouscounter = true;
119 | break; }
120 | case 34: {
121 | ciphertext = in.readBytes();
122 | _hasCiphertext = true;
123 | break; }
124 | default:
125 | in.skipTag(tag);
126 | }
127 | }
128 | }
129 |
130 | public static WhisperMessage fromBytes(byte[] in) throws EncodingException {
131 | WhisperMessage message = new WhisperMessage();
132 | ProtoUtil.messageFromBytes(in, message);
133 | return message;
134 | }
135 |
136 | public byte[] toBytes() throws EncodingException {
137 | return ProtoUtil.messageToBytes(this);
138 | }
139 |
140 |
141 | }
142 |
143 |
144 |
145 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/ratchet/AliceAxolotlParameters.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libaxolotl.ratchet;
2 |
3 | import org.whispersystems.libaxolotl.IdentityKey;
4 | import org.whispersystems.libaxolotl.IdentityKeyPair;
5 | import org.whispersystems.libaxolotl.ecc.ECKeyPair;
6 | import org.whispersystems.libaxolotl.ecc.ECPublicKey;
7 | import org.whispersystems.libaxolotl.util.guava.Optional;
8 |
9 | public class AliceAxolotlParameters {
10 |
11 | private final IdentityKeyPair ourIdentityKey;
12 | private final ECKeyPair ourBaseKey;
13 |
14 | private final IdentityKey theirIdentityKey;
15 | private final ECPublicKey theirSignedPreKey;
16 | private final Optional theirOneTimePreKey;
17 | private final ECPublicKey theirRatchetKey;
18 |
19 | private AliceAxolotlParameters(IdentityKeyPair ourIdentityKey, ECKeyPair ourBaseKey,
20 | IdentityKey theirIdentityKey, ECPublicKey theirSignedPreKey,
21 | ECPublicKey theirRatchetKey, Optional theirOneTimePreKey)
22 | {
23 | this.ourIdentityKey = ourIdentityKey;
24 | this.ourBaseKey = ourBaseKey;
25 | this.theirIdentityKey = theirIdentityKey;
26 | this.theirSignedPreKey = theirSignedPreKey;
27 | this.theirRatchetKey = theirRatchetKey;
28 | this.theirOneTimePreKey = theirOneTimePreKey;
29 |
30 | if (ourIdentityKey == null || ourBaseKey == null || theirIdentityKey == null ||
31 | theirSignedPreKey == null || theirRatchetKey == null || theirOneTimePreKey == null)
32 | {
33 | throw new IllegalArgumentException("Null values!");
34 | }
35 | }
36 |
37 | public IdentityKeyPair getOurIdentityKey() {
38 | return ourIdentityKey;
39 | }
40 |
41 | public ECKeyPair getOurBaseKey() {
42 | return ourBaseKey;
43 | }
44 |
45 | public IdentityKey getTheirIdentityKey() {
46 | return theirIdentityKey;
47 | }
48 |
49 | public ECPublicKey getTheirSignedPreKey() {
50 | return theirSignedPreKey;
51 | }
52 |
53 | public Optional getTheirOneTimePreKey() {
54 | return theirOneTimePreKey;
55 | }
56 |
57 | public static Builder newBuilder() {
58 | return new Builder();
59 | }
60 |
61 | public ECPublicKey getTheirRatchetKey() {
62 | return theirRatchetKey;
63 | }
64 |
65 | public static class Builder {
66 | private IdentityKeyPair ourIdentityKey;
67 | private ECKeyPair ourBaseKey;
68 |
69 | private IdentityKey theirIdentityKey;
70 | private ECPublicKey theirSignedPreKey;
71 | private ECPublicKey theirRatchetKey;
72 | private Optional theirOneTimePreKey;
73 |
74 | public Builder setOurIdentityKey(IdentityKeyPair ourIdentityKey) {
75 | this.ourIdentityKey = ourIdentityKey;
76 | return this;
77 | }
78 |
79 | public Builder setOurBaseKey(ECKeyPair ourBaseKey) {
80 | this.ourBaseKey = ourBaseKey;
81 | return this;
82 | }
83 |
84 | public Builder setTheirRatchetKey(ECPublicKey theirRatchetKey) {
85 | this.theirRatchetKey = theirRatchetKey;
86 | return this;
87 | }
88 |
89 | public Builder setTheirIdentityKey(IdentityKey theirIdentityKey) {
90 | this.theirIdentityKey = theirIdentityKey;
91 | return this;
92 | }
93 |
94 | public Builder setTheirSignedPreKey(ECPublicKey theirSignedPreKey) {
95 | this.theirSignedPreKey = theirSignedPreKey;
96 | return this;
97 | }
98 |
99 | public Builder setTheirOneTimePreKey(Optional theirOneTimePreKey) {
100 | this.theirOneTimePreKey = theirOneTimePreKey;
101 | return this;
102 | }
103 |
104 | public AliceAxolotlParameters create() {
105 | return new AliceAxolotlParameters(ourIdentityKey, ourBaseKey, theirIdentityKey,
106 | theirSignedPreKey, theirRatchetKey, theirOneTimePreKey);
107 | }
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/ratchet/BobAxolotlParameters.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libaxolotl.ratchet;
2 |
3 | import org.whispersystems.libaxolotl.IdentityKey;
4 | import org.whispersystems.libaxolotl.IdentityKeyPair;
5 | import org.whispersystems.libaxolotl.ecc.ECKeyPair;
6 | import org.whispersystems.libaxolotl.ecc.ECPublicKey;
7 | import org.whispersystems.libaxolotl.util.guava.Optional;
8 |
9 | public class BobAxolotlParameters {
10 |
11 | private final IdentityKeyPair ourIdentityKey;
12 | private final ECKeyPair ourSignedPreKey;
13 | private final Optional ourOneTimePreKey;
14 | private final ECKeyPair ourRatchetKey;
15 |
16 | private final IdentityKey theirIdentityKey;
17 | private final ECPublicKey theirBaseKey;
18 |
19 | BobAxolotlParameters(IdentityKeyPair ourIdentityKey, ECKeyPair ourSignedPreKey,
20 | ECKeyPair ourRatchetKey, Optional ourOneTimePreKey,
21 | IdentityKey theirIdentityKey, ECPublicKey theirBaseKey)
22 | {
23 | this.ourIdentityKey = ourIdentityKey;
24 | this.ourSignedPreKey = ourSignedPreKey;
25 | this.ourRatchetKey = ourRatchetKey;
26 | this.ourOneTimePreKey = ourOneTimePreKey;
27 | this.theirIdentityKey = theirIdentityKey;
28 | this.theirBaseKey = theirBaseKey;
29 |
30 | if (ourIdentityKey == null || ourSignedPreKey == null || ourRatchetKey == null ||
31 | ourOneTimePreKey == null || theirIdentityKey == null || theirBaseKey == null)
32 | {
33 | throw new IllegalArgumentException("Null value!");
34 | }
35 | }
36 |
37 | public IdentityKeyPair getOurIdentityKey() {
38 | return ourIdentityKey;
39 | }
40 |
41 | public ECKeyPair getOurSignedPreKey() {
42 | return ourSignedPreKey;
43 | }
44 |
45 | public Optional getOurOneTimePreKey() {
46 | return ourOneTimePreKey;
47 | }
48 |
49 | public IdentityKey getTheirIdentityKey() {
50 | return theirIdentityKey;
51 | }
52 |
53 | public ECPublicKey getTheirBaseKey() {
54 | return theirBaseKey;
55 | }
56 |
57 | public static Builder newBuilder() {
58 | return new Builder();
59 | }
60 |
61 | public ECKeyPair getOurRatchetKey() {
62 | return ourRatchetKey;
63 | }
64 |
65 | public static class Builder {
66 | private IdentityKeyPair ourIdentityKey;
67 | private ECKeyPair ourSignedPreKey;
68 | private Optional ourOneTimePreKey;
69 | private ECKeyPair ourRatchetKey;
70 |
71 | private IdentityKey theirIdentityKey;
72 | private ECPublicKey theirBaseKey;
73 |
74 | public Builder setOurIdentityKey(IdentityKeyPair ourIdentityKey) {
75 | this.ourIdentityKey = ourIdentityKey;
76 | return this;
77 | }
78 |
79 | public Builder setOurSignedPreKey(ECKeyPair ourSignedPreKey) {
80 | this.ourSignedPreKey = ourSignedPreKey;
81 | return this;
82 | }
83 |
84 | public Builder setOurOneTimePreKey(Optional ourOneTimePreKey) {
85 | this.ourOneTimePreKey = ourOneTimePreKey;
86 | return this;
87 | }
88 |
89 | public Builder setTheirIdentityKey(IdentityKey theirIdentityKey) {
90 | this.theirIdentityKey = theirIdentityKey;
91 | return this;
92 | }
93 |
94 | public Builder setTheirBaseKey(ECPublicKey theirBaseKey) {
95 | this.theirBaseKey = theirBaseKey;
96 | return this;
97 | }
98 |
99 | public Builder setOurRatchetKey(ECKeyPair ourRatchetKey) {
100 | this.ourRatchetKey = ourRatchetKey;
101 | return this;
102 | }
103 |
104 | public BobAxolotlParameters create() {
105 | return new BobAxolotlParameters(ourIdentityKey, ourSignedPreKey, ourRatchetKey,
106 | ourOneTimePreKey, theirIdentityKey, theirBaseKey);
107 | }
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/ratchet/ChainKey.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.libaxolotl.ratchet;
18 |
19 |
20 | import org.whispersystems.libaxolotl.j2me.jce.JmeSecurity;
21 | import org.whispersystems.libaxolotl.j2me.jce.mac.Mac;
22 | import org.whispersystems.libaxolotl.kdf.DerivedMessageSecrets;
23 | import org.whispersystems.libaxolotl.kdf.HKDF;
24 |
25 | public class ChainKey {
26 |
27 | private static final byte[] MESSAGE_KEY_SEED = {0x01};
28 | private static final byte[] CHAIN_KEY_SEED = {0x02};
29 |
30 | private final HKDF kdf;
31 | private final byte[] key;
32 | private final int index;
33 |
34 | public ChainKey(HKDF kdf, byte[] key, int index) {
35 | this.kdf = kdf;
36 | this.key = key;
37 | this.index = index;
38 | }
39 |
40 | public byte[] getKey() {
41 | return key;
42 | }
43 |
44 | public int getIndex() {
45 | return index;
46 | }
47 |
48 | public ChainKey getNextChainKey() {
49 | byte[] nextKey = getBaseMaterial(CHAIN_KEY_SEED);
50 | return new ChainKey(kdf, nextKey, index + 1);
51 | }
52 |
53 | public MessageKeys getMessageKeys() {
54 | byte[] inputKeyMaterial = getBaseMaterial(MESSAGE_KEY_SEED);
55 | byte[] keyMaterialBytes = kdf.deriveSecrets(inputKeyMaterial, "WhisperMessageKeys".getBytes(), DerivedMessageSecrets.SIZE);
56 | DerivedMessageSecrets keyMaterial = new DerivedMessageSecrets(keyMaterialBytes);
57 |
58 | return new MessageKeys(keyMaterial.getCipherKey(), keyMaterial.getMacKey(), keyMaterial.getIv(), index);
59 | }
60 |
61 | private byte[] getBaseMaterial(byte[] seed) {
62 | Mac mac = JmeSecurity.getProvider().createMacSha256(key);
63 | byte[] output = new byte[32];
64 |
65 | mac.update(seed, 0, seed.length);
66 | mac.doFinal(output, 0);
67 |
68 | return output;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/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.libaxolotl.ratchet;
18 |
19 | import org.bouncycastle.crypto.params.KeyParameter;
20 | import org.bouncycastle.crypto.params.ParametersWithIV;
21 |
22 | public class MessageKeys {
23 |
24 | private final KeyParameter cipherKey;
25 | private final KeyParameter macKey;
26 | private final ParametersWithIV iv;
27 | private final int counter;
28 |
29 | public MessageKeys(KeyParameter cipherKey, KeyParameter macKey, ParametersWithIV iv, int counter) {
30 | this.cipherKey = cipherKey;
31 | this.macKey = macKey;
32 | this.iv = iv;
33 | this.counter = counter;
34 | }
35 |
36 | public KeyParameter getCipherKey() {
37 | return cipherKey;
38 | }
39 |
40 | public KeyParameter getMacKey() {
41 | return macKey;
42 | }
43 |
44 | public ParametersWithIV getIv() {
45 | return iv;
46 | }
47 |
48 | public int getCounter() {
49 | return counter;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/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.libaxolotl.ratchet;
18 |
19 | import org.whispersystems.libaxolotl.InvalidKeyException;
20 | import org.whispersystems.libaxolotl.ecc.Curve;
21 | import org.whispersystems.libaxolotl.ecc.ECKeyPair;
22 | import org.whispersystems.libaxolotl.ecc.ECPublicKey;
23 | import org.whispersystems.libaxolotl.kdf.DerivedRootSecrets;
24 | import org.whispersystems.libaxolotl.kdf.HKDF;
25 | import org.whispersystems.libaxolotl.util.Pair;
26 |
27 | public class RootKey {
28 |
29 | private final HKDF kdf;
30 | private final byte[] key;
31 |
32 | public RootKey(HKDF kdf, byte[] key) {
33 | this.kdf = kdf;
34 | this.key = key;
35 | }
36 |
37 | public byte[] getKeyBytes() {
38 | return key;
39 | }
40 |
41 | public Pair createChain(ECPublicKey theirRatchetKey, ECKeyPair ourRatchetKey)
42 | throws InvalidKeyException
43 | {
44 | byte[] sharedSecret = Curve.calculateAgreement(theirRatchetKey, ourRatchetKey.getPrivateKey());
45 | byte[] derivedSecretBytes = kdf.deriveSecrets(sharedSecret, key, "WhisperRatchet".getBytes(), DerivedRootSecrets.SIZE);
46 | DerivedRootSecrets derivedSecrets = new DerivedRootSecrets(derivedSecretBytes);
47 |
48 | RootKey newRootKey = new RootKey(kdf, derivedSecrets.getRootKey());
49 | ChainKey newChainKey = new ChainKey(kdf, derivedSecrets.getChainKey(), 0);
50 |
51 | return new Pair(newRootKey, newChainKey);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/ratchet/SymmetricAxolotlParameters.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libaxolotl.ratchet;
2 |
3 | import org.whispersystems.libaxolotl.IdentityKey;
4 | import org.whispersystems.libaxolotl.IdentityKeyPair;
5 | import org.whispersystems.libaxolotl.ecc.ECKeyPair;
6 | import org.whispersystems.libaxolotl.ecc.ECPublicKey;
7 |
8 | public class SymmetricAxolotlParameters {
9 |
10 | private final ECKeyPair ourBaseKey;
11 | private final ECKeyPair ourRatchetKey;
12 | private final IdentityKeyPair ourIdentityKey;
13 |
14 | private final ECPublicKey theirBaseKey;
15 | private final ECPublicKey theirRatchetKey;
16 | private final IdentityKey theirIdentityKey;
17 |
18 | SymmetricAxolotlParameters(ECKeyPair ourBaseKey, ECKeyPair ourRatchetKey,
19 | IdentityKeyPair ourIdentityKey, ECPublicKey theirBaseKey,
20 | ECPublicKey theirRatchetKey, IdentityKey theirIdentityKey)
21 | {
22 | this.ourBaseKey = ourBaseKey;
23 | this.ourRatchetKey = ourRatchetKey;
24 | this.ourIdentityKey = ourIdentityKey;
25 | this.theirBaseKey = theirBaseKey;
26 | this.theirRatchetKey = theirRatchetKey;
27 | this.theirIdentityKey = theirIdentityKey;
28 |
29 | if (ourBaseKey == null || ourRatchetKey == null || ourIdentityKey == null ||
30 | theirBaseKey == null || theirRatchetKey == null || theirIdentityKey == null)
31 | {
32 | throw new IllegalArgumentException("Null values!");
33 | }
34 | }
35 |
36 | public ECKeyPair getOurBaseKey() {
37 | return ourBaseKey;
38 | }
39 |
40 | public ECKeyPair getOurRatchetKey() {
41 | return ourRatchetKey;
42 | }
43 |
44 | public IdentityKeyPair getOurIdentityKey() {
45 | return ourIdentityKey;
46 | }
47 |
48 | public ECPublicKey getTheirBaseKey() {
49 | return theirBaseKey;
50 | }
51 |
52 | public ECPublicKey getTheirRatchetKey() {
53 | return theirRatchetKey;
54 | }
55 |
56 | public IdentityKey getTheirIdentityKey() {
57 | return theirIdentityKey;
58 | }
59 |
60 | public static Builder newBuilder() {
61 | return new Builder();
62 | }
63 |
64 | public static class Builder {
65 | private ECKeyPair ourBaseKey;
66 | private ECKeyPair ourRatchetKey;
67 | private IdentityKeyPair ourIdentityKey;
68 |
69 | private ECPublicKey theirBaseKey;
70 | private ECPublicKey theirRatchetKey;
71 | private IdentityKey theirIdentityKey;
72 |
73 | public Builder setOurBaseKey(ECKeyPair ourBaseKey) {
74 | this.ourBaseKey = ourBaseKey;
75 | return this;
76 | }
77 |
78 | public Builder setOurRatchetKey(ECKeyPair ourRatchetKey) {
79 | this.ourRatchetKey = ourRatchetKey;
80 | return this;
81 | }
82 |
83 | public Builder setOurIdentityKey(IdentityKeyPair ourIdentityKey) {
84 | this.ourIdentityKey = ourIdentityKey;
85 | return this;
86 | }
87 |
88 | public Builder setTheirBaseKey(ECPublicKey theirBaseKey) {
89 | this.theirBaseKey = theirBaseKey;
90 | return this;
91 | }
92 |
93 | public Builder setTheirRatchetKey(ECPublicKey theirRatchetKey) {
94 | this.theirRatchetKey = theirRatchetKey;
95 | return this;
96 | }
97 |
98 | public Builder setTheirIdentityKey(IdentityKey theirIdentityKey) {
99 | this.theirIdentityKey = theirIdentityKey;
100 | return this;
101 | }
102 |
103 | public SymmetricAxolotlParameters create() {
104 | return new SymmetricAxolotlParameters(ourBaseKey, ourRatchetKey, ourIdentityKey,
105 | theirBaseKey, theirRatchetKey, theirIdentityKey);
106 | }
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/state/AxolotlStore.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libaxolotl.state;
2 |
3 | public interface AxolotlStore
4 | extends IdentityKeyStore, PreKeyStore, SessionStore, SignedPreKeyStore
5 | {
6 | }
7 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/state/IdentityKeyStore.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libaxolotl.state;
2 |
3 | import org.whispersystems.libaxolotl.IdentityKey;
4 | import org.whispersystems.libaxolotl.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 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/state/PreKeyBundle.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libaxolotl.state;
2 |
3 | import org.whispersystems.libaxolotl.IdentityKey;
4 | import org.whispersystems.libaxolotl.ecc.ECPublicKey;
5 |
6 | /**
7 | * A class that contains a remote PreKey and collection
8 | * of associated items.
9 | *
10 | * @author Moxie Marlinspike
11 | */
12 | public class PreKeyBundle {
13 |
14 | private int registrationId;
15 |
16 | private int deviceId;
17 |
18 | private int preKeyId;
19 | private ECPublicKey preKeyPublic;
20 |
21 | private int signedPreKeyId;
22 | private ECPublicKey signedPreKeyPublic;
23 | private byte[] signedPreKeySignature;
24 |
25 | private IdentityKey identityKey;
26 |
27 | public PreKeyBundle(int registrationId, int deviceId, int preKeyId, ECPublicKey preKeyPublic,
28 | int signedPreKeyId, ECPublicKey signedPreKeyPublic, byte[] signedPreKeySignature,
29 | IdentityKey identityKey)
30 | {
31 | this.registrationId = registrationId;
32 | this.deviceId = deviceId;
33 | this.preKeyId = preKeyId;
34 | this.preKeyPublic = preKeyPublic;
35 | this.signedPreKeyId = signedPreKeyId;
36 | this.signedPreKeyPublic = signedPreKeyPublic;
37 | this.signedPreKeySignature = signedPreKeySignature;
38 | this.identityKey = identityKey;
39 | }
40 |
41 | /**
42 | * @return the device ID this PreKey belongs to.
43 | */
44 | public int getDeviceId() {
45 | return deviceId;
46 | }
47 |
48 | /**
49 | * @return the unique key ID for this PreKey.
50 | */
51 | public int getPreKeyId() {
52 | return preKeyId;
53 | }
54 |
55 | /**
56 | * @return the public key for this PreKey.
57 | */
58 | public ECPublicKey getPreKey() {
59 | return preKeyPublic;
60 | }
61 |
62 | /**
63 | * @return the unique key ID for this signed prekey.
64 | */
65 | public int getSignedPreKeyId() {
66 | return signedPreKeyId;
67 | }
68 |
69 | /**
70 | * @return the signed prekey for this PreKeyBundle.
71 | */
72 | public ECPublicKey getSignedPreKey() {
73 | return signedPreKeyPublic;
74 | }
75 |
76 | /**
77 | * @return the signature over the signed prekey.
78 | */
79 | public byte[] getSignedPreKeySignature() {
80 | return signedPreKeySignature;
81 | }
82 |
83 | /**
84 | * @return the {@link org.whispersystems.libaxolotl.IdentityKey} of this PreKeys owner.
85 | */
86 | public IdentityKey getIdentityKey() {
87 | return identityKey;
88 | }
89 |
90 | /**
91 | * @return the registration ID associated with this PreKey.
92 | */
93 | public int getRegistrationId() {
94 | return registrationId;
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/state/PreKeyRecord.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libaxolotl.state;
2 |
3 |
4 | import org.whispersystems.libaxolotl.InvalidKeyException;
5 | import org.whispersystems.libaxolotl.ecc.Curve;
6 | import org.whispersystems.libaxolotl.ecc.ECKeyPair;
7 | import org.whispersystems.libaxolotl.ecc.ECPrivateKey;
8 | import org.whispersystems.libaxolotl.ecc.ECPublicKey;
9 | import org.whispersystems.libaxolotl.state.protos.PreKeyRecordStructure;
10 | import org.whispersystems.libaxolotl.j2me.AssertionError;
11 |
12 | import java.io.IOException;
13 |
14 |
15 | public class PreKeyRecord {
16 |
17 | private PreKeyRecordStructure structure;
18 |
19 | public PreKeyRecord(int id, ECKeyPair keyPair) {
20 | this.structure = new PreKeyRecordStructure();
21 | this.structure.setId(id);
22 | this.structure.setPublickey(keyPair.getPublicKey().serialize());
23 | this.structure.setPrivatekey(keyPair.getPrivateKey().serialize());
24 | }
25 |
26 | public PreKeyRecord(byte[] serialized) throws IOException {
27 | this.structure = PreKeyRecordStructure.fromBytes(serialized);
28 | }
29 |
30 | public int getId() {
31 | return this.structure.getId();
32 | }
33 |
34 | public ECKeyPair getKeyPair() {
35 | try {
36 | ECPublicKey publicKey = Curve.decodePoint (this.structure.getPublickey (), 0);
37 | ECPrivateKey privateKey = Curve.decodePrivatePoint(this.structure.getPrivatekey() );
38 |
39 | return new ECKeyPair(publicKey, privateKey);
40 | } catch (InvalidKeyException e) {
41 | throw new AssertionError(e);
42 | }
43 | }
44 |
45 | public byte[] serialize() {
46 | return this.structure.toBytes();
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/state/PreKeyStore.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libaxolotl.state;
2 |
3 | import org.whispersystems.libaxolotl.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 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/state/SessionRecord.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libaxolotl.state;
2 |
3 | import org.whispersystems.libaxolotl.state.protos.RecordStructure;
4 | import org.whispersystems.libaxolotl.state.protos.SessionStructure;
5 | import org.whispersystems.libaxolotl.j2me.Arrays;
6 |
7 | import java.io.IOException;
8 | import java.util.Vector;
9 |
10 |
11 | /**
12 | * A SessionRecord encapsulates the state of an ongoing session.
13 | *
14 | * @author Moxie Marlinspike
15 | */
16 | public class SessionRecord {
17 |
18 | private static final int ARCHIVED_STATES_MAX_LENGTH = 40;
19 |
20 | private SessionState sessionState = new SessionState();
21 | private Vector previousStates = new Vector();
22 | private boolean fresh = false;
23 |
24 | public SessionRecord() {
25 | this.fresh = true;
26 | }
27 |
28 | public SessionRecord(SessionState sessionState) {
29 | this.sessionState = sessionState;
30 | this.fresh = false;
31 | }
32 |
33 | public SessionRecord(byte[] serialized) throws IOException {
34 | RecordStructure record = RecordStructure.fromBytes(serialized);
35 | this.sessionState = new SessionState(record.getCurrentsession());
36 | this.fresh = false;
37 |
38 | for (int i=0;i ARCHIVED_STATES_MAX_LENGTH) {
92 | previousStates.removeElementAt(previousStates.size() - 1);
93 | }
94 | }
95 |
96 | public void setState(SessionState sessionState) {
97 | this.sessionState = sessionState;
98 | }
99 |
100 | /**
101 | * @return a serialized version of the current SessionRecord.
102 | */
103 | public byte[] serialize() {
104 | RecordStructure record = new RecordStructure();
105 | record.setCurrentsession(sessionState.getStructure());
106 |
107 | for (int i=0;i
19 | * It is important that implementations return a copy of the current durable information. The
20 | * returned SessionRecord may be modified, but those changes should not have an effect on the
21 | * durable session state (what is returned by subsequent calls to this method) without the
22 | * store method being called here first.
23 | *
24 | * @param address The name and device ID of the remote client.
25 | * @return a copy of the SessionRecord corresponding to the recipientId + deviceId tuple, or
26 | * a new SessionRecord if one does not currently exist.
27 | */
28 | public SessionRecord loadSession(AxolotlAddress address);
29 |
30 | /**
31 | * Returns all known devices with active sessions for a recipient
32 | *
33 | * @param name the name of the client.
34 | * @return all known sub-devices with active sessions.
35 | */
36 | public Vector getSubDeviceSessions(String name);
37 |
38 | /**
39 | * Commit to storage the {@link SessionRecord} for a given recipientId + deviceId tuple.
40 | * @param address the address of the remote client.
41 | * @param record the current SessionRecord for the remote client.
42 | */
43 | public void storeSession(AxolotlAddress address, SessionRecord record);
44 |
45 | /**
46 | * Determine whether there is a committed {@link SessionRecord} for a recipientId + deviceId tuple.
47 | * @param address the address of the remote client.
48 | * @return true if a {@link SessionRecord} exists, false otherwise.
49 | */
50 | public boolean containsSession(AxolotlAddress address);
51 |
52 | /**
53 | * Remove a {@link SessionRecord} for a recipientId + deviceId tuple.
54 | *
55 | * @param address the address of the remote client.
56 | */
57 | public void deleteSession(AxolotlAddress address);
58 |
59 | /**
60 | * Remove the {@link SessionRecord}s corresponding to all devices of a recipientId.
61 | *
62 | * @param name the name of the remote client.
63 | */
64 | public void deleteAllSessions(String name);
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/state/SignedPreKeyRecord.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libaxolotl.state;
2 |
3 | import org.whispersystems.libaxolotl.InvalidKeyException;
4 | import org.whispersystems.libaxolotl.ecc.Curve;
5 | import org.whispersystems.libaxolotl.ecc.ECKeyPair;
6 | import org.whispersystems.libaxolotl.ecc.ECPrivateKey;
7 | import org.whispersystems.libaxolotl.ecc.ECPublicKey;
8 | import org.whispersystems.libaxolotl.state.protos.SignedPreKeyRecordStructure;
9 | import org.whispersystems.libaxolotl.j2me.AssertionError;
10 |
11 | import java.io.IOException;
12 |
13 |
14 | public class SignedPreKeyRecord {
15 |
16 | private SignedPreKeyRecordStructure structure;
17 |
18 | public SignedPreKeyRecord(int id, long timestamp, ECKeyPair keyPair, byte[] signature) {
19 | this.structure = new SignedPreKeyRecordStructure();
20 | structure.setId(id);
21 | structure.setPublickey(keyPair.getPublicKey().serialize());
22 | structure.setPrivatekey(keyPair.getPrivateKey().serialize());
23 | structure.setSignature(signature);
24 | structure.setTimestamp(timestamp);
25 | }
26 |
27 | public SignedPreKeyRecord(byte[] serialized) throws IOException {
28 | this.structure = SignedPreKeyRecordStructure.fromBytes(serialized);
29 | }
30 |
31 | public int getId() {
32 | return this.structure.getId();
33 | }
34 |
35 | public long getTimestamp() {
36 | return this.structure.getTimestamp();
37 | }
38 |
39 | public ECKeyPair getKeyPair() {
40 | try {
41 | ECPublicKey publicKey = Curve.decodePoint(this.structure.getPublickey(), 0);
42 | ECPrivateKey privateKey = Curve.decodePrivatePoint(this.structure.getPrivatekey());
43 |
44 | return new ECKeyPair(publicKey, privateKey);
45 | } catch (InvalidKeyException e) {
46 | throw new AssertionError(e);
47 | }
48 | }
49 |
50 | public byte[] getSignature() {
51 | return this.structure.getSignature();
52 | }
53 |
54 | public byte[] serialize() {
55 | return this.structure.toBytes();
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/state/SignedPreKeyStore.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libaxolotl.state;
2 |
3 | import org.whispersystems.libaxolotl.InvalidKeyIdException;
4 |
5 | import java.util.Vector;
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 Vector 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 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/state/protos/IdentityKeyPairStructure.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libaxolotl.state.protos;
2 |
3 | import java.util.Vector;
4 | import java.io.IOException;
5 |
6 | import com.ponderingpanda.protobuf.*;
7 |
8 |
9 | public class IdentityKeyPairStructure implements Message {
10 |
11 |
12 |
13 | protected byte[] publickey; // 1
14 | protected boolean _hasPublickey;
15 | protected byte[] privatekey; // 2
16 | protected boolean _hasPrivatekey;
17 |
18 | public byte[] getPublickey() {
19 | return publickey;
20 | }
21 |
22 | public void setPublickey(byte[] publickey) {
23 | this.publickey = publickey;
24 | this._hasPublickey = true;
25 | }
26 |
27 | public void clearPublickey() {
28 | _hasPublickey = false;
29 | }
30 |
31 | public boolean hasPublickey() {
32 | return _hasPublickey;
33 | }
34 | public byte[] getPrivatekey() {
35 | return privatekey;
36 | }
37 |
38 | public void setPrivatekey(byte[] privatekey) {
39 | this.privatekey = privatekey;
40 | this._hasPrivatekey = true;
41 | }
42 |
43 | public void clearPrivatekey() {
44 | _hasPrivatekey = false;
45 | }
46 |
47 | public boolean hasPrivatekey() {
48 | return _hasPrivatekey;
49 | }
50 |
51 | public final void serialize(CodedOutputStream out) throws IOException {
52 | if(_hasPublickey)
53 | out.writeBytes(1, publickey);
54 |
55 | if(_hasPrivatekey)
56 | out.writeBytes(2, privatekey);
57 |
58 | }
59 |
60 | public final void deserialize(CodedInputStream in) throws IOException {
61 | while(true) {
62 | int tag = in.readTag();
63 | switch(tag) {
64 | case 0:
65 | return;
66 | case 10: {
67 | publickey = in.readBytes();
68 | _hasPublickey = true;
69 | break; }
70 | case 18: {
71 | privatekey = in.readBytes();
72 | _hasPrivatekey = true;
73 | break; }
74 | default:
75 | in.skipTag(tag);
76 | }
77 | }
78 | }
79 |
80 | public static IdentityKeyPairStructure fromBytes(byte[] in) throws EncodingException {
81 | IdentityKeyPairStructure message = new IdentityKeyPairStructure();
82 | ProtoUtil.messageFromBytes(in, message);
83 | return message;
84 | }
85 |
86 | public byte[] toBytes() throws EncodingException {
87 | return ProtoUtil.messageToBytes(this);
88 | }
89 |
90 |
91 | }
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/state/protos/PreKeyRecordStructure.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libaxolotl.state.protos;
2 |
3 | import java.util.Vector;
4 | import java.io.IOException;
5 |
6 | import com.ponderingpanda.protobuf.*;
7 |
8 |
9 | public class PreKeyRecordStructure implements Message {
10 |
11 |
12 |
13 | protected int id; // 1
14 | protected boolean _hasId;
15 | protected byte[] publickey; // 2
16 | protected boolean _hasPublickey;
17 | protected byte[] privatekey; // 3
18 | protected boolean _hasPrivatekey;
19 |
20 | public int getId() {
21 | return id;
22 | }
23 |
24 | public void setId(int id) {
25 | this.id = id;
26 | this._hasId = true;
27 | }
28 |
29 | public void clearId() {
30 | _hasId = false;
31 | }
32 |
33 | public boolean hasId() {
34 | return _hasId;
35 | }
36 | public byte[] getPublickey() {
37 | return publickey;
38 | }
39 |
40 | public void setPublickey(byte[] publickey) {
41 | this.publickey = publickey;
42 | this._hasPublickey = true;
43 | }
44 |
45 | public void clearPublickey() {
46 | _hasPublickey = false;
47 | }
48 |
49 | public boolean hasPublickey() {
50 | return _hasPublickey;
51 | }
52 | public byte[] getPrivatekey() {
53 | return privatekey;
54 | }
55 |
56 | public void setPrivatekey(byte[] privatekey) {
57 | this.privatekey = privatekey;
58 | this._hasPrivatekey = true;
59 | }
60 |
61 | public void clearPrivatekey() {
62 | _hasPrivatekey = false;
63 | }
64 |
65 | public boolean hasPrivatekey() {
66 | return _hasPrivatekey;
67 | }
68 |
69 | public final void serialize(CodedOutputStream out) throws IOException {
70 | if(_hasId)
71 | out.writeUInt32(1, id);
72 |
73 | if(_hasPublickey)
74 | out.writeBytes(2, publickey);
75 |
76 | if(_hasPrivatekey)
77 | out.writeBytes(3, privatekey);
78 |
79 | }
80 |
81 | public final void deserialize(CodedInputStream in) throws IOException {
82 | while(true) {
83 | int tag = in.readTag();
84 | switch(tag) {
85 | case 0:
86 | return;
87 | case 8: {
88 | id = in.readUInt32();
89 | _hasId = true;
90 | break; }
91 | case 18: {
92 | publickey = in.readBytes();
93 | _hasPublickey = true;
94 | break; }
95 | case 26: {
96 | privatekey = in.readBytes();
97 | _hasPrivatekey = true;
98 | break; }
99 | default:
100 | in.skipTag(tag);
101 | }
102 | }
103 | }
104 |
105 | public static PreKeyRecordStructure fromBytes(byte[] in) throws EncodingException {
106 | PreKeyRecordStructure message = new PreKeyRecordStructure();
107 | ProtoUtil.messageFromBytes(in, message);
108 | return message;
109 | }
110 |
111 | public byte[] toBytes() throws EncodingException {
112 | return ProtoUtil.messageToBytes(this);
113 | }
114 |
115 |
116 | }
117 |
118 |
119 |
120 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/state/protos/RecordStructure.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libaxolotl.state.protos;
2 |
3 | import java.util.Vector;
4 | import java.io.IOException;
5 |
6 | import com.ponderingpanda.protobuf.*;
7 |
8 |
9 | public class RecordStructure implements Message {
10 |
11 |
12 |
13 | protected SessionStructure currentsession; // 1
14 | protected Vector previoussessions = new Vector(); // 2
15 |
16 | public SessionStructure getCurrentsession() {
17 | return currentsession;
18 | }
19 |
20 | public void setCurrentsession(SessionStructure currentsession) {
21 | this.currentsession = currentsession;
22 | }
23 |
24 | public void clearCurrentsession() {
25 | currentsession = null;
26 | }
27 |
28 | public boolean hasCurrentsession() {
29 | return currentsession != null;
30 | }
31 | public void addPrevioussessions(SessionStructure value) {
32 | this.previoussessions.addElement(value);
33 | }
34 |
35 | public int getPrevioussessionsCount() {
36 | return this.previoussessions.size();
37 | }
38 |
39 | public SessionStructure getPrevioussessions(int index) {
40 | return (SessionStructure)this.previoussessions.elementAt(index);
41 | }
42 |
43 | public Vector getPrevioussessionsVector() {
44 | return this.previoussessions;
45 | }
46 |
47 | public void setPrevioussessionsVector(Vector value) {
48 | this.previoussessions = value;
49 | }
50 |
51 | public final void serialize(CodedOutputStream out) throws IOException {
52 | out.writeMessage(1, currentsession);
53 |
54 | for(int i = 0; i < getPrevioussessionsCount(); i++) {
55 | out.writeMessage(2, getPrevioussessions(i));
56 | }
57 |
58 | }
59 |
60 | public final void deserialize(CodedInputStream in) throws IOException {
61 | while(true) {
62 | int tag = in.readTag();
63 | switch(tag) {
64 | case 0:
65 | return;
66 | case 10: {
67 | currentsession = new SessionStructure();
68 | in.readMessage(currentsession);
69 | break; }
70 | case 18: {
71 | SessionStructure message = new SessionStructure();
72 | in.readMessage(message);
73 | addPrevioussessions(message);
74 | break; }
75 | default:
76 | in.skipTag(tag);
77 | }
78 | }
79 | }
80 |
81 | public static RecordStructure fromBytes(byte[] in) throws EncodingException {
82 | RecordStructure message = new RecordStructure();
83 | ProtoUtil.messageFromBytes(in, message);
84 | return message;
85 | }
86 |
87 | public byte[] toBytes() throws EncodingException {
88 | return ProtoUtil.messageToBytes(this);
89 | }
90 |
91 |
92 | }
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/state/protos/SenderKeyRecordStructure.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libaxolotl.state.protos;
2 |
3 | import java.util.Vector;
4 | import java.io.IOException;
5 |
6 | import com.ponderingpanda.protobuf.*;
7 |
8 |
9 | public class SenderKeyRecordStructure implements Message {
10 |
11 |
12 |
13 | protected Vector senderkeystates = new Vector(); // 1
14 |
15 | public void addSenderkeystates(SenderKeyStateStructure value) {
16 | this.senderkeystates.addElement(value);
17 | }
18 |
19 | public int getSenderkeystatesCount() {
20 | return this.senderkeystates.size();
21 | }
22 |
23 | public SenderKeyStateStructure getSenderkeystates(int index) {
24 | return (SenderKeyStateStructure)this.senderkeystates.elementAt(index);
25 | }
26 |
27 | public Vector getSenderkeystatesVector() {
28 | return this.senderkeystates;
29 | }
30 |
31 | public void setSenderkeystatesVector(Vector value) {
32 | this.senderkeystates = value;
33 | }
34 |
35 | public final void serialize(CodedOutputStream out) throws IOException {
36 | for(int i = 0; i < getSenderkeystatesCount(); i++) {
37 | out.writeMessage(1, getSenderkeystates(i));
38 | }
39 |
40 | }
41 |
42 | public final void deserialize(CodedInputStream in) throws IOException {
43 | while(true) {
44 | int tag = in.readTag();
45 | switch(tag) {
46 | case 0:
47 | return;
48 | case 10: {
49 | SenderKeyStateStructure message = new SenderKeyStateStructure();
50 | in.readMessage(message);
51 | addSenderkeystates(message);
52 | break; }
53 | default:
54 | in.skipTag(tag);
55 | }
56 | }
57 | }
58 |
59 | public static SenderKeyRecordStructure fromBytes(byte[] in) throws EncodingException {
60 | SenderKeyRecordStructure message = new SenderKeyRecordStructure();
61 | ProtoUtil.messageFromBytes(in, message);
62 | return message;
63 | }
64 |
65 | public byte[] toBytes() throws EncodingException {
66 | return ProtoUtil.messageToBytes(this);
67 | }
68 |
69 |
70 | }
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/state/protos/SignedPreKeyRecordStructure.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libaxolotl.state.protos;
2 |
3 | import java.util.Vector;
4 | import java.io.IOException;
5 |
6 | import com.ponderingpanda.protobuf.*;
7 |
8 |
9 | public class SignedPreKeyRecordStructure implements Message {
10 |
11 |
12 |
13 | protected int id; // 1
14 | protected boolean _hasId;
15 | protected byte[] publickey; // 2
16 | protected boolean _hasPublickey;
17 | protected byte[] privatekey; // 3
18 | protected boolean _hasPrivatekey;
19 | protected byte[] signature; // 4
20 | protected boolean _hasSignature;
21 | protected long timestamp; // 5
22 | protected boolean _hasTimestamp;
23 |
24 | public int getId() {
25 | return id;
26 | }
27 |
28 | public void setId(int id) {
29 | this.id = id;
30 | this._hasId = true;
31 | }
32 |
33 | public void clearId() {
34 | _hasId = false;
35 | }
36 |
37 | public boolean hasId() {
38 | return _hasId;
39 | }
40 | public byte[] getPublickey() {
41 | return publickey;
42 | }
43 |
44 | public void setPublickey(byte[] publickey) {
45 | this.publickey = publickey;
46 | this._hasPublickey = true;
47 | }
48 |
49 | public void clearPublickey() {
50 | _hasPublickey = false;
51 | }
52 |
53 | public boolean hasPublickey() {
54 | return _hasPublickey;
55 | }
56 | public byte[] getPrivatekey() {
57 | return privatekey;
58 | }
59 |
60 | public void setPrivatekey(byte[] privatekey) {
61 | this.privatekey = privatekey;
62 | this._hasPrivatekey = true;
63 | }
64 |
65 | public void clearPrivatekey() {
66 | _hasPrivatekey = false;
67 | }
68 |
69 | public boolean hasPrivatekey() {
70 | return _hasPrivatekey;
71 | }
72 | public byte[] getSignature() {
73 | return signature;
74 | }
75 |
76 | public void setSignature(byte[] signature) {
77 | this.signature = signature;
78 | this._hasSignature = true;
79 | }
80 |
81 | public void clearSignature() {
82 | _hasSignature = false;
83 | }
84 |
85 | public boolean hasSignature() {
86 | return _hasSignature;
87 | }
88 | public long getTimestamp() {
89 | return timestamp;
90 | }
91 |
92 | public void setTimestamp(long timestamp) {
93 | this.timestamp = timestamp;
94 | this._hasTimestamp = true;
95 | }
96 |
97 | public void clearTimestamp() {
98 | _hasTimestamp = false;
99 | }
100 |
101 | public boolean hasTimestamp() {
102 | return _hasTimestamp;
103 | }
104 |
105 | public final void serialize(CodedOutputStream out) throws IOException {
106 | if(_hasId)
107 | out.writeUInt32(1, id);
108 |
109 | if(_hasPublickey)
110 | out.writeBytes(2, publickey);
111 |
112 | if(_hasPrivatekey)
113 | out.writeBytes(3, privatekey);
114 |
115 | if(_hasSignature)
116 | out.writeBytes(4, signature);
117 |
118 | if(_hasTimestamp)
119 | out.writeFixed64(5, timestamp);
120 |
121 | }
122 |
123 | public final void deserialize(CodedInputStream in) throws IOException {
124 | while(true) {
125 | int tag = in.readTag();
126 | switch(tag) {
127 | case 0:
128 | return;
129 | case 8: {
130 | id = in.readUInt32();
131 | _hasId = true;
132 | break; }
133 | case 18: {
134 | publickey = in.readBytes();
135 | _hasPublickey = true;
136 | break; }
137 | case 26: {
138 | privatekey = in.readBytes();
139 | _hasPrivatekey = true;
140 | break; }
141 | case 34: {
142 | signature = in.readBytes();
143 | _hasSignature = true;
144 | break; }
145 | case 41: {
146 | timestamp = in.readFixed64();
147 | _hasTimestamp = true;
148 | break; }
149 | default:
150 | in.skipTag(tag);
151 | }
152 | }
153 | }
154 |
155 | public static SignedPreKeyRecordStructure fromBytes(byte[] in) throws EncodingException {
156 | SignedPreKeyRecordStructure message = new SignedPreKeyRecordStructure();
157 | ProtoUtil.messageFromBytes(in, message);
158 | return message;
159 | }
160 |
161 | public byte[] toBytes() throws EncodingException {
162 | return ProtoUtil.messageToBytes(this);
163 | }
164 |
165 |
166 | }
167 |
168 |
169 |
170 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/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.libaxolotl.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(HEX_DIGITS[(b >> 4) & 0xf]);
74 | buf.append(HEX_DIGITS[b & 0xf]);
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/util/KeyHelper.java:
--------------------------------------------------------------------------------
1 | package org.whispersystems.libaxolotl.util;
2 |
3 | import org.whispersystems.curve25519.SecureRandomProvider;
4 | import org.whispersystems.libaxolotl.IdentityKey;
5 | import org.whispersystems.libaxolotl.IdentityKeyPair;
6 | import org.whispersystems.libaxolotl.InvalidKeyException;
7 | import org.whispersystems.libaxolotl.ecc.Curve;
8 | import org.whispersystems.libaxolotl.ecc.ECKeyPair;
9 | import org.whispersystems.libaxolotl.state.PreKeyRecord;
10 | import org.whispersystems.libaxolotl.state.SignedPreKeyRecord;
11 |
12 | import java.util.Vector;
13 |
14 | /**
15 | * Helper class for generating keys of different types.
16 | *
17 | * @author Moxie Marlinspike
18 | */
19 | public class KeyHelper {
20 |
21 | private KeyHelper() {}
22 |
23 | /**
24 | * Generate an identity key pair. Clients should only do this once,
25 | * at install time.
26 | *
27 | * @return the generated IdentityKeyPair.
28 | */
29 | public static IdentityKeyPair generateIdentityKeyPair(SecureRandomProvider secureRandom) {
30 | ECKeyPair keyPair = Curve.generateKeyPair(secureRandom);
31 | IdentityKey publicKey = new IdentityKey(keyPair.getPublicKey());
32 | return new IdentityKeyPair(publicKey, keyPair.getPrivateKey());
33 | }
34 |
35 | /**
36 | * Generate a registration ID. Clients should only do this once,
37 | * at install time.
38 | *
39 | * @param extendedRange By default (false), the generated registration
40 | * ID is sized to require the minimal possible protobuf
41 | * encoding overhead. Specify true if the caller needs
42 | * the full range of MAX_INT at the cost of slightly
43 | * higher encoding overhead.
44 | * @return the generated registration ID.
45 | */
46 | public static int generateRegistrationId(SecureRandomProvider secureRandom, boolean extendedRange) {
47 | if (extendedRange) return secureRandom.nextInt(Integer.MAX_VALUE - 1) + 1;
48 | else return secureRandom.nextInt(16380) + 1;
49 | }
50 |
51 | public static int getRandomSequence(SecureRandomProvider secureRandomProvider, int max) {
52 | return secureRandomProvider.nextInt(max);
53 | }
54 |
55 | /**
56 | * Generate a list of PreKeys. Clients should do this at install time, and
57 | * subsequently any time the list of PreKeys stored on the server runs low.
58 | *
59 | * PreKey IDs are shorts, so they will eventually be repeated. Clients should
60 | * store PreKeys in a circular buffer, so that they are repeated as infrequently
61 | * as possible.
62 | *
63 | * @param start The starting PreKey ID, inclusive.
64 | * @param count The number of PreKeys to generate.
65 | * @return the list of generated PreKeyRecords.
66 | */
67 | public static Vector generatePreKeys(SecureRandomProvider secureRandom, int start, int count) {
68 | Vector results = new Vector();
69 |
70 | start--;
71 |
72 | for (int i=0;i.
16 | */
17 | package org.whispersystems.libaxolotl.util;
18 |
19 | public class Pair {
20 | private final Object v1;
21 | private final Object v2;
22 |
23 | public Pair(Object v1, Object v2) {
24 | this.v1 = v1;
25 | this.v2 = v2;
26 | }
27 |
28 | public Object first() {
29 | return v1;
30 | }
31 |
32 | public Object 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 |
--------------------------------------------------------------------------------
/src/main/java/org/whispersystems/libaxolotl/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.libaxolotl.util.guava;
18 |
19 |
20 | /**
21 | * Implementation of an {@link Optional} not containing a reference.
22 | */
23 |
24 | final class Absent extends Optional {
25 | static final Absent INSTANCE = new Absent();
26 |
27 | public boolean isPresent() {
28 | return false;
29 | }
30 |
31 | public Object get() {
32 | throw new IllegalStateException("value is absent");
33 | }
34 |
35 | public Object or(Object defaultValue) {
36 | return Preconditions.checkNotNull(defaultValue, "use orNull() instead of or(null)");
37 | }
38 |
39 | public Optional or(Optional secondChoice) {
40 | return (Optional) Preconditions.checkNotNull(secondChoice);
41 | }
42 |
43 | public Object or(Supplier supplier) {
44 | return Preconditions.checkNotNull(supplier.get(),
45 | "use orNull() instead of a Supplier that returns null");
46 | }
47 |
48 | public Object orNull() {
49 | return null;
50 | }
51 |
52 | // @Override public Set