From 60800e155612bea797eed93c67046a23d26054cc Mon Sep 17 00:00:00 2001 From: Moxie Marlinspike Date: Mon, 24 Nov 2014 12:54:30 -0800 Subject: Break out into separate repo. --- .../libaxolotl/ratchet/AliceAxolotlParameters.java | 109 +++++++++++++ .../libaxolotl/ratchet/BobAxolotlParameters.java | 109 +++++++++++++ .../libaxolotl/ratchet/ChainKey.java | 75 +++++++++ .../libaxolotl/ratchet/MessageKeys.java | 51 ++++++ .../libaxolotl/ratchet/RatchetingSession.java | 179 +++++++++++++++++++++ .../whispersystems/libaxolotl/ratchet/RootKey.java | 54 +++++++ .../ratchet/SymmetricAxolotlParameters.java | 108 +++++++++++++ 7 files changed, 685 insertions(+) create mode 100644 src/main/java/org/whispersystems/libaxolotl/ratchet/AliceAxolotlParameters.java create mode 100644 src/main/java/org/whispersystems/libaxolotl/ratchet/BobAxolotlParameters.java create mode 100644 src/main/java/org/whispersystems/libaxolotl/ratchet/ChainKey.java create mode 100644 src/main/java/org/whispersystems/libaxolotl/ratchet/MessageKeys.java create mode 100644 src/main/java/org/whispersystems/libaxolotl/ratchet/RatchetingSession.java create mode 100644 src/main/java/org/whispersystems/libaxolotl/ratchet/RootKey.java create mode 100644 src/main/java/org/whispersystems/libaxolotl/ratchet/SymmetricAxolotlParameters.java (limited to 'src/main/java/org/whispersystems/libaxolotl/ratchet') diff --git a/src/main/java/org/whispersystems/libaxolotl/ratchet/AliceAxolotlParameters.java b/src/main/java/org/whispersystems/libaxolotl/ratchet/AliceAxolotlParameters.java new file mode 100644 index 00000000..13c995e9 --- /dev/null +++ b/src/main/java/org/whispersystems/libaxolotl/ratchet/AliceAxolotlParameters.java @@ -0,0 +1,109 @@ +package org.whispersystems.libaxolotl.ratchet; + +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.libaxolotl.IdentityKeyPair; +import org.whispersystems.libaxolotl.ecc.ECKeyPair; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; +import org.whispersystems.libaxolotl.util.guava.Optional; + +public class AliceAxolotlParameters { + + private final IdentityKeyPair ourIdentityKey; + private final ECKeyPair ourBaseKey; + + private final IdentityKey theirIdentityKey; + private final ECPublicKey theirSignedPreKey; + private final Optional theirOneTimePreKey; + private final ECPublicKey theirRatchetKey; + + private AliceAxolotlParameters(IdentityKeyPair ourIdentityKey, ECKeyPair ourBaseKey, + IdentityKey theirIdentityKey, ECPublicKey theirSignedPreKey, + ECPublicKey theirRatchetKey, Optional theirOneTimePreKey) + { + this.ourIdentityKey = ourIdentityKey; + this.ourBaseKey = ourBaseKey; + this.theirIdentityKey = theirIdentityKey; + this.theirSignedPreKey = theirSignedPreKey; + this.theirRatchetKey = theirRatchetKey; + this.theirOneTimePreKey = theirOneTimePreKey; + + if (ourIdentityKey == null || ourBaseKey == null || theirIdentityKey == null || + theirSignedPreKey == null || theirRatchetKey == null || theirOneTimePreKey == null) + { + throw new IllegalArgumentException("Null values!"); + } + } + + public IdentityKeyPair getOurIdentityKey() { + return ourIdentityKey; + } + + public ECKeyPair getOurBaseKey() { + return ourBaseKey; + } + + public IdentityKey getTheirIdentityKey() { + return theirIdentityKey; + } + + public ECPublicKey getTheirSignedPreKey() { + return theirSignedPreKey; + } + + public Optional getTheirOneTimePreKey() { + return theirOneTimePreKey; + } + + public static Builder newBuilder() { + return new Builder(); + } + + public ECPublicKey getTheirRatchetKey() { + return theirRatchetKey; + } + + public static class Builder { + private IdentityKeyPair ourIdentityKey; + private ECKeyPair ourBaseKey; + + private IdentityKey theirIdentityKey; + private ECPublicKey theirSignedPreKey; + private ECPublicKey theirRatchetKey; + private Optional theirOneTimePreKey; + + public Builder setOurIdentityKey(IdentityKeyPair ourIdentityKey) { + this.ourIdentityKey = ourIdentityKey; + return this; + } + + public Builder setOurBaseKey(ECKeyPair ourBaseKey) { + this.ourBaseKey = ourBaseKey; + return this; + } + + public Builder setTheirRatchetKey(ECPublicKey theirRatchetKey) { + this.theirRatchetKey = theirRatchetKey; + return this; + } + + public Builder setTheirIdentityKey(IdentityKey theirIdentityKey) { + this.theirIdentityKey = theirIdentityKey; + return this; + } + + public Builder setTheirSignedPreKey(ECPublicKey theirSignedPreKey) { + this.theirSignedPreKey = theirSignedPreKey; + return this; + } + + public Builder setTheirOneTimePreKey(Optional theirOneTimePreKey) { + this.theirOneTimePreKey = theirOneTimePreKey; + return this; + } + + public AliceAxolotlParameters create() { + return new AliceAxolotlParameters(ourIdentityKey, ourBaseKey, theirIdentityKey, + theirSignedPreKey, theirRatchetKey, theirOneTimePreKey); + } + } +} diff --git a/src/main/java/org/whispersystems/libaxolotl/ratchet/BobAxolotlParameters.java b/src/main/java/org/whispersystems/libaxolotl/ratchet/BobAxolotlParameters.java new file mode 100644 index 00000000..27116a8b --- /dev/null +++ b/src/main/java/org/whispersystems/libaxolotl/ratchet/BobAxolotlParameters.java @@ -0,0 +1,109 @@ +package org.whispersystems.libaxolotl.ratchet; + +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.libaxolotl.IdentityKeyPair; +import org.whispersystems.libaxolotl.ecc.ECKeyPair; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; +import org.whispersystems.libaxolotl.util.guava.Optional; + +public class BobAxolotlParameters { + + private final IdentityKeyPair ourIdentityKey; + private final ECKeyPair ourSignedPreKey; + private final Optional ourOneTimePreKey; + private final ECKeyPair ourRatchetKey; + + private final IdentityKey theirIdentityKey; + private final ECPublicKey theirBaseKey; + + BobAxolotlParameters(IdentityKeyPair ourIdentityKey, ECKeyPair ourSignedPreKey, + ECKeyPair ourRatchetKey, Optional ourOneTimePreKey, + IdentityKey theirIdentityKey, ECPublicKey theirBaseKey) + { + this.ourIdentityKey = ourIdentityKey; + this.ourSignedPreKey = ourSignedPreKey; + this.ourRatchetKey = ourRatchetKey; + this.ourOneTimePreKey = ourOneTimePreKey; + this.theirIdentityKey = theirIdentityKey; + this.theirBaseKey = theirBaseKey; + + if (ourIdentityKey == null || ourSignedPreKey == null || ourRatchetKey == null || + ourOneTimePreKey == null || theirIdentityKey == null || theirBaseKey == null) + { + throw new IllegalArgumentException("Null value!"); + } + } + + public IdentityKeyPair getOurIdentityKey() { + return ourIdentityKey; + } + + public ECKeyPair getOurSignedPreKey() { + return ourSignedPreKey; + } + + public Optional getOurOneTimePreKey() { + return ourOneTimePreKey; + } + + public IdentityKey getTheirIdentityKey() { + return theirIdentityKey; + } + + public ECPublicKey getTheirBaseKey() { + return theirBaseKey; + } + + public static Builder newBuilder() { + return new Builder(); + } + + public ECKeyPair getOurRatchetKey() { + return ourRatchetKey; + } + + public static class Builder { + private IdentityKeyPair ourIdentityKey; + private ECKeyPair ourSignedPreKey; + private Optional ourOneTimePreKey; + private ECKeyPair ourRatchetKey; + + private IdentityKey theirIdentityKey; + private ECPublicKey theirBaseKey; + + public Builder setOurIdentityKey(IdentityKeyPair ourIdentityKey) { + this.ourIdentityKey = ourIdentityKey; + return this; + } + + public Builder setOurSignedPreKey(ECKeyPair ourSignedPreKey) { + this.ourSignedPreKey = ourSignedPreKey; + return this; + } + + public Builder setOurOneTimePreKey(Optional ourOneTimePreKey) { + this.ourOneTimePreKey = ourOneTimePreKey; + return this; + } + + public Builder setTheirIdentityKey(IdentityKey theirIdentityKey) { + this.theirIdentityKey = theirIdentityKey; + return this; + } + + public Builder setTheirBaseKey(ECPublicKey theirBaseKey) { + this.theirBaseKey = theirBaseKey; + return this; + } + + public Builder setOurRatchetKey(ECKeyPair ourRatchetKey) { + this.ourRatchetKey = ourRatchetKey; + return this; + } + + public BobAxolotlParameters create() { + return new BobAxolotlParameters(ourIdentityKey, ourSignedPreKey, ourRatchetKey, + ourOneTimePreKey, theirIdentityKey, theirBaseKey); + } + } +} diff --git a/src/main/java/org/whispersystems/libaxolotl/ratchet/ChainKey.java b/src/main/java/org/whispersystems/libaxolotl/ratchet/ChainKey.java new file mode 100644 index 00000000..9dd1dbee --- /dev/null +++ b/src/main/java/org/whispersystems/libaxolotl/ratchet/ChainKey.java @@ -0,0 +1,75 @@ +/** + * Copyright (C) 2014 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.whispersystems.libaxolotl.ratchet; + + +import org.whispersystems.libaxolotl.kdf.DerivedMessageSecrets; +import org.whispersystems.libaxolotl.kdf.HKDF; + +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; + +public class ChainKey { + + private static final byte[] MESSAGE_KEY_SEED = {0x01}; + private static final byte[] CHAIN_KEY_SEED = {0x02}; + + private final HKDF kdf; + private final byte[] key; + private final int index; + + public ChainKey(HKDF kdf, byte[] key, int index) { + this.kdf = kdf; + this.key = key; + this.index = index; + } + + public byte[] getKey() { + return key; + } + + public int getIndex() { + return index; + } + + public ChainKey getNextChainKey() { + byte[] nextKey = getBaseMaterial(CHAIN_KEY_SEED); + return new ChainKey(kdf, nextKey, index + 1); + } + + public MessageKeys getMessageKeys() { + byte[] inputKeyMaterial = getBaseMaterial(MESSAGE_KEY_SEED); + byte[] keyMaterialBytes = kdf.deriveSecrets(inputKeyMaterial, "WhisperMessageKeys".getBytes(), DerivedMessageSecrets.SIZE); + DerivedMessageSecrets keyMaterial = new DerivedMessageSecrets(keyMaterialBytes); + + return new MessageKeys(keyMaterial.getCipherKey(), keyMaterial.getMacKey(), keyMaterial.getIv(), index); + } + + private byte[] getBaseMaterial(byte[] seed) { + try { + Mac mac = Mac.getInstance("HmacSHA256"); + mac.init(new SecretKeySpec(key, "HmacSHA256")); + + return mac.doFinal(seed); + } catch (NoSuchAlgorithmException | InvalidKeyException e) { + throw new AssertionError(e); + } + } +} diff --git a/src/main/java/org/whispersystems/libaxolotl/ratchet/MessageKeys.java b/src/main/java/org/whispersystems/libaxolotl/ratchet/MessageKeys.java new file mode 100644 index 00000000..95a8c7dc --- /dev/null +++ b/src/main/java/org/whispersystems/libaxolotl/ratchet/MessageKeys.java @@ -0,0 +1,51 @@ +/** + * Copyright (C) 2014 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.whispersystems.libaxolotl.ratchet; + +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +public class MessageKeys { + + private final SecretKeySpec cipherKey; + private final SecretKeySpec macKey; + private final IvParameterSpec iv; + private final int counter; + + public MessageKeys(SecretKeySpec cipherKey, SecretKeySpec macKey, IvParameterSpec iv, int counter) { + this.cipherKey = cipherKey; + this.macKey = macKey; + this.iv = iv; + this.counter = counter; + } + + public SecretKeySpec getCipherKey() { + return cipherKey; + } + + public SecretKeySpec getMacKey() { + return macKey; + } + + public IvParameterSpec getIv() { + return iv; + } + + public int getCounter() { + return counter; + } +} diff --git a/src/main/java/org/whispersystems/libaxolotl/ratchet/RatchetingSession.java b/src/main/java/org/whispersystems/libaxolotl/ratchet/RatchetingSession.java new file mode 100644 index 00000000..8c094ec0 --- /dev/null +++ b/src/main/java/org/whispersystems/libaxolotl/ratchet/RatchetingSession.java @@ -0,0 +1,179 @@ +/** + * Copyright (C) 2014 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.whispersystems.libaxolotl.ratchet; + +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECKeyPair; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; +import org.whispersystems.libaxolotl.kdf.HKDF; +import org.whispersystems.libaxolotl.state.SessionState; +import org.whispersystems.libaxolotl.util.ByteUtil; +import org.whispersystems.libaxolotl.util.Pair; +import org.whispersystems.libaxolotl.util.guava.Optional; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Arrays; + +public class RatchetingSession { + + public static void initializeSession(SessionState sessionState, + int sessionVersion, + SymmetricAxolotlParameters parameters) + throws InvalidKeyException + { + if (isAlice(parameters.getOurBaseKey().getPublicKey(), parameters.getTheirBaseKey())) { + AliceAxolotlParameters.Builder aliceParameters = AliceAxolotlParameters.newBuilder(); + + aliceParameters.setOurBaseKey(parameters.getOurBaseKey()) + .setOurIdentityKey(parameters.getOurIdentityKey()) + .setTheirRatchetKey(parameters.getTheirRatchetKey()) + .setTheirIdentityKey(parameters.getTheirIdentityKey()) + .setTheirSignedPreKey(parameters.getTheirBaseKey()) + .setTheirOneTimePreKey(Optional.absent()); + + RatchetingSession.initializeSession(sessionState, sessionVersion, aliceParameters.create()); + } else { + BobAxolotlParameters.Builder bobParameters = BobAxolotlParameters.newBuilder(); + + bobParameters.setOurIdentityKey(parameters.getOurIdentityKey()) + .setOurRatchetKey(parameters.getOurRatchetKey()) + .setOurSignedPreKey(parameters.getOurBaseKey()) + .setOurOneTimePreKey(Optional.absent()) + .setTheirBaseKey(parameters.getTheirBaseKey()) + .setTheirIdentityKey(parameters.getTheirIdentityKey()); + + RatchetingSession.initializeSession(sessionState, sessionVersion, bobParameters.create()); + } + } + + public static void initializeSession(SessionState sessionState, + int sessionVersion, + AliceAxolotlParameters parameters) + throws InvalidKeyException + { + try { + sessionState.setSessionVersion(sessionVersion); + sessionState.setRemoteIdentityKey(parameters.getTheirIdentityKey()); + sessionState.setLocalIdentityKey(parameters.getOurIdentityKey().getPublicKey()); + + ECKeyPair sendingRatchetKey = Curve.generateKeyPair(); + ByteArrayOutputStream secrets = new ByteArrayOutputStream(); + + if (sessionVersion >= 3) { + secrets.write(getDiscontinuityBytes()); + } + + secrets.write(Curve.calculateAgreement(parameters.getTheirSignedPreKey(), + parameters.getOurIdentityKey().getPrivateKey())); + secrets.write(Curve.calculateAgreement(parameters.getTheirIdentityKey().getPublicKey(), + parameters.getOurBaseKey().getPrivateKey())); + secrets.write(Curve.calculateAgreement(parameters.getTheirSignedPreKey(), + parameters.getOurBaseKey().getPrivateKey())); + + if (sessionVersion >= 3 & parameters.getTheirOneTimePreKey().isPresent()) { + secrets.write(Curve.calculateAgreement(parameters.getTheirOneTimePreKey().get(), + parameters.getOurBaseKey().getPrivateKey())); + } + + DerivedKeys derivedKeys = calculateDerivedKeys(sessionVersion, secrets.toByteArray()); + Pair sendingChain = derivedKeys.getRootKey().createChain(parameters.getTheirRatchetKey(), sendingRatchetKey); + + sessionState.addReceiverChain(parameters.getTheirRatchetKey(), derivedKeys.getChainKey()); + sessionState.setSenderChain(sendingRatchetKey, sendingChain.second()); + sessionState.setRootKey(sendingChain.first()); + } catch (IOException e) { + throw new AssertionError(e); + } + } + + public static void initializeSession(SessionState sessionState, + int sessionVersion, + BobAxolotlParameters parameters) + throws InvalidKeyException + { + + try { + sessionState.setSessionVersion(sessionVersion); + sessionState.setRemoteIdentityKey(parameters.getTheirIdentityKey()); + sessionState.setLocalIdentityKey(parameters.getOurIdentityKey().getPublicKey()); + + ByteArrayOutputStream secrets = new ByteArrayOutputStream(); + + if (sessionVersion >= 3) { + secrets.write(getDiscontinuityBytes()); + } + + secrets.write(Curve.calculateAgreement(parameters.getTheirIdentityKey().getPublicKey(), + parameters.getOurSignedPreKey().getPrivateKey())); + secrets.write(Curve.calculateAgreement(parameters.getTheirBaseKey(), + parameters.getOurIdentityKey().getPrivateKey())); + secrets.write(Curve.calculateAgreement(parameters.getTheirBaseKey(), + parameters.getOurSignedPreKey().getPrivateKey())); + + if (sessionVersion >= 3 && parameters.getOurOneTimePreKey().isPresent()) { + secrets.write(Curve.calculateAgreement(parameters.getTheirBaseKey(), + parameters.getOurOneTimePreKey().get().getPrivateKey())); + } + + DerivedKeys derivedKeys = calculateDerivedKeys(sessionVersion, secrets.toByteArray()); + + sessionState.setSenderChain(parameters.getOurRatchetKey(), derivedKeys.getChainKey()); + sessionState.setRootKey(derivedKeys.getRootKey()); + } catch (IOException e) { + throw new AssertionError(e); + } + } + + private static byte[] getDiscontinuityBytes() { + byte[] discontinuity = new byte[32]; + Arrays.fill(discontinuity, (byte) 0xFF); + return discontinuity; + } + + private static DerivedKeys calculateDerivedKeys(int sessionVersion, byte[] masterSecret) { + HKDF kdf = HKDF.createFor(sessionVersion); + byte[] derivedSecretBytes = kdf.deriveSecrets(masterSecret, "WhisperText".getBytes(), 64); + byte[][] derivedSecrets = ByteUtil.split(derivedSecretBytes, 32, 32); + + return new DerivedKeys(new RootKey(kdf, derivedSecrets[0]), + new ChainKey(kdf, derivedSecrets[1], 0)); + } + + private static boolean isAlice(ECPublicKey ourKey, ECPublicKey theirKey) { + return ourKey.compareTo(theirKey) < 0; + } + + private static class DerivedKeys { + private final RootKey rootKey; + private final ChainKey chainKey; + + private DerivedKeys(RootKey rootKey, ChainKey chainKey) { + this.rootKey = rootKey; + this.chainKey = chainKey; + } + + public RootKey getRootKey() { + return rootKey; + } + + public ChainKey getChainKey() { + return chainKey; + } + } +} diff --git a/src/main/java/org/whispersystems/libaxolotl/ratchet/RootKey.java b/src/main/java/org/whispersystems/libaxolotl/ratchet/RootKey.java new file mode 100644 index 00000000..39f3a831 --- /dev/null +++ b/src/main/java/org/whispersystems/libaxolotl/ratchet/RootKey.java @@ -0,0 +1,54 @@ +/** + * Copyright (C) 2014 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.whispersystems.libaxolotl.ratchet; + +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECKeyPair; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; +import org.whispersystems.libaxolotl.kdf.DerivedRootSecrets; +import org.whispersystems.libaxolotl.kdf.HKDF; +import org.whispersystems.libaxolotl.util.ByteUtil; +import org.whispersystems.libaxolotl.util.Pair; + +public class RootKey { + + private final HKDF kdf; + private final byte[] key; + + public RootKey(HKDF kdf, byte[] key) { + this.kdf = kdf; + this.key = key; + } + + public byte[] getKeyBytes() { + return key; + } + + public Pair createChain(ECPublicKey theirRatchetKey, ECKeyPair ourRatchetKey) + throws InvalidKeyException + { + byte[] sharedSecret = Curve.calculateAgreement(theirRatchetKey, ourRatchetKey.getPrivateKey()); + byte[] derivedSecretBytes = kdf.deriveSecrets(sharedSecret, key, "WhisperRatchet".getBytes(), DerivedRootSecrets.SIZE); + DerivedRootSecrets derivedSecrets = new DerivedRootSecrets(derivedSecretBytes); + + RootKey newRootKey = new RootKey(kdf, derivedSecrets.getRootKey()); + ChainKey newChainKey = new ChainKey(kdf, derivedSecrets.getChainKey(), 0); + + return new Pair<>(newRootKey, newChainKey); + } +} diff --git a/src/main/java/org/whispersystems/libaxolotl/ratchet/SymmetricAxolotlParameters.java b/src/main/java/org/whispersystems/libaxolotl/ratchet/SymmetricAxolotlParameters.java new file mode 100644 index 00000000..7a63c45f --- /dev/null +++ b/src/main/java/org/whispersystems/libaxolotl/ratchet/SymmetricAxolotlParameters.java @@ -0,0 +1,108 @@ +package org.whispersystems.libaxolotl.ratchet; + +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.libaxolotl.IdentityKeyPair; +import org.whispersystems.libaxolotl.ecc.ECKeyPair; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; + +public class SymmetricAxolotlParameters { + + private final ECKeyPair ourBaseKey; + private final ECKeyPair ourRatchetKey; + private final IdentityKeyPair ourIdentityKey; + + private final ECPublicKey theirBaseKey; + private final ECPublicKey theirRatchetKey; + private final IdentityKey theirIdentityKey; + + SymmetricAxolotlParameters(ECKeyPair ourBaseKey, ECKeyPair ourRatchetKey, + IdentityKeyPair ourIdentityKey, ECPublicKey theirBaseKey, + ECPublicKey theirRatchetKey, IdentityKey theirIdentityKey) + { + this.ourBaseKey = ourBaseKey; + this.ourRatchetKey = ourRatchetKey; + this.ourIdentityKey = ourIdentityKey; + this.theirBaseKey = theirBaseKey; + this.theirRatchetKey = theirRatchetKey; + this.theirIdentityKey = theirIdentityKey; + + if (ourBaseKey == null || ourRatchetKey == null || ourIdentityKey == null || + theirBaseKey == null || theirRatchetKey == null || theirIdentityKey == null) + { + throw new IllegalArgumentException("Null values!"); + } + } + + public ECKeyPair getOurBaseKey() { + return ourBaseKey; + } + + public ECKeyPair getOurRatchetKey() { + return ourRatchetKey; + } + + public IdentityKeyPair getOurIdentityKey() { + return ourIdentityKey; + } + + public ECPublicKey getTheirBaseKey() { + return theirBaseKey; + } + + public ECPublicKey getTheirRatchetKey() { + return theirRatchetKey; + } + + public IdentityKey getTheirIdentityKey() { + return theirIdentityKey; + } + + public static Builder newBuilder() { + return new Builder(); + } + + public static class Builder { + private ECKeyPair ourBaseKey; + private ECKeyPair ourRatchetKey; + private IdentityKeyPair ourIdentityKey; + + private ECPublicKey theirBaseKey; + private ECPublicKey theirRatchetKey; + private IdentityKey theirIdentityKey; + + public Builder setOurBaseKey(ECKeyPair ourBaseKey) { + this.ourBaseKey = ourBaseKey; + return this; + } + + public Builder setOurRatchetKey(ECKeyPair ourRatchetKey) { + this.ourRatchetKey = ourRatchetKey; + return this; + } + + public Builder setOurIdentityKey(IdentityKeyPair ourIdentityKey) { + this.ourIdentityKey = ourIdentityKey; + return this; + } + + public Builder setTheirBaseKey(ECPublicKey theirBaseKey) { + this.theirBaseKey = theirBaseKey; + return this; + } + + public Builder setTheirRatchetKey(ECPublicKey theirRatchetKey) { + this.theirRatchetKey = theirRatchetKey; + return this; + } + + public Builder setTheirIdentityKey(IdentityKey theirIdentityKey) { + this.theirIdentityKey = theirIdentityKey; + return this; + } + + public SymmetricAxolotlParameters create() { + return new SymmetricAxolotlParameters(ourBaseKey, ourRatchetKey, ourIdentityKey, + theirBaseKey, theirRatchetKey, theirIdentityKey); + } + } +} -- cgit v1.2.3