aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/org/whispersystems/libaxolotl/groups/state
diff options
context:
space:
mode:
authorMoxie Marlinspike <moxie@thoughtcrime.org>2014-11-24 12:54:30 -0800
committerMoxie Marlinspike <moxie@thoughtcrime.org>2014-11-24 12:54:30 -0800
commit60800e155612bea797eed93c67046a23d26054cc (patch)
treed88368c1c26162e27e790195133ca2b526597afe /src/main/java/org/whispersystems/libaxolotl/groups/state
Break out into separate repo.
Diffstat (limited to '')
-rw-r--r--src/main/java/org/whispersystems/libaxolotl/groups/state/SenderKeyRecord.java64
-rw-r--r--src/main/java/org/whispersystems/libaxolotl/groups/state/SenderKeyState.java144
-rw-r--r--src/main/java/org/whispersystems/libaxolotl/groups/state/SenderKeyStore.java6
3 files changed, 214 insertions, 0 deletions
diff --git a/src/main/java/org/whispersystems/libaxolotl/groups/state/SenderKeyRecord.java b/src/main/java/org/whispersystems/libaxolotl/groups/state/SenderKeyRecord.java
new file mode 100644
index 00000000..bb1ba952
--- /dev/null
+++ b/src/main/java/org/whispersystems/libaxolotl/groups/state/SenderKeyRecord.java
@@ -0,0 +1,64 @@
+package org.whispersystems.libaxolotl.groups.state;
+
+import org.whispersystems.libaxolotl.InvalidKeyIdException;
+import org.whispersystems.libaxolotl.ecc.ECKeyPair;
+import org.whispersystems.libaxolotl.ecc.ECPublicKey;
+import org.whispersystems.libaxolotl.state.StorageProtos;
+
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+
+import static org.whispersystems.libaxolotl.state.StorageProtos.SenderKeyRecordStructure;
+
+public class SenderKeyRecord {
+
+ private List<SenderKeyState> senderKeyStates = new LinkedList<>();
+
+ public SenderKeyRecord() {}
+
+ public SenderKeyRecord(byte[] serialized) throws IOException {
+ SenderKeyRecordStructure senderKeyRecordStructure = SenderKeyRecordStructure.parseFrom(serialized);
+
+ for (StorageProtos.SenderKeyStateStructure structure : senderKeyRecordStructure.getSenderKeyStatesList()) {
+ this.senderKeyStates.add(new SenderKeyState(structure));
+ }
+ }
+
+ public SenderKeyState getSenderKeyState() throws InvalidKeyIdException {
+ if (!senderKeyStates.isEmpty()) {
+ return senderKeyStates.get(0);
+ } else {
+ throw new InvalidKeyIdException("No key state in record!");
+ }
+ }
+
+ public SenderKeyState getSenderKeyState(int keyId) throws InvalidKeyIdException {
+ for (SenderKeyState state : senderKeyStates) {
+ if (state.getKeyId() == keyId) {
+ return state;
+ }
+ }
+
+ throw new InvalidKeyIdException("No keys for: " + keyId);
+ }
+
+ public void addSenderKeyState(int id, int iteration, byte[] chainKey, ECPublicKey signatureKey) {
+ senderKeyStates.add(new SenderKeyState(id, iteration, chainKey, signatureKey));
+ }
+
+ public void setSenderKeyState(int id, int iteration, byte[] chainKey, ECKeyPair signatureKey) {
+ senderKeyStates.clear();
+ senderKeyStates.add(new SenderKeyState(id, iteration, chainKey, signatureKey));
+ }
+
+ public byte[] serialize() {
+ SenderKeyRecordStructure.Builder recordStructure = SenderKeyRecordStructure.newBuilder();
+
+ for (SenderKeyState senderKeyState : senderKeyStates) {
+ recordStructure.addSenderKeyStates(senderKeyState.getStructure());
+ }
+
+ return recordStructure.build().toByteArray();
+ }
+}
diff --git a/src/main/java/org/whispersystems/libaxolotl/groups/state/SenderKeyState.java b/src/main/java/org/whispersystems/libaxolotl/groups/state/SenderKeyState.java
new file mode 100644
index 00000000..80498ce0
--- /dev/null
+++ b/src/main/java/org/whispersystems/libaxolotl/groups/state/SenderKeyState.java
@@ -0,0 +1,144 @@
+package org.whispersystems.libaxolotl.groups.state;
+
+import com.google.protobuf.ByteString;
+
+import org.whispersystems.libaxolotl.InvalidKeyException;
+import org.whispersystems.libaxolotl.ecc.Curve;
+import org.whispersystems.libaxolotl.ecc.ECKeyPair;
+import org.whispersystems.libaxolotl.ecc.ECPrivateKey;
+import org.whispersystems.libaxolotl.ecc.ECPublicKey;
+import org.whispersystems.libaxolotl.groups.ratchet.SenderChainKey;
+import org.whispersystems.libaxolotl.groups.ratchet.SenderMessageKey;
+import org.whispersystems.libaxolotl.util.guava.Optional;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import static org.whispersystems.libaxolotl.state.StorageProtos.SenderKeyStateStructure;
+
+public class SenderKeyState {
+
+ private SenderKeyStateStructure senderKeyStateStructure;
+
+ public SenderKeyState(int id, int iteration, byte[] chainKey, ECPublicKey signatureKey) {
+ this(id, iteration, chainKey, signatureKey, Optional.<ECPrivateKey>absent());
+ }
+
+ public SenderKeyState(int id, int iteration, byte[] chainKey, ECKeyPair signatureKey) {
+ this(id, iteration, chainKey, signatureKey.getPublicKey(), Optional.of(signatureKey.getPrivateKey()));
+ }
+
+ private SenderKeyState(int id, int iteration, byte[] chainKey,
+ ECPublicKey signatureKeyPublic,
+ Optional<ECPrivateKey> signatureKeyPrivate)
+ {
+ SenderKeyStateStructure.SenderChainKey senderChainKeyStructure =
+ SenderKeyStateStructure.SenderChainKey.newBuilder()
+ .setIteration(iteration)
+ .setSeed(ByteString.copyFrom(chainKey))
+ .build();
+
+ SenderKeyStateStructure.SenderSigningKey.Builder signingKeyStructure =
+ SenderKeyStateStructure.SenderSigningKey.newBuilder()
+ .setPublic(ByteString.copyFrom(signatureKeyPublic.serialize()));
+
+ if (signatureKeyPrivate.isPresent()) {
+ signingKeyStructure.setPrivate(ByteString.copyFrom(signatureKeyPrivate.get().serialize()));
+ }
+
+ this.senderKeyStateStructure = SenderKeyStateStructure.newBuilder()
+ .setSenderKeyId(id)
+ .setSenderChainKey(senderChainKeyStructure)
+ .setSenderSigningKey(signingKeyStructure)
+ .build();
+ }
+
+ public SenderKeyState(SenderKeyStateStructure senderKeyStateStructure) {
+ this.senderKeyStateStructure = senderKeyStateStructure;
+ }
+
+ public int getKeyId() {
+ return senderKeyStateStructure.getSenderKeyId();
+ }
+
+ public SenderChainKey getSenderChainKey() {
+ return new SenderChainKey(senderKeyStateStructure.getSenderChainKey().getIteration(),
+ senderKeyStateStructure.getSenderChainKey().getSeed().toByteArray());
+ }
+
+ public void setSenderChainKey(SenderChainKey chainKey) {
+ SenderKeyStateStructure.SenderChainKey senderChainKeyStructure =
+ SenderKeyStateStructure.SenderChainKey.newBuilder()
+ .setIteration(chainKey.getIteration())
+ .setSeed(ByteString.copyFrom(chainKey.getSeed()))
+ .build();
+
+ this.senderKeyStateStructure = senderKeyStateStructure.toBuilder()
+ .setSenderChainKey(senderChainKeyStructure)
+ .build();
+ }
+
+ public ECPublicKey getSigningKeyPublic() throws InvalidKeyException {
+ return Curve.decodePoint(senderKeyStateStructure.getSenderSigningKey()
+ .getPublic()
+ .toByteArray(), 0);
+ }
+
+ public ECPrivateKey getSigningKeyPrivate() {
+ return Curve.decodePrivatePoint(senderKeyStateStructure.getSenderSigningKey()
+ .getPrivate().toByteArray());
+ }
+
+ public boolean hasSenderMessageKey(int iteration) {
+ for (SenderKeyStateStructure.SenderMessageKey senderMessageKey : senderKeyStateStructure.getSenderMessageKeysList()) {
+ if (senderMessageKey.getIteration() == iteration) return true;
+ }
+
+ return false;
+ }
+
+ public void addSenderMessageKey(SenderMessageKey senderMessageKey) {
+ SenderKeyStateStructure.SenderMessageKey senderMessageKeyStructure =
+ SenderKeyStateStructure.SenderMessageKey.newBuilder()
+ .setIteration(senderMessageKey.getIteration())
+ .setSeed(ByteString.copyFrom(senderMessageKey.getSeed()))
+ .build();
+
+ this.senderKeyStateStructure = this.senderKeyStateStructure.toBuilder()
+ .addSenderMessageKeys(senderMessageKeyStructure)
+ .build();
+ }
+
+ public SenderMessageKey removeSenderMessageKey(int iteration) {
+ List<SenderKeyStateStructure.SenderMessageKey> keys = new LinkedList<>(senderKeyStateStructure.getSenderMessageKeysList());
+ Iterator<SenderKeyStateStructure.SenderMessageKey> iterator = keys.iterator();
+
+ SenderKeyStateStructure.SenderMessageKey result = null;
+
+ while (iterator.hasNext()) {
+ SenderKeyStateStructure.SenderMessageKey senderMessageKey = iterator.next();
+
+ if (senderMessageKey.getIteration() == iteration) {
+ result = senderMessageKey;
+ iterator.remove();
+ break;
+ }
+ }
+
+ this.senderKeyStateStructure = this.senderKeyStateStructure.toBuilder()
+ .clearSenderMessageKeys()
+ .addAllSenderMessageKeys(keys)
+ .build();
+
+ if (result != null) {
+ return new SenderMessageKey(result.getIteration(), result.getSeed().toByteArray());
+ } else {
+ return null;
+ }
+ }
+
+ public SenderKeyStateStructure getStructure() {
+ return senderKeyStateStructure;
+ }
+}
diff --git a/src/main/java/org/whispersystems/libaxolotl/groups/state/SenderKeyStore.java b/src/main/java/org/whispersystems/libaxolotl/groups/state/SenderKeyStore.java
new file mode 100644
index 00000000..da01b1f3
--- /dev/null
+++ b/src/main/java/org/whispersystems/libaxolotl/groups/state/SenderKeyStore.java
@@ -0,0 +1,6 @@
+package org.whispersystems.libaxolotl.groups.state;
+
+public interface SenderKeyStore {
+ public void storeSenderKey(String senderKeyId, SenderKeyRecord record);
+ public SenderKeyRecord loadSenderKey(String senderKeyId);
+}