From d6c5e92c9de1bb9973761902a2ac4a2e12ae0e9c Mon Sep 17 00:00:00 2001 From: Moxie Marlinspike Date: Sat, 5 Jul 2014 13:42:07 -0700 Subject: [PATCH] Collapse RatchetingSessionV2 and RatchetingSessionV3. --- .../test/SessionCipherTest.java | 33 +++-- ...V2Test.java => RatchetingSessionTest.java} | 20 +-- .../libaxolotl/SessionBuilder.java | 50 +++---- ...gSessionV3.java => RatchetingSession.java} | 33 +++-- .../ratchet/RatchetingSessionV2.java | 138 ------------------ 5 files changed, 72 insertions(+), 202 deletions(-) rename libaxolotl/src/androidTest/java/org/whispersystems/test/ratchet/{RatchetingSessionV2Test.java => RatchetingSessionTest.java} (95%) rename libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/{RatchetingSessionV3.java => RatchetingSession.java} (86%) delete mode 100644 libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/RatchetingSessionV2.java diff --git a/libaxolotl/src/androidTest/java/org/whispersystems/test/SessionCipherTest.java b/libaxolotl/src/androidTest/java/org/whispersystems/test/SessionCipherTest.java index e888e91040..88e9d488d4 100644 --- a/libaxolotl/src/androidTest/java/org/whispersystems/test/SessionCipherTest.java +++ b/libaxolotl/src/androidTest/java/org/whispersystems/test/SessionCipherTest.java @@ -12,8 +12,7 @@ import org.whispersystems.libaxolotl.SessionCipher; import org.whispersystems.libaxolotl.ecc.Curve; import org.whispersystems.libaxolotl.ecc.ECKeyPair; import org.whispersystems.libaxolotl.protocol.CiphertextMessage; -import org.whispersystems.libaxolotl.ratchet.RatchetingSessionV2; -import org.whispersystems.libaxolotl.ratchet.RatchetingSessionV3; +import org.whispersystems.libaxolotl.ratchet.RatchetingSession; import org.whispersystems.libaxolotl.state.SessionRecord; import org.whispersystems.libaxolotl.state.SessionState; import org.whispersystems.libaxolotl.state.SessionStore; @@ -136,13 +135,15 @@ public class SessionCipherTest extends AndroidTestCase { ECKeyPair bobEphemeralKey = bobBaseKey; - RatchetingSessionV2.initializeSession(aliceSessionState, aliceBaseKey, bobBaseKey.getPublicKey(), - aliceEphemeralKey, bobEphemeralKey.getPublicKey(), - aliceIdentityKey, bobIdentityKey.getPublicKey()); + RatchetingSession.initializeSession(aliceSessionState, 2, aliceBaseKey, bobBaseKey.getPublicKey(), + aliceEphemeralKey, bobEphemeralKey.getPublicKey(), + null, null, + aliceIdentityKey, bobIdentityKey.getPublicKey()); - RatchetingSessionV2.initializeSession(bobSessionState, bobBaseKey, aliceBaseKey.getPublicKey(), - bobEphemeralKey, aliceEphemeralKey.getPublicKey(), - bobIdentityKey, aliceIdentityKey.getPublicKey()); + RatchetingSession.initializeSession(bobSessionState, 2, bobBaseKey, aliceBaseKey.getPublicKey(), + bobEphemeralKey, aliceEphemeralKey.getPublicKey(), + null, null, + bobIdentityKey, aliceIdentityKey.getPublicKey()); } private void initializeSessionsV3(SessionState aliceSessionState, SessionState bobSessionState) @@ -165,15 +166,15 @@ public class SessionCipherTest extends AndroidTestCase { ECKeyPair bobPreKey = Curve.generateKeyPair(true); - RatchetingSessionV3.initializeSession(aliceSessionState, aliceBaseKey, bobBaseKey.getPublicKey(), - aliceEphemeralKey, bobEphemeralKey.getPublicKey(), - alicePreKey, bobPreKey.getPublicKey(), - aliceIdentityKey, bobIdentityKey.getPublicKey()); + RatchetingSession.initializeSession(aliceSessionState, 3, aliceBaseKey, bobBaseKey.getPublicKey(), + aliceEphemeralKey, bobEphemeralKey.getPublicKey(), + alicePreKey, bobPreKey.getPublicKey(), + aliceIdentityKey, bobIdentityKey.getPublicKey()); - RatchetingSessionV3.initializeSession(bobSessionState, bobBaseKey, aliceBaseKey.getPublicKey(), - bobEphemeralKey, aliceEphemeralKey.getPublicKey(), - bobPreKey, alicePreKey.getPublicKey(), - bobIdentityKey, aliceIdentityKey.getPublicKey()); + RatchetingSession.initializeSession(bobSessionState, 3, bobBaseKey, aliceBaseKey.getPublicKey(), + bobEphemeralKey, aliceEphemeralKey.getPublicKey(), + bobPreKey, alicePreKey.getPublicKey(), + bobIdentityKey, aliceIdentityKey.getPublicKey()); } } diff --git a/libaxolotl/src/androidTest/java/org/whispersystems/test/ratchet/RatchetingSessionV2Test.java b/libaxolotl/src/androidTest/java/org/whispersystems/test/ratchet/RatchetingSessionTest.java similarity index 95% rename from libaxolotl/src/androidTest/java/org/whispersystems/test/ratchet/RatchetingSessionV2Test.java rename to libaxolotl/src/androidTest/java/org/whispersystems/test/ratchet/RatchetingSessionTest.java index 643dad0b21..b9e088b3fa 100644 --- a/libaxolotl/src/androidTest/java/org/whispersystems/test/ratchet/RatchetingSessionV2Test.java +++ b/libaxolotl/src/androidTest/java/org/whispersystems/test/ratchet/RatchetingSessionTest.java @@ -5,16 +5,16 @@ import android.test.AndroidTestCase; import org.whispersystems.libaxolotl.IdentityKey; import org.whispersystems.libaxolotl.IdentityKeyPair; import org.whispersystems.libaxolotl.InvalidKeyException; -import org.whispersystems.libaxolotl.state.SessionState; import org.whispersystems.libaxolotl.ecc.Curve; import org.whispersystems.libaxolotl.ecc.ECKeyPair; import org.whispersystems.libaxolotl.ecc.ECPrivateKey; import org.whispersystems.libaxolotl.ecc.ECPublicKey; -import org.whispersystems.libaxolotl.ratchet.RatchetingSessionV2; +import org.whispersystems.libaxolotl.ratchet.RatchetingSession; +import org.whispersystems.libaxolotl.state.SessionState; import java.util.Arrays; -public class RatchetingSessionV2Test extends AndroidTestCase { +public class RatchetingSessionTest extends AndroidTestCase { public void testRatchetingSessionAsBob() throws InvalidKeyException { byte[] bobPublic = {(byte) 0x05, (byte) 0x2c, (byte) 0xb4, (byte) 0x97, @@ -107,9 +107,10 @@ public class RatchetingSessionV2Test extends AndroidTestCase { SessionState session = new SessionState(); - RatchetingSessionV2.initializeSession(session, bobBaseKey, aliceBasePublicKey, - bobEphemeralKey, aliceEphemeralPublicKey, - bobIdentityKey, aliceIdentityPublicKey); + RatchetingSession.initializeSession(session, 2, bobBaseKey, aliceBasePublicKey, + bobEphemeralKey, aliceEphemeralPublicKey, + null, null, + bobIdentityKey, aliceIdentityPublicKey); assertTrue(session.getLocalIdentityKey().equals(bobIdentityKey.getPublicKey())); assertTrue(session.getRemoteIdentityKey().equals(aliceIdentityPublicKey)); @@ -204,9 +205,10 @@ public class RatchetingSessionV2Test extends AndroidTestCase { SessionState session = new SessionState(); - RatchetingSessionV2.initializeSession(session, aliceBaseKey, bobBasePublicKey, - aliceEphemeralKey, bobEphemeralPublicKey, - aliceIdentityKey, bobIdentityKey); + RatchetingSession.initializeSession(session, 2, aliceBaseKey, bobBasePublicKey, + aliceEphemeralKey, bobEphemeralPublicKey, + null, null, + aliceIdentityKey, bobIdentityKey); assertTrue(session.getLocalIdentityKey().equals(aliceIdentityKey.getPublicKey())); assertTrue(session.getRemoteIdentityKey().equals(bobIdentityKey)); diff --git a/libaxolotl/src/main/java/org/whispersystems/libaxolotl/SessionBuilder.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/SessionBuilder.java index 1f4a25d5a6..6cf95db2ae 100644 --- a/libaxolotl/src/main/java/org/whispersystems/libaxolotl/SessionBuilder.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/SessionBuilder.java @@ -7,8 +7,7 @@ import org.whispersystems.libaxolotl.ecc.ECKeyPair; import org.whispersystems.libaxolotl.ecc.ECPublicKey; import org.whispersystems.libaxolotl.protocol.KeyExchangeMessage; import org.whispersystems.libaxolotl.protocol.PreKeyWhisperMessage; -import org.whispersystems.libaxolotl.ratchet.RatchetingSessionV2; -import org.whispersystems.libaxolotl.ratchet.RatchetingSessionV3; +import org.whispersystems.libaxolotl.ratchet.RatchetingSession; import org.whispersystems.libaxolotl.state.DeviceKeyRecord; import org.whispersystems.libaxolotl.state.DeviceKeyStore; import org.whispersystems.libaxolotl.state.IdentityKeyStore; @@ -21,8 +20,6 @@ import org.whispersystems.libaxolotl.state.SessionStore; import org.whispersystems.libaxolotl.util.KeyHelper; import org.whispersystems.libaxolotl.util.Medium; -import java.util.Arrays; - /** * SessionBuilder is responsible for setting up encrypted sessions. * Once a session has been established, {@link org.whispersystems.libaxolotl.SessionCipher} @@ -138,11 +135,12 @@ public class SessionBuilder { if (!simultaneousInitiate) sessionRecord.reset(); else sessionRecord.archiveCurrentState(); - RatchetingSessionV3.initializeSession(sessionRecord.getSessionState(), - ourBaseKey, theirBaseKey, - ourEphemeralKey, theirEphemeralKey, - ourPreKey, theirPreKey, - ourIdentityKey, theirIdentityKey); + RatchetingSession.initializeSession(sessionRecord.getSessionState(), + message.getMessageVersion(), + ourBaseKey, theirBaseKey, + ourEphemeralKey, theirEphemeralKey, + ourPreKey, theirPreKey, + ourIdentityKey, theirIdentityKey); sessionRecord.getSessionState().setLocalRegistrationId(identityKeyStore.getLocalRegistrationId()); sessionRecord.getSessionState().setRemoteRegistrationId(message.getRegistrationId()); @@ -186,10 +184,12 @@ public class SessionBuilder { if (!simultaneousInitiate) sessionRecord.reset(); else sessionRecord.archiveCurrentState(); - RatchetingSessionV2.initializeSession(sessionRecord.getSessionState(), - ourBaseKey, theirBaseKey, - ourEphemeralKey, theirEphemeralKey, - ourIdentityKey, theirIdentityKey); + RatchetingSession.initializeSession(sessionRecord.getSessionState(), + message.getMessageVersion(), + ourBaseKey, theirBaseKey, + ourEphemeralKey, theirEphemeralKey, + null, null, + ourIdentityKey, theirIdentityKey); sessionRecord.getSessionState().setLocalRegistrationId(identityKeyStore.getLocalRegistrationId()); sessionRecord.getSessionState().setRemoteRegistrationId(message.getRegistrationId()); @@ -242,15 +242,11 @@ public class SessionBuilder { if (sessionRecord.getSessionState().getNeedsRefresh()) sessionRecord.archiveCurrentState(); else sessionRecord.reset(); - if (preKey.getDeviceKey() == null) { - RatchetingSessionV2.initializeSession(sessionRecord.getSessionState(), - ourBaseKey, theirBaseKey, ourEphemeralKey, - theirEphemeralKey, ourIdentityKey, theirIdentityKey); - } else { - RatchetingSessionV3.initializeSession(sessionRecord.getSessionState(), - ourBaseKey, theirBaseKey, ourEphemeralKey, theirEphemeralKey, - ourPreKey, theirPreKey, ourIdentityKey, theirIdentityKey); - } + RatchetingSession.initializeSession(sessionRecord.getSessionState(), + preKey.getDeviceKey() == null ? 2 : 3, + ourBaseKey, theirBaseKey, ourEphemeralKey, + theirEphemeralKey, ourPreKey, theirPreKey, + ourIdentityKey, theirIdentityKey); sessionRecord.getSessionState().setPendingPreKey(preKey.getPreKeyId(), preKey.getDeviceKeyId(), ourBaseKey.getPublicKey()); sessionRecord.getSessionState().setLocalRegistrationId(identityKeyStore.getLocalRegistrationId()); @@ -310,10 +306,12 @@ public class SessionBuilder { sessionRecord.reset(); - RatchetingSessionV2.initializeSession(sessionRecord.getSessionState(), - ourBaseKey, message.getBaseKey(), - ourEphemeralKey, message.getEphemeralKey(), - ourIdentityKey, message.getIdentityKey()); + RatchetingSession.initializeSession(sessionRecord.getSessionState(), + 2, + ourBaseKey, message.getBaseKey(), + ourEphemeralKey, message.getEphemeralKey(), + null, null, + ourIdentityKey, message.getIdentityKey()); sessionRecord.getSessionState().setSessionVersion(message.getVersion()); sessionStore.storeSession(recipientId, deviceId, sessionRecord); diff --git a/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/RatchetingSessionV3.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/RatchetingSession.java similarity index 86% rename from libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/RatchetingSessionV3.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/RatchetingSession.java index bc25ab8a62..7ec60046f0 100644 --- a/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/RatchetingSessionV3.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/RatchetingSession.java @@ -19,21 +19,22 @@ package org.whispersystems.libaxolotl.ratchet; import org.whispersystems.libaxolotl.IdentityKey; import org.whispersystems.libaxolotl.IdentityKeyPair; import org.whispersystems.libaxolotl.InvalidKeyException; -import org.whispersystems.libaxolotl.state.SessionState; import org.whispersystems.libaxolotl.ecc.Curve; import org.whispersystems.libaxolotl.ecc.ECKeyPair; import org.whispersystems.libaxolotl.ecc.ECPublicKey; import org.whispersystems.libaxolotl.kdf.DerivedSecrets; import org.whispersystems.libaxolotl.kdf.HKDF; +import org.whispersystems.libaxolotl.state.SessionState; import org.whispersystems.libaxolotl.util.Pair; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Arrays; -public class RatchetingSessionV3 { +public class RatchetingSession { public static void initializeSession(SessionState sessionState, + int sessionVersion, ECKeyPair ourBaseKey, ECPublicKey theirBaseKey, ECKeyPair ourEphemeralKey, @@ -45,17 +46,18 @@ public class RatchetingSessionV3 { throws InvalidKeyException { if (isAlice(ourBaseKey.getPublicKey(), theirBaseKey, ourEphemeralKey.getPublicKey(), theirEphemeralKey)) { - initializeSessionAsAlice(sessionState, ourBaseKey, theirBaseKey, theirEphemeralKey, + initializeSessionAsAlice(sessionState, sessionVersion, ourBaseKey, theirBaseKey, theirEphemeralKey, ourPreKey, theirPreKey, ourIdentityKey, theirIdentityKey); } else { - initializeSessionAsBob(sessionState, ourBaseKey, theirBaseKey, ourEphemeralKey, + initializeSessionAsBob(sessionState, sessionVersion, ourBaseKey, theirBaseKey, ourEphemeralKey, ourPreKey, theirPreKey, ourIdentityKey, theirIdentityKey); } - sessionState.setSessionVersion(3); + sessionState.setSessionVersion(sessionVersion); } private static void initializeSessionAsAlice(SessionState sessionState, + int sessionVersion, ECKeyPair ourBaseKey, ECPublicKey theirBaseKey, ECPublicKey theirEphemeralKey, ECKeyPair ourPreKey, ECPublicKey theirPreKey, @@ -67,7 +69,8 @@ public class RatchetingSessionV3 { sessionState.setLocalIdentityKey(ourIdentityKey.getPublicKey()); ECKeyPair sendingKey = Curve.generateKeyPair(true); - Pair receivingChain = calculate4DHE(true, ourBaseKey, theirBaseKey, + Pair receivingChain = calculate4DHE(true, sessionVersion, + ourBaseKey, theirBaseKey, ourPreKey, theirPreKey, ourIdentityKey, theirIdentityKey); Pair sendingChain = receivingChain.first().createChain(theirEphemeralKey, sendingKey); @@ -78,6 +81,7 @@ public class RatchetingSessionV3 { } private static void initializeSessionAsBob(SessionState sessionState, + int sessionVersion, ECKeyPair ourBaseKey, ECPublicKey theirBaseKey, ECKeyPair ourEphemeralKey, ECKeyPair ourPreKey, ECPublicKey theirPreKey, @@ -88,7 +92,8 @@ public class RatchetingSessionV3 { sessionState.setRemoteIdentityKey(theirIdentityKey); sessionState.setLocalIdentityKey(ourIdentityKey.getPublicKey()); - Pair sendingChain = calculate4DHE(false, ourBaseKey, theirBaseKey, + Pair sendingChain = calculate4DHE(false, sessionVersion, + ourBaseKey, theirBaseKey, ourPreKey, theirPreKey, ourIdentityKey, theirIdentityKey); @@ -96,18 +101,20 @@ public class RatchetingSessionV3 { sessionState.setRootKey(sendingChain.first()); } - private static Pair calculate4DHE(boolean isAlice, + private static Pair calculate4DHE(boolean isAlice, int sessionVersion, ECKeyPair ourEphemeral, ECPublicKey theirEphemeral, ECKeyPair ourPreKey, ECPublicKey theirPreKey, IdentityKeyPair ourIdentity, IdentityKey theirIdentity) throws InvalidKeyException { try { - byte[] discontinuity = new byte[32]; - ByteArrayOutputStream secrets = new ByteArrayOutputStream(); + byte[] discontinuity = new byte[32]; + ByteArrayOutputStream secrets = new ByteArrayOutputStream(); - Arrays.fill(discontinuity, (byte)0xFF); - secrets.write(discontinuity); + if (sessionVersion >= 3) { + Arrays.fill(discontinuity, (byte) 0xFF); + secrets.write(discontinuity); + } if (isAlice) { secrets.write(Curve.calculateAgreement(theirEphemeral, ourIdentity.getPrivateKey())); @@ -119,7 +126,7 @@ public class RatchetingSessionV3 { secrets.write(Curve.calculateAgreement(theirEphemeral, ourEphemeral.getPrivateKey())); - if (ourPreKey != null && theirPreKey != null) { + if (sessionVersion >= 3 && ourPreKey != null && theirPreKey != null) { secrets.write(Curve.calculateAgreement(theirPreKey, ourPreKey.getPrivateKey())); } diff --git a/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/RatchetingSessionV2.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/RatchetingSessionV2.java deleted file mode 100644 index b42b77649f..0000000000 --- a/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/RatchetingSessionV2.java +++ /dev/null @@ -1,138 +0,0 @@ -/** - * 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.IdentityKey; -import org.whispersystems.libaxolotl.IdentityKeyPair; -import org.whispersystems.libaxolotl.InvalidKeyException; -import org.whispersystems.libaxolotl.state.SessionState; -import org.whispersystems.libaxolotl.ecc.Curve; -import org.whispersystems.libaxolotl.ecc.ECKeyPair; -import org.whispersystems.libaxolotl.ecc.ECPublicKey; -import org.whispersystems.libaxolotl.kdf.DerivedSecrets; -import org.whispersystems.libaxolotl.kdf.HKDF; -import org.whispersystems.libaxolotl.util.Pair; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; - -public class RatchetingSessionV2 { - - public static void initializeSession(SessionState sessionState, - ECKeyPair ourBaseKey, - ECPublicKey theirBaseKey, - ECKeyPair ourEphemeralKey, - ECPublicKey theirEphemeralKey, - IdentityKeyPair ourIdentityKey, - IdentityKey theirIdentityKey) - throws InvalidKeyException - { - if (isAlice(ourBaseKey.getPublicKey(), theirBaseKey, ourEphemeralKey.getPublicKey(), theirEphemeralKey)) { - initializeSessionAsAlice(sessionState, ourBaseKey, theirBaseKey, theirEphemeralKey, - ourIdentityKey, theirIdentityKey); - } else { - initializeSessionAsBob(sessionState, ourBaseKey, theirBaseKey, - ourEphemeralKey, ourIdentityKey, theirIdentityKey); - } - - sessionState.setSessionVersion(2); - } - - private static void initializeSessionAsAlice(SessionState sessionState, - ECKeyPair ourBaseKey, ECPublicKey theirBaseKey, - ECPublicKey theirEphemeralKey, - IdentityKeyPair ourIdentityKey, - IdentityKey theirIdentityKey) - throws InvalidKeyException - { - sessionState.setRemoteIdentityKey(theirIdentityKey); - sessionState.setLocalIdentityKey(ourIdentityKey.getPublicKey()); - - ECKeyPair sendingKey = Curve.generateKeyPair(true); - Pair receivingChain = calculate3DHE(true, ourBaseKey, theirBaseKey, ourIdentityKey, theirIdentityKey); - Pair sendingChain = receivingChain.first().createChain(theirEphemeralKey, sendingKey); - - sessionState.addReceiverChain(theirEphemeralKey, receivingChain.second()); - sessionState.setSenderChain(sendingKey, sendingChain.second()); - sessionState.setRootKey(sendingChain.first()); - } - - private static void initializeSessionAsBob(SessionState sessionState, - ECKeyPair ourBaseKey, ECPublicKey theirBaseKey, - ECKeyPair ourEphemeralKey, - IdentityKeyPair ourIdentityKey, - IdentityKey theirIdentityKey) - throws InvalidKeyException - { - sessionState.setRemoteIdentityKey(theirIdentityKey); - sessionState.setLocalIdentityKey(ourIdentityKey.getPublicKey()); - - Pair sendingChain = calculate3DHE(false, ourBaseKey, theirBaseKey, - ourIdentityKey, theirIdentityKey); - - sessionState.setSenderChain(ourEphemeralKey, sendingChain.second()); - sessionState.setRootKey(sendingChain.first()); - } - - private static Pair calculate3DHE(boolean isAlice, - ECKeyPair ourEphemeral, ECPublicKey theirEphemeral, - IdentityKeyPair ourIdentity, IdentityKey theirIdentity) - throws InvalidKeyException - { - try { - ByteArrayOutputStream secrets = new ByteArrayOutputStream(); - - if (isAlice) { - secrets.write(Curve.calculateAgreement(theirEphemeral, ourIdentity.getPrivateKey())); - secrets.write(Curve.calculateAgreement(theirIdentity.getPublicKey(), ourEphemeral.getPrivateKey())); - } else { - secrets.write(Curve.calculateAgreement(theirIdentity.getPublicKey(), ourEphemeral.getPrivateKey())); - secrets.write(Curve.calculateAgreement(theirEphemeral, ourIdentity.getPrivateKey())); - } - - secrets.write(Curve.calculateAgreement(theirEphemeral, ourEphemeral.getPrivateKey())); - - DerivedSecrets derivedSecrets = new HKDF().deriveSecrets(secrets.toByteArray(), - "WhisperText".getBytes()); - - return new Pair(new RootKey(derivedSecrets.getCipherKey().getEncoded()), - new ChainKey(derivedSecrets.getMacKey().getEncoded(), 0)); - } catch (IOException e) { - throw new AssertionError(e); - } - } - - private static boolean isAlice(ECPublicKey ourBaseKey, ECPublicKey theirBaseKey, - ECPublicKey ourEphemeralKey, ECPublicKey theirEphemeralKey) - { - if (ourEphemeralKey.equals(ourBaseKey)) { - return false; - } - - if (theirEphemeralKey.equals(theirBaseKey)) { - return true; - } - - return isLowEnd(ourBaseKey, theirBaseKey); - } - - private static boolean isLowEnd(ECPublicKey ourKey, ECPublicKey theirKey) { - return ourKey.compareTo(theirKey) < 0; - } - - -}