From d902c12941c362bf75165a2b2b9c7430e13ef6dc Mon Sep 17 00:00:00 2001 From: Moxie Marlinspike Date: Mon, 21 Apr 2014 08:40:19 -0700 Subject: [PATCH] Break core ratchet out into libaxolotol. 1) Break the core cryptography functions out into libaxolotol. 2) The objective for this code is a Java library that isn't dependent on any Android functions. However, while the code has been separated from any Android functionality, it is still an 'android library project' because of the JNI. --- build.gradle | 6 + libaxolotl/.gitignore | 2 + libaxolotl/build.gradle | 34 ++ {library => libaxolotl}/jni/Android.mk | 0 {library => libaxolotl}/jni/Application.mk | 0 .../jni/curve25519-donna-jni.c | 6 +- .../jni/curve25519-donna.c | 0 .../jni/curve25519-donna.h | 0 .../libs/armeabi-v7a/libcurve25519.so | Bin 17532 -> 17532 bytes .../libs/armeabi/libcurve25519.so | Bin 21624 -> 21624 bytes .../libs/x86/libcurve25519.so | Bin 17488 -> 17488 bytes libaxolotl/protobuf/Makefile | 3 + .../protobuf/WhisperTextProtocol.proto | 2 +- .../test/InMemorySessionState.java | 321 ++++++++++++++++++ .../test/InMemorySessionStore.java | 44 +++ .../test/SessionCipherTest.java | 76 +++++ .../test/ecc/Curve25519Test.java | 82 +++++ .../org/whispersystems/test/kdf/HKDFTest.java | 44 +++ .../test/ratchet/ChainKeyTest.java | 58 ++++ .../test/ratchet/RatchetingSessionTest.java | 218 ++++++++++++ .../test/ratchet/RootKeyTest.java | 83 +++++ libaxolotl/src/main/AndroidManifest.xml | 7 + .../DuplicateMessageException.java | 2 +- .../libaxolotl/IdentityKey.java | 66 ++++ .../libaxolotl}/IdentityKeyPair.java | 4 +- .../libaxolotl}/InvalidKeyException.java | 12 +- .../libaxolotl}/InvalidMacException.java | 16 +- .../libaxolotl}/InvalidMessageException.java | 16 +- .../libaxolotl/InvalidVersionException.java | 16 +- .../libaxolotl}/LegacyMessageException.java | 2 +- .../libaxolotl}/SessionCipher.java | 112 +++--- .../libaxolotl/SessionState.java | 54 +++ .../libaxolotl/SessionStore.java | 12 + .../whispersystems/libaxolotl}/ecc/Curve.java | 5 +- .../libaxolotl}/ecc/Curve25519.java | 4 +- .../libaxolotl}/ecc/DjbECPrivateKey.java | 2 +- .../libaxolotl}/ecc/DjbECPublicKey.java | 6 +- .../libaxolotl}/ecc/ECKeyPair.java | 2 +- .../libaxolotl}/ecc/ECPrivateKey.java | 2 +- .../libaxolotl}/ecc/ECPublicKey.java | 2 +- .../libaxolotl}/kdf/DerivedSecrets.java | 2 +- .../whispersystems/libaxolotl}/kdf/HKDF.java | 4 +- .../protocol/CiphertextMessage.java | 33 ++ .../protocol/PreKeyWhisperMessage.java | 42 ++- .../libaxolotl}/protocol/WhisperMessage.java | 53 +-- .../libaxolotl}/protocol/WhisperProtos.java | 200 +++++------ .../libaxolotl}/ratchet/ChainKey.java | 27 +- .../libaxolotl/ratchet/MessageKeys.java | 44 +++ .../ratchet/RatchetingSession.java | 52 ++- .../libaxolotl/ratchet/RootKey.java | 50 +++ .../libaxolotl/util/ByteUtil.java | 241 +++++++++++++ .../whispersystems/libaxolotl/util/Hex.java | 78 +++++ .../whispersystems/libaxolotl/util/Pair.java | 51 +++ library/build.gradle | 8 + .../textsecure/crypto/AttachmentCipher.java | 2 + .../crypto/AttachmentCipherInputStream.java | 2 + .../textsecure/crypto/IdentityKey.java | 113 ------ .../crypto/IdentityKeyParcelable.java | 69 ++++ .../crypto/InvalidVersionException.java | 40 --- .../textsecure/crypto/MasterCipher.java | 9 +- .../textsecure/crypto/PreKeyUtil.java | 4 +- .../textsecure/crypto/PublicKey.java | 5 +- .../crypto/SessionCipherFactory.java | 39 +++ .../textsecure/crypto/kdf/NKDF.java | 86 ----- .../crypto/protocol/CiphertextMessage.java | 17 - .../crypto/ratchet/MessageKeys.java | 28 -- .../textsecure/crypto/ratchet/RootKey.java | 38 --- .../push/IncomingEncryptedPushMessage.java | 2 +- .../textsecure/push/PreKeyEntity.java | 8 +- .../textsecure/push/PushServiceSocket.java | 2 +- .../textsecure/storage/PreKeyRecord.java | 12 +- .../textsecure/storage/Record.java | 4 +- .../textsecure/storage/Session.java | 5 +- .../textsecure/storage/SessionKey.java | 115 ------- .../textsecure/storage/SessionRecordV2.java | 31 +- ...State.java => TextSecureSessionState.java} | 59 ++-- .../storage/{ => legacy}/LocalKeyRecord.java | 5 +- .../storage/{ => legacy}/RemoteKeyRecord.java | 15 +- .../storage/{ => legacy}/SessionRecordV1.java | 5 +- settings.gradle | 2 +- .../securesms/ConversationActivity.java | 2 +- .../securesms/KeyScanningActivity.java | 6 +- .../securesms/ReceiveKeyActivity.java | 17 +- .../securesms/VerifyIdentityActivity.java | 10 +- .../securesms/ViewIdentityActivity.java | 18 +- .../securesms/ViewLocalIdentityActivity.java | 73 +--- .../securesms/contacts/ContactAccessor.java | 51 --- .../crypto/AsymmetricMasterCipher.java | 12 +- .../crypto/AsymmetricMasterSecret.java | 7 +- .../securesms/crypto/DecryptingQueue.java | 21 +- .../securesms/crypto/IdentityKeyUtil.java | 12 +- .../crypto/KeyExchangeInitiator.java | 6 +- .../crypto/KeyExchangeProcessor.java | 4 +- .../crypto/KeyExchangeProcessorV2.java | 18 +- .../securesms/crypto/MasterSecretUtil.java | 14 +- .../crypto/protocol/KeyExchangeMessage.java | 10 +- .../crypto/protocol/KeyExchangeMessageV2.java | 18 +- .../securesms/database/DatabaseFactory.java | 6 +- .../securesms/database/DraftDatabase.java | 2 +- .../database/EncryptingSmsDatabase.java | 2 +- .../securesms/database/IdentityDatabase.java | 6 +- .../securesms/database/MmsDatabase.java | 2 +- .../securesms/database/ThreadDatabase.java | 2 +- .../securesms/gcm/GcmBroadcastReceiver.java | 2 +- .../securesms/service/AvatarDownloader.java | 2 +- .../securesms/service/PreKeyService.java | 3 +- .../securesms/service/PushDownloader.java | 2 +- .../securesms/service/PushReceiver.java | 8 +- .../service/RegistrationService.java | 2 +- .../securesms/service/SmsReceiver.java | 12 +- .../sms/IncomingIdentityUpdateMessage.java | 2 +- .../securesms/sms/SmsTransportDetails.java | 2 +- .../securesms/transport/MmsTransport.java | 7 +- .../securesms/transport/PushTransport.java | 13 +- .../securesms/transport/SmsTransport.java | 7 +- .../transport/UntrustedIdentityException.java | 3 +- 116 files changed, 2268 insertions(+), 1039 deletions(-) create mode 100644 libaxolotl/.gitignore create mode 100644 libaxolotl/build.gradle rename {library => libaxolotl}/jni/Android.mk (100%) rename {library => libaxolotl}/jni/Application.mk (100%) rename {library => libaxolotl}/jni/curve25519-donna-jni.c (88%) rename {library => libaxolotl}/jni/curve25519-donna.c (100%) rename {library => libaxolotl}/jni/curve25519-donna.h (100%) rename {library => libaxolotl}/libs/armeabi-v7a/libcurve25519.so (76%) rename {library => libaxolotl}/libs/armeabi/libcurve25519.so (80%) rename {library => libaxolotl}/libs/x86/libcurve25519.so (80%) create mode 100644 libaxolotl/protobuf/Makefile rename {library => libaxolotl}/protobuf/WhisperTextProtocol.proto (90%) create mode 100644 libaxolotl/src/androidTest/java/org/whispersystems/test/InMemorySessionState.java create mode 100644 libaxolotl/src/androidTest/java/org/whispersystems/test/InMemorySessionStore.java create mode 100644 libaxolotl/src/androidTest/java/org/whispersystems/test/SessionCipherTest.java create mode 100644 libaxolotl/src/androidTest/java/org/whispersystems/test/ecc/Curve25519Test.java create mode 100644 libaxolotl/src/androidTest/java/org/whispersystems/test/kdf/HKDFTest.java create mode 100644 libaxolotl/src/androidTest/java/org/whispersystems/test/ratchet/ChainKeyTest.java create mode 100644 libaxolotl/src/androidTest/java/org/whispersystems/test/ratchet/RatchetingSessionTest.java create mode 100644 libaxolotl/src/androidTest/java/org/whispersystems/test/ratchet/RootKeyTest.java create mode 100644 libaxolotl/src/main/AndroidManifest.xml rename {library/src/org/whispersystems/textsecure/crypto => libaxolotl/src/main/java/org/whispersystems/libaxolotl}/DuplicateMessageException.java (73%) create mode 100644 libaxolotl/src/main/java/org/whispersystems/libaxolotl/IdentityKey.java rename {library/src/org/whispersystems/textsecure/crypto => libaxolotl/src/main/java/org/whispersystems/libaxolotl}/IdentityKeyPair.java (91%) rename {library/src/org/whispersystems/textsecure/crypto => libaxolotl/src/main/java/org/whispersystems/libaxolotl}/InvalidKeyException.java (76%) rename {library/src/org/whispersystems/textsecure/crypto => libaxolotl/src/main/java/org/whispersystems/libaxolotl}/InvalidMacException.java (67%) rename {library/src/org/whispersystems/textsecure/crypto => libaxolotl/src/main/java/org/whispersystems/libaxolotl}/InvalidMessageException.java (77%) rename library/src/org/whispersystems/textsecure/crypto/SerializableKey.java => libaxolotl/src/main/java/org/whispersystems/libaxolotl/InvalidVersionException.java (73%) rename {library/src/org/whispersystems/textsecure/crypto => libaxolotl/src/main/java/org/whispersystems/libaxolotl}/LegacyMessageException.java (72%) rename {library/src/org/whispersystems/textsecure/crypto => libaxolotl/src/main/java/org/whispersystems/libaxolotl}/SessionCipher.java (69%) create mode 100644 libaxolotl/src/main/java/org/whispersystems/libaxolotl/SessionState.java create mode 100644 libaxolotl/src/main/java/org/whispersystems/libaxolotl/SessionStore.java rename {library/src/org/whispersystems/textsecure/crypto => libaxolotl/src/main/java/org/whispersystems/libaxolotl}/ecc/Curve.java (90%) rename {library/src/org/whispersystems/textsecure/crypto => libaxolotl/src/main/java/org/whispersystems/libaxolotl}/ecc/Curve25519.java (95%) rename {library/src/org/whispersystems/textsecure/crypto => libaxolotl/src/main/java/org/whispersystems/libaxolotl}/ecc/DjbECPrivateKey.java (95%) rename {library/src/org/whispersystems/textsecure/crypto => libaxolotl/src/main/java/org/whispersystems/libaxolotl}/ecc/DjbECPublicKey.java (92%) rename {library/src/org/whispersystems/textsecure/crypto => libaxolotl/src/main/java/org/whispersystems/libaxolotl}/ecc/ECKeyPair.java (95%) rename {library/src/org/whispersystems/textsecure/crypto => libaxolotl/src/main/java/org/whispersystems/libaxolotl}/ecc/ECPrivateKey.java (94%) rename {library/src/org/whispersystems/textsecure/crypto => libaxolotl/src/main/java/org/whispersystems/libaxolotl}/ecc/ECPublicKey.java (94%) rename {library/src/org/whispersystems/textsecure/crypto => libaxolotl/src/main/java/org/whispersystems/libaxolotl}/kdf/DerivedSecrets.java (95%) rename {library/src/org/whispersystems/textsecure/crypto => libaxolotl/src/main/java/org/whispersystems/libaxolotl}/kdf/HKDF.java (97%) create mode 100644 libaxolotl/src/main/java/org/whispersystems/libaxolotl/protocol/CiphertextMessage.java rename {library/src/org/whispersystems/textsecure/crypto => libaxolotl/src/main/java/org/whispersystems/libaxolotl}/protocol/PreKeyWhisperMessage.java (71%) rename {library/src/org/whispersystems/textsecure/crypto => libaxolotl/src/main/java/org/whispersystems/libaxolotl}/protocol/WhisperMessage.java (65%) rename {library/src/org/whispersystems/textsecure/crypto => libaxolotl/src/main/java/org/whispersystems/libaxolotl}/protocol/WhisperProtos.java (82%) rename {library/src/org/whispersystems/textsecure/crypto => libaxolotl/src/main/java/org/whispersystems/libaxolotl}/ratchet/ChainKey.java (58%) create mode 100644 libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/MessageKeys.java rename {library/src/org/whispersystems/textsecure/crypto => libaxolotl/src/main/java/org/whispersystems/libaxolotl}/ratchet/RatchetingSession.java (74%) create mode 100644 libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/RootKey.java create mode 100644 libaxolotl/src/main/java/org/whispersystems/libaxolotl/util/ByteUtil.java create mode 100644 libaxolotl/src/main/java/org/whispersystems/libaxolotl/util/Hex.java create mode 100644 libaxolotl/src/main/java/org/whispersystems/libaxolotl/util/Pair.java delete mode 100644 library/src/org/whispersystems/textsecure/crypto/IdentityKey.java create mode 100644 library/src/org/whispersystems/textsecure/crypto/IdentityKeyParcelable.java delete mode 100644 library/src/org/whispersystems/textsecure/crypto/InvalidVersionException.java create mode 100644 library/src/org/whispersystems/textsecure/crypto/SessionCipherFactory.java delete mode 100644 library/src/org/whispersystems/textsecure/crypto/kdf/NKDF.java delete mode 100644 library/src/org/whispersystems/textsecure/crypto/protocol/CiphertextMessage.java delete mode 100644 library/src/org/whispersystems/textsecure/crypto/ratchet/MessageKeys.java delete mode 100644 library/src/org/whispersystems/textsecure/crypto/ratchet/RootKey.java delete mode 100644 library/src/org/whispersystems/textsecure/storage/SessionKey.java rename library/src/org/whispersystems/textsecure/storage/{SessionState.java => TextSecureSessionState.java} (90%) rename library/src/org/whispersystems/textsecure/storage/{ => legacy}/LocalKeyRecord.java (86%) rename library/src/org/whispersystems/textsecure/storage/{ => legacy}/RemoteKeyRecord.java (73%) rename library/src/org/whispersystems/textsecure/storage/{ => legacy}/SessionRecordV1.java (65%) diff --git a/build.gradle b/build.gradle index c71520804..84e6cc5c5 100644 --- a/build.gradle +++ b/build.gradle @@ -101,6 +101,12 @@ android { } } +tasks.whenTaskAdded { task -> + if (task.name.equals("lint")) { + task.enabled = false + } +} + def Properties props = new Properties() def propFile = new File('signing.properties') diff --git a/libaxolotl/.gitignore b/libaxolotl/.gitignore new file mode 100644 index 000000000..7673526e0 --- /dev/null +++ b/libaxolotl/.gitignore @@ -0,0 +1,2 @@ +/build +/obj diff --git a/libaxolotl/build.gradle b/libaxolotl/build.gradle new file mode 100644 index 000000000..2774bffb1 --- /dev/null +++ b/libaxolotl/build.gradle @@ -0,0 +1,34 @@ +apply plugin: 'android-library' + +repositories { + mavenCentral() +} + +dependencies { + compile 'com.google.protobuf:protobuf-java:2.4.1' +} + +android { + compileSdkVersion 19 + buildToolsVersion '19.1.0' + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_7 + targetCompatibility JavaVersion.VERSION_1_7 + } + + android { + sourceSets { + main { + jniLibs.srcDirs = ['libs'] + } + } + } + +} + +tasks.whenTaskAdded { task -> + if (task.name.equals("lint")) { + task.enabled = false + } +} \ No newline at end of file diff --git a/library/jni/Android.mk b/libaxolotl/jni/Android.mk similarity index 100% rename from library/jni/Android.mk rename to libaxolotl/jni/Android.mk diff --git a/library/jni/Application.mk b/libaxolotl/jni/Application.mk similarity index 100% rename from library/jni/Application.mk rename to libaxolotl/jni/Application.mk diff --git a/library/jni/curve25519-donna-jni.c b/libaxolotl/jni/curve25519-donna-jni.c similarity index 88% rename from library/jni/curve25519-donna-jni.c rename to libaxolotl/jni/curve25519-donna-jni.c index 4ce32bb63..71862ce22 100644 --- a/library/jni/curve25519-donna-jni.c +++ b/libaxolotl/jni/curve25519-donna-jni.c @@ -21,7 +21,7 @@ #include #include "curve25519-donna.h" -JNIEXPORT jbyteArray JNICALL Java_org_whispersystems_textsecure_crypto_ecc_Curve25519_generatePrivateKey +JNIEXPORT jbyteArray JNICALL Java_org_whispersystems_libaxolotl_ecc_Curve25519_generatePrivateKey (JNIEnv *env, jclass clazz, jbyteArray random, jboolean ephemeral) { uint8_t* privateKey = (uint8_t*)(*env)->GetByteArrayElements(env, random, 0); @@ -40,7 +40,7 @@ JNIEXPORT jbyteArray JNICALL Java_org_whispersystems_textsecure_crypto_ecc_Curve return random; } -JNIEXPORT jbyteArray JNICALL Java_org_whispersystems_textsecure_crypto_ecc_Curve25519_generatePublicKey +JNIEXPORT jbyteArray JNICALL Java_org_whispersystems_libaxolotl_ecc_Curve25519_generatePublicKey (JNIEnv *env, jclass clazz, jbyteArray privateKey) { static const uint8_t basepoint[32] = {9}; @@ -57,7 +57,7 @@ JNIEXPORT jbyteArray JNICALL Java_org_whispersystems_textsecure_crypto_ecc_Curve return publicKey; } -JNIEXPORT jbyteArray JNICALL Java_org_whispersystems_textsecure_crypto_ecc_Curve25519_calculateAgreement +JNIEXPORT jbyteArray JNICALL Java_org_whispersystems_libaxolotl_ecc_Curve25519_calculateAgreement (JNIEnv *env, jclass clazz, jbyteArray privateKey, jbyteArray publicKey) { jbyteArray sharedKey = (*env)->NewByteArray(env, 32); diff --git a/library/jni/curve25519-donna.c b/libaxolotl/jni/curve25519-donna.c similarity index 100% rename from library/jni/curve25519-donna.c rename to libaxolotl/jni/curve25519-donna.c diff --git a/library/jni/curve25519-donna.h b/libaxolotl/jni/curve25519-donna.h similarity index 100% rename from library/jni/curve25519-donna.h rename to libaxolotl/jni/curve25519-donna.h diff --git a/library/libs/armeabi-v7a/libcurve25519.so b/libaxolotl/libs/armeabi-v7a/libcurve25519.so similarity index 76% rename from library/libs/armeabi-v7a/libcurve25519.so rename to libaxolotl/libs/armeabi-v7a/libcurve25519.so index 3fa1b15aa8b334258988015469018f1a5a10caf6..57efd28a843b65155d1aae40297f7ad53c6b42a6 100755 GIT binary patch delta 1471 zcmaKsT}V_x6vxl#Ue{GO?z&5A6mG6jWZ*}F3E{`Of}jr)1(FnIf=C+*8mtiP?IlzS zmFYoE$iV2Kgy2T_ps_-U^bkTsy;LUJ7d}{71S#8pc4yh~J~S|#^E>}@=bo86_iPWa z?EyB@p|w>KwT*UlJMC*TTVgvWU zw-kN~eys2+_?f~x4DW9$OD>R`LS!JpgOFJ8C^#|1j!M9x!^sn?0k0|CtmJ!<-(le^ zVB#g5N{x4`=)_ks12WZiTwNENw7`wEO<)Mm%$NmMCzZx$_a<*F9Ln2 zuuvv=u#(C};4wu%Y2iljoT7JH_!@Xc(Z_ai*iJJD*zipXWdREoeg*ba5Y0mfeyJCOq#(JVOe7nOq}3O9mn%}B=3J@h?#N)3R|^VhaOMzE{>LZ~~~-52CH zwLD&@RqhToDrkPy9@sd~=w}*tW>)Z?N{<6qozgJv+{toyDDwzQHScEn*kx}WqKm_; zwih>6y+7yH6MnAZ>x!SQ_@wxMek7mWRQxZBzrstMZr8G3+>bl!M8hi|qS0>=^NjP- zUiQ{p@V#Md%^W|}nwCO^=I^2>*`jt<&S$FfT`gJhAJK(+#nkz`s*2JHaatfFgGlW0 zB3RfSX+zQ)uzL_6mW!RKpz znvTbGz79_m+`^rHpChr1!C9S~H~F(PFZ!gHpM$o9yC7ymOq+xjYsP#AnkZ9DFRu-_ J%?*JPD48_~@sCO&qs98(?Ty`D(S^%7pYuKUzH{$=_eKL! zG$0MP$o>i<|43Vh*|m=--bX&PDveo0ULvwnI<>)?iqJLggB^w5uJLo&cezAg%!&L3 zuz54l1x+uI;AqVbTdd=~IzA|olFTO?yhfg&6_AgDI)wrGkOJV1!bE{w9|PYnNld{P z@Bn;U;FsX10)Gd;71(aT_nS&n6YMe&1(A@05TCFLoNRnWwcvprsU15G-VoR)M8z1fCc4^E$o)UKjMxAFQO)ECO3`CN8aj*E;?TE+{9e*7Tp? zGhm!jd+F@m?G!019HVbmBW8W)v$cW$oevRBw{}@%2~bFl#9~i4TnJZDy1cm(pf|1 zeu>nna!s%C3-=3Yw)7rhyw}qPRrVlOIJXENHZW2C)(rR7)yj zSp>NcM)qJBSIS6Xp^%7>1fd=_QCY*nm!e<;#s0H9i{pK0;4+?G0ywDfZ}6hRnOIk# z6yz&}qE}J4z@CF!ci)Xmg23XC#fcmMhrrQSRtiNe6ydl6+yd5`;f=A2er~pz z*vtQDH7TC<)|RdgPlwmT$MoI&oL;eAby7hi*%H+F$CNInb608^4^(B@EZ7~l9r0pA z<4;l#vjk%))yeY1ZYXE^mh}(*zsbT@4O_{hY!RJ#`B;69Z7?nNl*HQ?UmgEiUsgOW>IF@t z#4_v#i%f6I`L3MrV@CI(VeV?U?DC+!iLNFZnCKaz512;?@&5Z68x2E@jq`hrIl2fx z!CyBz^*Su8<4cf4!h<~7?bM^&@M1{K=#b6)tlMc>!%tkRGzQTi|s7 delta 1473 zcmaKsT}V_x6vxlCd;M&~6?+H-mt6@hjf~8s(ntj>(OfY4f(=|VDKOMzC1fkMDA-zU zj0!D<7BW&0Zc@QM2xUz@QUPDVV-m+f7nFDnxJW9< zy#tO;$#DSe$%%XewO}vUFDg0*UcU*iMQ|6m6de9Wbnrtkua4iqOYj(26+8_dkHp>d z1CDt(28AFAO8JUcgZpv7G!ZW_@LupMDPCjXCU8)SU-^UGG1Lo33a&g&BzSD#G4OUN z{?Wj{zLG;B;^R%rBYWNC|ij9Qw;P!r_2pKI{NDfz`uMVxb7Qruv7x%^WPP=xs=oO|V;$?#Rw{S3iGE|PBU%~Nzh`%(C|=fA zmTK-@zW4|7mcgf!y(!Dh9^%&o8i^<3g#pMmf9&|pF diff --git a/library/libs/x86/libcurve25519.so b/libaxolotl/libs/x86/libcurve25519.so similarity index 80% rename from library/libs/x86/libcurve25519.so rename to libaxolotl/libs/x86/libcurve25519.so index bb80ed1ea8d5277b013c6a5ede59c0662d115665..f4bc66c4ab6715e10aa844958f685e76eb3cc151 100755 GIT binary patch delta 776 zcmZ9KPiPZS5XR>v*=Qq`LLQ{TVV#YIziZEC?Z!w1dX zE))6~{moeT1{}Y6Hq!Wpd7=}B_SG*UPE}XfW$9A4xzFN`JRBq{r2RkZ(;@<~{z$c0 z81F&t_Gaz%)_%P(?S#K#@z+QAs->c;oY0P|YkXJBsn2D<_54;74^HZ@M6$m`YTzx9UW*(8{a^(Qf-k_Q;3}vuh&X@4FN(y#RWJ>D z--zVF)RM>(Fj*6+gZ57%+i)Rgz@))1r~|!U@qQ5{Wk=-w2KGj}aiHa$9*2%w-+~J= zrf#e}yZfV|QOv^_MFP9VXrc%P6K(Ekb3eEd`C~lOKVf@`>LsidbJ-RfR%(<_$32?y yjs%zDJ}nQG=f_Y+S6nqz1**aw13s1sx`_u*1a2$_W`%vKCo}Zi%Ge zVDcR5Akr;_4#7N3h)|@P!OH$z!qn4C5x9uxQcvI4t&8}B=lML}=Xv=3FHWf9gvuqV z>q10zq3P@AoattwZJSL=e>U zEa$SRiGrWMvUUi-~5Un6uVQ0jr8(7fbV8q7{A~k$5(x5K}h!#16+V+pn I&qbc8f40XG6aWAK diff --git a/libaxolotl/protobuf/Makefile b/libaxolotl/protobuf/Makefile new file mode 100644 index 000000000..fae3824f1 --- /dev/null +++ b/libaxolotl/protobuf/Makefile @@ -0,0 +1,3 @@ + +all: + protoc --java_out=../src/main/java/ WhisperTextProtocol.proto diff --git a/library/protobuf/WhisperTextProtocol.proto b/libaxolotl/protobuf/WhisperTextProtocol.proto similarity index 90% rename from library/protobuf/WhisperTextProtocol.proto rename to libaxolotl/protobuf/WhisperTextProtocol.proto index 259d93b8e..a0b0a5d0d 100644 --- a/library/protobuf/WhisperTextProtocol.proto +++ b/libaxolotl/protobuf/WhisperTextProtocol.proto @@ -1,6 +1,6 @@ package textsecure; -option java_package = "org.whispersystems.textsecure.crypto.protocol"; +option java_package = "org.whispersystems.libaxolotl.protocol"; option java_outer_classname = "WhisperProtos"; message WhisperMessage { diff --git a/libaxolotl/src/androidTest/java/org/whispersystems/test/InMemorySessionState.java b/libaxolotl/src/androidTest/java/org/whispersystems/test/InMemorySessionState.java new file mode 100644 index 000000000..44c103289 --- /dev/null +++ b/libaxolotl/src/androidTest/java/org/whispersystems/test/InMemorySessionState.java @@ -0,0 +1,321 @@ +package org.whispersystems.test; + +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.libaxolotl.IdentityKeyPair; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.SessionState; +import org.whispersystems.libaxolotl.ecc.ECKeyPair; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; +import org.whispersystems.libaxolotl.ratchet.ChainKey; +import org.whispersystems.libaxolotl.ratchet.MessageKeys; +import org.whispersystems.libaxolotl.ratchet.RootKey; +import org.whispersystems.libaxolotl.util.Pair; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import javax.crypto.spec.SecretKeySpec; + +public class InMemorySessionState implements SessionState { + + private Map receiverChains = new HashMap<>(); + + private boolean needsRefresh; + private int sessionVersion; + private IdentityKey remoteIdentityKey; + private IdentityKey localIdentityKey; + private int previousCounter; + private RootKey rootKey; + private ECKeyPair senderEphemeral; + private ChainKey senderChainKey; + private int pendingPreKeyid; + private ECPublicKey pendingPreKey; + private int remoteRegistrationId; + private int localRegistrationId; + + public InMemorySessionState() {} + + public InMemorySessionState(SessionState sessionState) { + try { + this.needsRefresh = sessionState.getNeedsRefresh(); + this.sessionVersion = sessionState.getSessionVersion(); + this.remoteIdentityKey = new IdentityKey(sessionState.getRemoteIdentityKey().serialize(), 0); + this.localIdentityKey = new IdentityKey(sessionState.getLocalIdentityKey().serialize(), 0); + this.previousCounter = sessionState.getPreviousCounter(); + this.rootKey = new RootKey(sessionState.getRootKey().getKeyBytes()); + this.senderEphemeral = sessionState.getSenderEphemeralPair(); + this.senderChainKey = new ChainKey(sessionState.getSenderChainKey().getKey(), + sessionState.getSenderChainKey().getIndex()); + this.pendingPreKeyid = sessionState.getPendingPreKey().first(); + this.pendingPreKey = sessionState.getPendingPreKey().second(); + this.remoteRegistrationId = sessionState.getRemoteRegistrationId(); + this.localRegistrationId = sessionState.getLocalRegistrationId(); + } catch (InvalidKeyException e) { + throw new AssertionError(e); + } + } + + @Override + public void setNeedsRefresh(boolean needsRefresh) { + this.needsRefresh = needsRefresh; + } + + @Override + public boolean getNeedsRefresh() { + return needsRefresh; + } + + @Override + public void setSessionVersion(int version) { + this.sessionVersion = version; + } + + @Override + public int getSessionVersion() { + return sessionVersion; + } + + @Override + public void setRemoteIdentityKey(IdentityKey identityKey) { + this.remoteIdentityKey = identityKey; + } + + @Override + public void setLocalIdentityKey(IdentityKey identityKey) { + this.localIdentityKey = identityKey; + + } + + @Override + public IdentityKey getRemoteIdentityKey() { + return remoteIdentityKey; + } + + @Override + public IdentityKey getLocalIdentityKey() { + return localIdentityKey; + } + + @Override + public int getPreviousCounter() { + return previousCounter; + } + + @Override + public void setPreviousCounter(int previousCounter) { + this.previousCounter = previousCounter; + } + + @Override + public RootKey getRootKey() { + return rootKey; + } + + @Override + public void setRootKey(RootKey rootKey) { + this.rootKey = rootKey; + } + + @Override + public ECPublicKey getSenderEphemeral() { + return senderEphemeral.getPublicKey(); + } + + @Override + public ECKeyPair getSenderEphemeralPair() { + return senderEphemeral; + } + + @Override + public boolean hasReceiverChain(ECPublicKey senderEphemeral) { + return receiverChains.containsKey(senderEphemeral); + } + + @Override + public boolean hasSenderChain() { + return senderChainKey != null; + } + + @Override + public ChainKey getReceiverChainKey(ECPublicKey senderEphemeral) { + InMemoryChain chain = receiverChains.get(senderEphemeral); + return new ChainKey(chain.chainKey, chain.index); + } + + @Override + public void addReceiverChain(ECPublicKey senderEphemeral, ChainKey chainKey) { + InMemoryChain chain = new InMemoryChain(); + chain.chainKey = chainKey.getKey(); + chain.index = chainKey.getIndex(); + + receiverChains.put(senderEphemeral, chain); + } + + @Override + public void setSenderChain(ECKeyPair senderEphemeralPair, ChainKey chainKey) { + this.senderEphemeral = senderEphemeralPair; + this.senderChainKey = chainKey; + } + + @Override + public ChainKey getSenderChainKey() { + return senderChainKey; + } + + @Override + public void setSenderChainKey(ChainKey nextChainKey) { + this.senderChainKey = nextChainKey; + } + + @Override + public boolean hasMessageKeys(ECPublicKey senderEphemeral, int counter) { + InMemoryChain chain = receiverChains.get(senderEphemeral); + + if (chain == null) return false; + + for (InMemoryChain.InMemoryMessageKey messageKey : chain.messageKeys) { + if (messageKey.index == counter) { + return true; + } + } + + return false; + } + + @Override + public MessageKeys removeMessageKeys(ECPublicKey senderEphemeral, int counter) { + InMemoryChain chain = receiverChains.get(senderEphemeral); + MessageKeys results = null; + + if (chain == null) return null; + + Iterator iterator = chain.messageKeys.iterator(); + + while (iterator.hasNext()) { + InMemoryChain.InMemoryMessageKey messageKey = iterator.next(); + + if (messageKey.index == counter) { + results = new MessageKeys(new SecretKeySpec(messageKey.cipherKey, "AES"), + new SecretKeySpec(messageKey.macKey, "HmacSHA256"), + messageKey.index); + + iterator.remove(); + break; + } + } + + return results; + } + + @Override + public void setMessageKeys(ECPublicKey senderEphemeral, MessageKeys messageKeys) { + InMemoryChain chain = receiverChains.get(senderEphemeral); + InMemoryChain.InMemoryMessageKey key = new InMemoryChain.InMemoryMessageKey(); + + key.cipherKey = messageKeys.getCipherKey().getEncoded(); + key.macKey = messageKeys.getMacKey().getEncoded(); + key.index = messageKeys.getCounter(); + + chain.messageKeys.add(key); + } + + @Override + public void setReceiverChainKey(ECPublicKey senderEphemeral, ChainKey chainKey) { + InMemoryChain chain = receiverChains.get(senderEphemeral); + chain.chainKey = chainKey.getKey(); + chain.index = chainKey.getIndex(); + } + + @Override + public void setPendingKeyExchange(int sequence, ECKeyPair ourBaseKey, ECKeyPair ourEphemeralKey, IdentityKeyPair ourIdentityKey) { + throw new AssertionError(); + } + + @Override + public int getPendingKeyExchangeSequence() { + throw new AssertionError(); + } + + @Override + public ECKeyPair getPendingKeyExchangeBaseKey() throws InvalidKeyException { + throw new AssertionError(); + } + + @Override + public ECKeyPair getPendingKeyExchangeEphemeralKey() throws InvalidKeyException { + throw new AssertionError(); + } + + @Override + public IdentityKeyPair getPendingKeyExchangeIdentityKey() throws InvalidKeyException { + throw new AssertionError(); + } + + @Override + public boolean hasPendingKeyExchange() { + throw new AssertionError(); + } + + @Override + public void setPendingPreKey(int preKeyId, ECPublicKey baseKey) { + this.pendingPreKeyid = preKeyId; + this.pendingPreKey = baseKey; + } + + @Override + public boolean hasPendingPreKey() { + return this.pendingPreKey != null; + } + + @Override + public Pair getPendingPreKey() { + return new Pair<>(pendingPreKeyid, pendingPreKey); + } + + @Override + public void clearPendingPreKey() { + this.pendingPreKey = null; + this.pendingPreKeyid = -1; + } + + @Override + public void setRemoteRegistrationId(int registrationId) { + this.remoteRegistrationId = registrationId; + } + + @Override + public int getRemoteRegistrationId() { + return remoteRegistrationId; + } + + @Override + public void setLocalRegistrationId(int registrationId) { + this.localRegistrationId = registrationId; + } + + @Override + public int getLocalRegistrationId() { + return localRegistrationId; + } + + @Override + public byte[] serialize() { + throw new AssertionError(); + } + + private static class InMemoryChain { + byte[] chainKey; + int index; + List messageKeys = new LinkedList<>(); + + public static class InMemoryMessageKey { + public InMemoryMessageKey(){} + int index; + byte[] cipherKey; + byte[] macKey; + } + } +} diff --git a/libaxolotl/src/androidTest/java/org/whispersystems/test/InMemorySessionStore.java b/libaxolotl/src/androidTest/java/org/whispersystems/test/InMemorySessionStore.java new file mode 100644 index 000000000..08f7eb5de --- /dev/null +++ b/libaxolotl/src/androidTest/java/org/whispersystems/test/InMemorySessionStore.java @@ -0,0 +1,44 @@ +package org.whispersystems.test; + +import org.whispersystems.libaxolotl.SessionState; +import org.whispersystems.libaxolotl.SessionStore; + +import java.util.LinkedList; +import java.util.List; + +public class InMemorySessionStore implements SessionStore { + + private SessionState currentSessionState; + private List previousSessionStates; + + private SessionState checkedOutSessionState; + private List checkedOutPreviousSessionStates; + + public InMemorySessionStore(SessionState sessionState) { + this.currentSessionState = sessionState; + this.previousSessionStates = new LinkedList<>(); + this.checkedOutPreviousSessionStates = new LinkedList<>(); + } + + @Override + public SessionState getSessionState() { + checkedOutSessionState = new InMemorySessionState(currentSessionState); + return checkedOutSessionState; + } + + @Override + public List getPreviousSessionStates() { + checkedOutPreviousSessionStates = new LinkedList<>(); + for (SessionState state : previousSessionStates) { + checkedOutPreviousSessionStates.add(new InMemorySessionState(state)); + } + + return checkedOutPreviousSessionStates; + } + + @Override + public void save() { + this.currentSessionState = this.checkedOutSessionState; + this.previousSessionStates = this.checkedOutPreviousSessionStates; + } +} diff --git a/libaxolotl/src/androidTest/java/org/whispersystems/test/SessionCipherTest.java b/libaxolotl/src/androidTest/java/org/whispersystems/test/SessionCipherTest.java new file mode 100644 index 000000000..39345c16d --- /dev/null +++ b/libaxolotl/src/androidTest/java/org/whispersystems/test/SessionCipherTest.java @@ -0,0 +1,76 @@ +package org.whispersystems.test; + +import android.test.AndroidTestCase; + +import org.whispersystems.libaxolotl.DuplicateMessageException; +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.libaxolotl.IdentityKeyPair; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.InvalidMessageException; +import org.whispersystems.libaxolotl.LegacyMessageException; +import org.whispersystems.libaxolotl.SessionCipher; +import org.whispersystems.libaxolotl.SessionState; +import org.whispersystems.libaxolotl.SessionStore; +import org.whispersystems.libaxolotl.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECKeyPair; +import org.whispersystems.libaxolotl.protocol.CiphertextMessage; +import org.whispersystems.libaxolotl.ratchet.RatchetingSession; + +import java.util.Arrays; + +public class SessionCipherTest extends AndroidTestCase { + + public void testBasicSession() + throws InvalidKeyException, DuplicateMessageException, + LegacyMessageException, InvalidMessageException + { + SessionState aliceSessionState = new InMemorySessionState(); + SessionState bobSessionState = new InMemorySessionState(); + + initializeSessions(aliceSessionState, bobSessionState); + + SessionStore aliceSessionStore = new InMemorySessionStore(aliceSessionState); + SessionStore bobSessionStore = new InMemorySessionStore(bobSessionState); + + SessionCipher aliceCipher = new SessionCipher(aliceSessionStore); + SessionCipher bobCipher = new SessionCipher(bobSessionStore); + + byte[] alicePlaintext = "This is a plaintext message.".getBytes(); + CiphertextMessage message = aliceCipher.encrypt(alicePlaintext); + byte[] bobPlaintext = bobCipher.decrypt(message.serialize()); + + assertTrue(Arrays.equals(alicePlaintext, bobPlaintext)); + + byte[] bobReply = "This is a message from Bob.".getBytes(); + CiphertextMessage reply = bobCipher.encrypt(bobReply); + byte[] receivedReply = aliceCipher.decrypt(reply.serialize()); + + assertTrue(Arrays.equals(bobReply, receivedReply)); + } + + + private void initializeSessions(SessionState aliceSessionState, SessionState bobSessionState) + throws InvalidKeyException + { + ECKeyPair aliceIdentityKeyPair = Curve.generateKeyPair(false); + IdentityKeyPair aliceIdentityKey = new IdentityKeyPair(new IdentityKey(aliceIdentityKeyPair.getPublicKey()), + aliceIdentityKeyPair.getPrivateKey()); + ECKeyPair aliceBaseKey = Curve.generateKeyPair(true); + ECKeyPair aliceEphemeralKey = Curve.generateKeyPair(true); + + ECKeyPair bobIdentityKeyPair = Curve.generateKeyPair(false); + IdentityKeyPair bobIdentityKey = new IdentityKeyPair(new IdentityKey(bobIdentityKeyPair.getPublicKey()), + bobIdentityKeyPair.getPrivateKey()); + ECKeyPair bobBaseKey = Curve.generateKeyPair(true); + ECKeyPair bobEphemeralKey = bobBaseKey; + + + RatchetingSession.initializeSession(aliceSessionState, aliceBaseKey, bobBaseKey.getPublicKey(), + aliceEphemeralKey, bobEphemeralKey.getPublicKey(), + aliceIdentityKey, bobIdentityKey.getPublicKey()); + + RatchetingSession.initializeSession(bobSessionState, bobBaseKey, aliceBaseKey.getPublicKey(), + bobEphemeralKey, aliceEphemeralKey.getPublicKey(), + bobIdentityKey, aliceIdentityKey.getPublicKey()); + } +} diff --git a/libaxolotl/src/androidTest/java/org/whispersystems/test/ecc/Curve25519Test.java b/libaxolotl/src/androidTest/java/org/whispersystems/test/ecc/Curve25519Test.java new file mode 100644 index 000000000..5903353de --- /dev/null +++ b/libaxolotl/src/androidTest/java/org/whispersystems/test/ecc/Curve25519Test.java @@ -0,0 +1,82 @@ +package org.whispersystems.test.ecc; + +import android.test.AndroidTestCase; + +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 java.util.Arrays; + + +public class Curve25519Test extends AndroidTestCase { + + public void testAgreement() throws InvalidKeyException { + + byte[] alicePublic = {(byte) 0x05, (byte) 0x1b, (byte) 0xb7, (byte) 0x59, (byte) 0x66, + (byte) 0xf2, (byte) 0xe9, (byte) 0x3a, (byte) 0x36, (byte) 0x91, + (byte) 0xdf, (byte) 0xff, (byte) 0x94, (byte) 0x2b, (byte) 0xb2, + (byte) 0xa4, (byte) 0x66, (byte) 0xa1, (byte) 0xc0, (byte) 0x8b, + (byte) 0x8d, (byte) 0x78, (byte) 0xca, (byte) 0x3f, (byte) 0x4d, + (byte) 0x6d, (byte) 0xf8, (byte) 0xb8, (byte) 0xbf, (byte) 0xa2, + (byte) 0xe4, (byte) 0xee, (byte) 0x28}; + + byte[] alicePrivate = {(byte) 0xc8, (byte) 0x06, (byte) 0x43, (byte) 0x9d, (byte) 0xc9, + (byte) 0xd2, (byte) 0xc4, (byte) 0x76, (byte) 0xff, (byte) 0xed, + (byte) 0x8f, (byte) 0x25, (byte) 0x80, (byte) 0xc0, (byte) 0x88, + (byte) 0x8d, (byte) 0x58, (byte) 0xab, (byte) 0x40, (byte) 0x6b, + (byte) 0xf7, (byte) 0xae, (byte) 0x36, (byte) 0x98, (byte) 0x87, + (byte) 0x90, (byte) 0x21, (byte) 0xb9, (byte) 0x6b, (byte) 0xb4, + (byte) 0xbf, (byte) 0x59}; + + byte[] bobPublic = {(byte) 0x05, (byte) 0x65, (byte) 0x36, (byte) 0x14, (byte) 0x99, + (byte) 0x3d, (byte) 0x2b, (byte) 0x15, (byte) 0xee, (byte) 0x9e, + (byte) 0x5f, (byte) 0xd3, (byte) 0xd8, (byte) 0x6c, (byte) 0xe7, + (byte) 0x19, (byte) 0xef, (byte) 0x4e, (byte) 0xc1, (byte) 0xda, + (byte) 0xae, (byte) 0x18, (byte) 0x86, (byte) 0xa8, (byte) 0x7b, + (byte) 0x3f, (byte) 0x5f, (byte) 0xa9, (byte) 0x56, (byte) 0x5a, + (byte) 0x27, (byte) 0xa2, (byte) 0x2f}; + + byte[] bobPrivate = {(byte) 0xb0, (byte) 0x3b, (byte) 0x34, (byte) 0xc3, (byte) 0x3a, + (byte) 0x1c, (byte) 0x44, (byte) 0xf2, (byte) 0x25, (byte) 0xb6, + (byte) 0x62, (byte) 0xd2, (byte) 0xbf, (byte) 0x48, (byte) 0x59, + (byte) 0xb8, (byte) 0x13, (byte) 0x54, (byte) 0x11, (byte) 0xfa, + (byte) 0x7b, (byte) 0x03, (byte) 0x86, (byte) 0xd4, (byte) 0x5f, + (byte) 0xb7, (byte) 0x5d, (byte) 0xc5, (byte) 0xb9, (byte) 0x1b, + (byte) 0x44, (byte) 0x66}; + + byte[] shared = {(byte) 0x32, (byte) 0x5f, (byte) 0x23, (byte) 0x93, (byte) 0x28, + (byte) 0x94, (byte) 0x1c, (byte) 0xed, (byte) 0x6e, (byte) 0x67, + (byte) 0x3b, (byte) 0x86, (byte) 0xba, (byte) 0x41, (byte) 0x01, + (byte) 0x74, (byte) 0x48, (byte) 0xe9, (byte) 0x9b, (byte) 0x64, + (byte) 0x9a, (byte) 0x9c, (byte) 0x38, (byte) 0x06, (byte) 0xc1, + (byte) 0xdd, (byte) 0x7c, (byte) 0xa4, (byte) 0xc4, (byte) 0x77, + (byte) 0xe6, (byte) 0x29}; + + ECPublicKey alicePublicKey = Curve.decodePoint(alicePublic, 0); + ECPrivateKey alicePrivateKey = Curve.decodePrivatePoint(alicePrivate); + + ECPublicKey bobPublicKey = Curve.decodePoint(bobPublic, 0); + ECPrivateKey bobPrivateKey = Curve.decodePrivatePoint(bobPrivate); + + byte[] sharedOne = Curve.calculateAgreement(alicePublicKey, bobPrivateKey); + byte[] sharedTwo = Curve.calculateAgreement(bobPublicKey, alicePrivateKey); + + assertTrue(Arrays.equals(sharedOne, shared)); + assertTrue(Arrays.equals(sharedTwo, shared)); + } + + public void testRandomAgreements() throws InvalidKeyException { + for (int i=0;i<50;i++) { + ECKeyPair alice = Curve.generateKeyPair(false); + ECKeyPair bob = Curve.generateKeyPair(false); + + byte[] sharedAlice = Curve.calculateAgreement(bob.getPublicKey(), alice.getPrivateKey()); + byte[] sharedBob = Curve.calculateAgreement(alice.getPublicKey(), bob.getPrivateKey()); + + assertTrue(Arrays.equals(sharedAlice, sharedBob)); + } + } +} diff --git a/libaxolotl/src/androidTest/java/org/whispersystems/test/kdf/HKDFTest.java b/libaxolotl/src/androidTest/java/org/whispersystems/test/kdf/HKDFTest.java new file mode 100644 index 000000000..c26ffa1cb --- /dev/null +++ b/libaxolotl/src/androidTest/java/org/whispersystems/test/kdf/HKDFTest.java @@ -0,0 +1,44 @@ +package org.whispersystems.test.kdf; + +import android.test.AndroidTestCase; + +import org.whispersystems.libaxolotl.kdf.DerivedSecrets; +import org.whispersystems.libaxolotl.kdf.HKDF; + +import java.util.Arrays; + +public class HKDFTest extends AndroidTestCase { + + public void testVector() { + byte[] ikm = {0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b}; + + byte[] salt = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c}; + + byte[] info = {(byte)0xf0, (byte)0xf1, (byte)0xf2, (byte)0xf3, (byte)0xf4, + (byte)0xf5, (byte)0xf6, (byte)0xf7, (byte)0xf8, (byte)0xf9}; + + byte[] expectedOutputOne = {(byte)0x6e, (byte)0xc2, (byte)0x55, (byte)0x6d, (byte)0x5d, + (byte)0x7b, (byte)0x1d, (byte)0x81, (byte)0xde, (byte)0xe4, + (byte)0x22, (byte)0x2a, (byte)0xd7, (byte)0x48, (byte)0x36, + (byte)0x95, (byte)0xdd, (byte)0xc9, (byte)0x8f, (byte)0x4f, + (byte)0x5f, (byte)0xab, (byte)0xc0, (byte)0xe0, (byte)0x20, + (byte)0x5d, (byte)0xc2, (byte)0xef, (byte)0x87, (byte)0x52, + (byte)0xd4, (byte)0x1e}; + + byte[] expectedOutputTwo = {(byte)0x04, (byte)0xe2, (byte)0xe2, (byte)0x11, (byte)0x01, + (byte)0xc6, (byte)0x8f, (byte)0xf0, (byte)0x93, (byte)0x94, + (byte)0xb8, (byte)0xad, (byte)0x0b, (byte)0xdc, (byte)0xb9, + (byte)0x60, (byte)0x9c, (byte)0xd4, (byte)0xee, (byte)0x82, + (byte)0xac, (byte)0x13, (byte)0x19, (byte)0x9b, (byte)0x4a, + (byte)0xa9, (byte)0xfd, (byte)0xa8, (byte)0x99, (byte)0xda, + (byte)0xeb, (byte)0xec}; + + DerivedSecrets derivedSecrets = new HKDF().deriveSecrets(ikm, salt, info); + + assertTrue(Arrays.equals(derivedSecrets.getCipherKey().getEncoded(), expectedOutputOne)); + assertTrue(Arrays.equals(derivedSecrets.getMacKey().getEncoded(), expectedOutputTwo)); + } +} diff --git a/libaxolotl/src/androidTest/java/org/whispersystems/test/ratchet/ChainKeyTest.java b/libaxolotl/src/androidTest/java/org/whispersystems/test/ratchet/ChainKeyTest.java new file mode 100644 index 000000000..2cf5dcbd4 --- /dev/null +++ b/libaxolotl/src/androidTest/java/org/whispersystems/test/ratchet/ChainKeyTest.java @@ -0,0 +1,58 @@ +package org.whispersystems.test.ratchet; + +import android.test.AndroidTestCase; + +import org.whispersystems.libaxolotl.ratchet.ChainKey; + +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; + +public class ChainKeyTest extends AndroidTestCase { + + public void testChainKeyDerivation() throws NoSuchAlgorithmException { + + byte[] seed = {(byte) 0x8a, (byte) 0xb7, (byte) 0x2d, (byte) 0x6f, (byte) 0x4c, + (byte) 0xc5, (byte) 0xac, (byte) 0x0d, (byte) 0x38, (byte) 0x7e, + (byte) 0xaf, (byte) 0x46, (byte) 0x33, (byte) 0x78, (byte) 0xdd, + (byte) 0xb2, (byte) 0x8e, (byte) 0xdd, (byte) 0x07, (byte) 0x38, + (byte) 0x5b, (byte) 0x1c, (byte) 0xb0, (byte) 0x12, (byte) 0x50, + (byte) 0xc7, (byte) 0x15, (byte) 0x98, (byte) 0x2e, (byte) 0x7a, + (byte) 0xd4, (byte) 0x8f}; + + byte[] messageKey = {(byte) 0x02, (byte) 0xa9, (byte) 0xaa, (byte) 0x6c, (byte) 0x7d, + (byte) 0xbd, (byte) 0x64, (byte) 0xf9, (byte) 0xd3, (byte) 0xaa, + (byte) 0x92, (byte) 0xf9, (byte) 0x2a, (byte) 0x27, (byte) 0x7b, + (byte) 0xf5, (byte) 0x46, (byte) 0x09, (byte) 0xda, (byte) 0xdf, + (byte) 0x0b, (byte) 0x00, (byte) 0x82, (byte) 0x8a, (byte) 0xcf, + (byte) 0xc6, (byte) 0x1e, (byte) 0x3c, (byte) 0x72, (byte) 0x4b, + (byte) 0x84, (byte) 0xa7}; + + byte[] macKey = {(byte) 0xbf, (byte) 0xbe, (byte) 0x5e, (byte) 0xfb, (byte) 0x60, + (byte) 0x30, (byte) 0x30, (byte) 0x52, (byte) 0x67, (byte) 0x42, + (byte) 0xe3, (byte) 0xee, (byte) 0x89, (byte) 0xc7, (byte) 0x02, + (byte) 0x4e, (byte) 0x88, (byte) 0x4e, (byte) 0x44, (byte) 0x0f, + (byte) 0x1f, (byte) 0xf3, (byte) 0x76, (byte) 0xbb, (byte) 0x23, + (byte) 0x17, (byte) 0xb2, (byte) 0xd6, (byte) 0x4d, (byte) 0xeb, + (byte) 0x7c, (byte) 0x83}; + + byte[] nextChainKey = {(byte) 0x28, (byte) 0xe8, (byte) 0xf8, (byte) 0xfe, (byte) 0xe5, + (byte) 0x4b, (byte) 0x80, (byte) 0x1e, (byte) 0xef, (byte) 0x7c, + (byte) 0x5c, (byte) 0xfb, (byte) 0x2f, (byte) 0x17, (byte) 0xf3, + (byte) 0x2c, (byte) 0x7b, (byte) 0x33, (byte) 0x44, (byte) 0x85, + (byte) 0xbb, (byte) 0xb7, (byte) 0x0f, (byte) 0xac, (byte) 0x6e, + (byte) 0xc1, (byte) 0x03, (byte) 0x42, (byte) 0xa2, (byte) 0x46, + (byte) 0xd1, (byte) 0x5d}; + + ChainKey chainKey = new ChainKey(seed, 0); + + assertTrue(Arrays.equals(chainKey.getKey(), seed)); + assertTrue(Arrays.equals(chainKey.getMessageKeys().getCipherKey().getEncoded(), messageKey)); + assertTrue(Arrays.equals(chainKey.getMessageKeys().getMacKey().getEncoded(), macKey)); + assertTrue(Arrays.equals(chainKey.getNextChainKey().getKey(), nextChainKey)); + assertTrue(chainKey.getIndex() == 0); + assertTrue(chainKey.getMessageKeys().getCounter() == 0); + assertTrue(chainKey.getNextChainKey().getIndex() == 1); + assertTrue(chainKey.getNextChainKey().getMessageKeys().getCounter() == 1); + } + +} diff --git a/libaxolotl/src/androidTest/java/org/whispersystems/test/ratchet/RatchetingSessionTest.java b/libaxolotl/src/androidTest/java/org/whispersystems/test/ratchet/RatchetingSessionTest.java new file mode 100644 index 000000000..fa72ee192 --- /dev/null +++ b/libaxolotl/src/androidTest/java/org/whispersystems/test/ratchet/RatchetingSessionTest.java @@ -0,0 +1,218 @@ +package org.whispersystems.test.ratchet; + +import android.test.AndroidTestCase; + +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.libaxolotl.IdentityKeyPair; +import org.whispersystems.test.InMemorySessionState; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.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.RatchetingSession; + +import java.util.Arrays; + +public class RatchetingSessionTest extends AndroidTestCase { + + public void testRatchetingSessionAsBob() throws InvalidKeyException { + byte[] bobPublic = {(byte) 0x05, (byte) 0x2c, (byte) 0xb4, (byte) 0x97, + (byte) 0x76, (byte) 0xb8, (byte) 0x77, (byte) 0x02, + (byte) 0x05, (byte) 0x74, (byte) 0x5a, (byte) 0x3a, + (byte) 0x6e, (byte) 0x24, (byte) 0xf5, (byte) 0x79, + (byte) 0xcd, (byte) 0xb4, (byte) 0xba, (byte) 0x7a, + (byte) 0x89, (byte) 0x04, (byte) 0x10, (byte) 0x05, + (byte) 0x92, (byte) 0x8e, (byte) 0xbb, (byte) 0xad, + (byte) 0xc9, (byte) 0xc0, (byte) 0x5a, (byte) 0xd4, + (byte) 0x58}; + + byte[] bobPrivate = {(byte) 0xa1, (byte) 0xca, (byte) 0xb4, (byte) 0x8f, + (byte) 0x7c, (byte) 0x89, (byte) 0x3f, (byte) 0xaf, + (byte) 0xa9, (byte) 0x88, (byte) 0x0a, (byte) 0x28, + (byte) 0xc3, (byte) 0xb4, (byte) 0x99, (byte) 0x9d, + (byte) 0x28, (byte) 0xd6, (byte) 0x32, (byte) 0x95, + (byte) 0x62, (byte) 0xd2, (byte) 0x7a, (byte) 0x4e, + (byte) 0xa4, (byte) 0xe2, (byte) 0x2e, (byte) 0x9f, + (byte) 0xf1, (byte) 0xbd, (byte) 0xd6, (byte) 0x5a}; + + byte[] bobIdentityPublic = {(byte) 0x05, (byte) 0xf1, (byte) 0xf4, (byte) 0x38, + (byte) 0x74, (byte) 0xf6, (byte) 0x96, (byte) 0x69, + (byte) 0x56, (byte) 0xc2, (byte) 0xdd, (byte) 0x47, + (byte) 0x3f, (byte) 0x8f, (byte) 0xa1, (byte) 0x5a, + (byte) 0xde, (byte) 0xb7, (byte) 0x1d, (byte) 0x1c, + (byte) 0xb9, (byte) 0x91, (byte) 0xb2, (byte) 0x34, + (byte) 0x16, (byte) 0x92, (byte) 0x32, (byte) 0x4c, + (byte) 0xef, (byte) 0xb1, (byte) 0xc5, (byte) 0xe6, + (byte) 0x26}; + + byte[] bobIdentityPrivate = {(byte) 0x48, (byte) 0x75, (byte) 0xcc, (byte) 0x69, + (byte) 0xdd, (byte) 0xf8, (byte) 0xea, (byte) 0x07, + (byte) 0x19, (byte) 0xec, (byte) 0x94, (byte) 0x7d, + (byte) 0x61, (byte) 0x08, (byte) 0x11, (byte) 0x35, + (byte) 0x86, (byte) 0x8d, (byte) 0x5f, (byte) 0xd8, + (byte) 0x01, (byte) 0xf0, (byte) 0x2c, (byte) 0x02, + (byte) 0x25, (byte) 0xe5, (byte) 0x16, (byte) 0xdf, + (byte) 0x21, (byte) 0x56, (byte) 0x60, (byte) 0x5e}; + + byte[] aliceBasePublic = {(byte) 0x05, (byte) 0x47, (byte) 0x2d, (byte) 0x1f, + (byte) 0xb1, (byte) 0xa9, (byte) 0x86, (byte) 0x2c, + (byte) 0x3a, (byte) 0xf6, (byte) 0xbe, (byte) 0xac, + (byte) 0xa8, (byte) 0x92, (byte) 0x02, (byte) 0x77, + (byte) 0xe2, (byte) 0xb2, (byte) 0x6f, (byte) 0x4a, + (byte) 0x79, (byte) 0x21, (byte) 0x3e, (byte) 0xc7, + (byte) 0xc9, (byte) 0x06, (byte) 0xae, (byte) 0xb3, + (byte) 0x5e, (byte) 0x03, (byte) 0xcf, (byte) 0x89, + (byte) 0x50}; + + byte[] aliceEphemeralPublic = {(byte) 0x05, (byte) 0x6c, (byte) 0x3e, (byte) 0x0d, + (byte) 0x1f, (byte) 0x52, (byte) 0x02, (byte) 0x83, + (byte) 0xef, (byte) 0xcc, (byte) 0x55, (byte) 0xfc, + (byte) 0xa5, (byte) 0xe6, (byte) 0x70, (byte) 0x75, + (byte) 0xb9, (byte) 0x04, (byte) 0x00, (byte) 0x7f, + (byte) 0x18, (byte) 0x81, (byte) 0xd1, (byte) 0x51, + (byte) 0xaf, (byte) 0x76, (byte) 0xdf, (byte) 0x18, + (byte) 0xc5, (byte) 0x1d, (byte) 0x29, (byte) 0xd3, + (byte) 0x4b}; + + byte[] aliceIdentityPublic = {(byte) 0x05, (byte) 0xb4, (byte) 0xa8, (byte) 0x45, + (byte) 0x56, (byte) 0x60, (byte) 0xad, (byte) 0xa6, + (byte) 0x5b, (byte) 0x40, (byte) 0x10, (byte) 0x07, + (byte) 0xf6, (byte) 0x15, (byte) 0xe6, (byte) 0x54, + (byte) 0x04, (byte) 0x17, (byte) 0x46, (byte) 0x43, + (byte) 0x2e, (byte) 0x33, (byte) 0x39, (byte) 0xc6, + (byte) 0x87, (byte) 0x51, (byte) 0x49, (byte) 0xbc, + (byte) 0xee, (byte) 0xfc, (byte) 0xb4, (byte) 0x2b, + (byte) 0x4a}; + + byte[] senderChain = {(byte)0xd2, (byte)0x2f, (byte)0xd5, (byte)0x6d, (byte)0x3f, + (byte)0xec, (byte)0x81, (byte)0x9c, (byte)0xf4, (byte)0xc3, + (byte)0xd5, (byte)0x0c, (byte)0x56, (byte)0xed, (byte)0xfb, + (byte)0x1c, (byte)0x28, (byte)0x0a, (byte)0x1b, (byte)0x31, + (byte)0x96, (byte)0x45, (byte)0x37, (byte)0xf1, (byte)0xd1, + (byte)0x61, (byte)0xe1, (byte)0xc9, (byte)0x31, (byte)0x48, + (byte)0xe3, (byte)0x6b}; + + IdentityKey bobIdentityKeyPublic = new IdentityKey(bobIdentityPublic, 0); + ECPrivateKey bobIdentityKeyPrivate = Curve.decodePrivatePoint(bobIdentityPrivate); + IdentityKeyPair bobIdentityKey = new IdentityKeyPair(bobIdentityKeyPublic, bobIdentityKeyPrivate); + ECPublicKey bobEphemeralPublicKey = Curve.decodePoint(bobPublic, 0); + ECPrivateKey bobEphemeralPrivateKey = Curve.decodePrivatePoint(bobPrivate); + ECKeyPair bobEphemeralKey = new ECKeyPair(bobEphemeralPublicKey, bobEphemeralPrivateKey); + ECKeyPair bobBaseKey = bobEphemeralKey; + + ECPublicKey aliceBasePublicKey = Curve.decodePoint(aliceBasePublic, 0); + ECPublicKey aliceEphemeralPublicKey = Curve.decodePoint(aliceEphemeralPublic, 0); + IdentityKey aliceIdentityPublicKey = new IdentityKey(aliceIdentityPublic, 0); + + SessionState session = new InMemorySessionState(); + + RatchetingSession.initializeSession(session, bobBaseKey, aliceBasePublicKey, + bobEphemeralKey, aliceEphemeralPublicKey, + bobIdentityKey, aliceIdentityPublicKey); + + assertTrue(session.getLocalIdentityKey().equals(bobIdentityKey.getPublicKey())); + assertTrue(session.getRemoteIdentityKey().equals(aliceIdentityPublicKey)); + assertTrue(Arrays.equals(session.getSenderChainKey().getKey(), senderChain)); + } + + public void testRatchetingSessionAsAlice() throws InvalidKeyException { + byte[] bobPublic = {(byte) 0x05, (byte) 0x2c, (byte) 0xb4, (byte) 0x97, (byte) 0x76, + (byte) 0xb8, (byte) 0x77, (byte) 0x02, (byte) 0x05, (byte) 0x74, + (byte) 0x5a, (byte) 0x3a, (byte) 0x6e, (byte) 0x24, (byte) 0xf5, + (byte) 0x79, (byte) 0xcd, (byte) 0xb4, (byte) 0xba, (byte) 0x7a, + (byte) 0x89, (byte) 0x04, (byte) 0x10, (byte) 0x05, (byte) 0x92, + (byte) 0x8e, (byte) 0xbb, (byte) 0xad, (byte) 0xc9, (byte) 0xc0, + (byte) 0x5a, (byte) 0xd4, (byte) 0x58}; + + byte[] bobIdentityPublic = {(byte) 0x05, (byte) 0xf1, (byte) 0xf4, (byte) 0x38, (byte) 0x74, + (byte) 0xf6, (byte) 0x96, (byte) 0x69, (byte) 0x56, (byte) 0xc2, + (byte) 0xdd, (byte) 0x47, (byte) 0x3f, (byte) 0x8f, (byte) 0xa1, + (byte) 0x5a, (byte) 0xde, (byte) 0xb7, (byte) 0x1d, (byte) 0x1c, + (byte) 0xb9, (byte) 0x91, (byte) 0xb2, (byte) 0x34, (byte) 0x16, + (byte) 0x92, (byte) 0x32, (byte) 0x4c, (byte) 0xef, (byte) 0xb1, + (byte) 0xc5, (byte) 0xe6, (byte) 0x26}; + + byte[] aliceBasePublic = {(byte) 0x05, (byte) 0x47, (byte) 0x2d, (byte) 0x1f, (byte) 0xb1, + (byte) 0xa9, (byte) 0x86, (byte) 0x2c, (byte) 0x3a, (byte) 0xf6, + (byte) 0xbe, (byte) 0xac, (byte) 0xa8, (byte) 0x92, (byte) 0x02, + (byte) 0x77, (byte) 0xe2, (byte) 0xb2, (byte) 0x6f, (byte) 0x4a, + (byte) 0x79, (byte) 0x21, (byte) 0x3e, (byte) 0xc7, (byte) 0xc9, + (byte) 0x06, (byte) 0xae, (byte) 0xb3, (byte) 0x5e, (byte) 0x03, + (byte) 0xcf, (byte) 0x89, (byte) 0x50}; + + byte[] aliceBasePrivate = {(byte) 0x11, (byte) 0xae, (byte) 0x7c, (byte) 0x64, (byte) 0xd1, + (byte) 0xe6, (byte) 0x1c, (byte) 0xd5, (byte) 0x96, (byte) 0xb7, + (byte) 0x6a, (byte) 0x0d, (byte) 0xb5, (byte) 0x01, (byte) 0x26, + (byte) 0x73, (byte) 0x39, (byte) 0x1c, (byte) 0xae, (byte) 0x66, + (byte) 0xed, (byte) 0xbf, (byte) 0xcf, (byte) 0x07, (byte) 0x3b, + (byte) 0x4d, (byte) 0xa8, (byte) 0x05, (byte) 0x16, (byte) 0xa4, + (byte) 0x74, (byte) 0x49}; + + byte[] aliceEphemeralPublic = {(byte) 0x05, (byte) 0x6c, (byte) 0x3e, (byte) 0x0d, (byte) 0x1f, + (byte) 0x52, (byte) 0x02, (byte) 0x83, (byte) 0xef, (byte) 0xcc, + (byte) 0x55, (byte) 0xfc, (byte) 0xa5, (byte) 0xe6, (byte) 0x70, + (byte) 0x75, (byte) 0xb9, (byte) 0x04, (byte) 0x00, (byte) 0x7f, + (byte) 0x18, (byte) 0x81, (byte) 0xd1, (byte) 0x51, (byte) 0xaf, + (byte) 0x76, (byte) 0xdf, (byte) 0x18, (byte) 0xc5, (byte) 0x1d, + (byte) 0x29, (byte) 0xd3, (byte) 0x4b}; + + byte[] aliceEphemeralPrivate = {(byte) 0xd1, (byte) 0xba, (byte) 0x38, (byte) 0xce, (byte) 0xa9, + (byte) 0x17, (byte) 0x43, (byte) 0xd3, (byte) 0x39, (byte) 0x39, + (byte) 0xc3, (byte) 0x3c, (byte) 0x84, (byte) 0x98, (byte) 0x65, + (byte) 0x09, (byte) 0x28, (byte) 0x01, (byte) 0x61, (byte) 0xb8, + (byte) 0xb6, (byte) 0x0f, (byte) 0xc7, (byte) 0x87, (byte) 0x0c, + (byte) 0x59, (byte) 0x9c, (byte) 0x1d, (byte) 0x46, (byte) 0x20, + (byte) 0x12, (byte) 0x48}; + + byte[] aliceIdentityPublic = {(byte) 0x05, (byte) 0xb4, (byte) 0xa8, (byte) 0x45, (byte) 0x56, + (byte) 0x60, (byte) 0xad, (byte) 0xa6, (byte) 0x5b, (byte) 0x40, + (byte) 0x10, (byte) 0x07, (byte) 0xf6, (byte) 0x15, (byte) 0xe6, + (byte) 0x54, (byte) 0x04, (byte) 0x17, (byte) 0x46, (byte) 0x43, + (byte) 0x2e, (byte) 0x33, (byte) 0x39, (byte) 0xc6, (byte) 0x87, + (byte) 0x51, (byte) 0x49, (byte) 0xbc, (byte) 0xee, (byte) 0xfc, + (byte) 0xb4, (byte) 0x2b, (byte) 0x4a}; + + byte[] aliceIdentityPrivate = {(byte) 0x90, (byte) 0x40, (byte) 0xf0, (byte) 0xd4, (byte) 0xe0, + (byte) 0x9c, (byte) 0xf3, (byte) 0x8f, (byte) 0x6d, (byte) 0xc7, + (byte) 0xc1, (byte) 0x37, (byte) 0x79, (byte) 0xc9, (byte) 0x08, + (byte) 0xc0, (byte) 0x15, (byte) 0xa1, (byte) 0xda, (byte) 0x4f, + (byte) 0xa7, (byte) 0x87, (byte) 0x37, (byte) 0xa0, (byte) 0x80, + (byte) 0xeb, (byte) 0x0a, (byte) 0x6f, (byte) 0x4f, (byte) 0x5f, + (byte) 0x8f, (byte) 0x58}; + + byte[] receiverChain = {(byte) 0xd2, (byte) 0x2f, (byte) 0xd5, (byte) 0x6d, (byte) 0x3f, + (byte) 0xec, (byte) 0x81, (byte) 0x9c, (byte) 0xf4, (byte) 0xc3, + (byte) 0xd5, (byte) 0x0c, (byte) 0x56, (byte) 0xed, (byte) 0xfb, + (byte) 0x1c, (byte) 0x28, (byte) 0x0a, (byte) 0x1b, (byte) 0x31, + (byte) 0x96, (byte) 0x45, (byte) 0x37, (byte) 0xf1, (byte) 0xd1, + (byte) 0x61, (byte) 0xe1, (byte) 0xc9, (byte) 0x31, (byte) 0x48, + (byte) 0xe3, (byte) 0x6b}; + + IdentityKey bobIdentityKey = new IdentityKey(bobIdentityPublic, 0); + ECPublicKey bobEphemeralPublicKey = Curve.decodePoint(bobPublic, 0); + ECPublicKey bobBasePublicKey = bobEphemeralPublicKey; + ECPublicKey aliceBasePublicKey = Curve.decodePoint(aliceBasePublic, 0); + ECPrivateKey aliceBasePrivateKey = Curve.decodePrivatePoint(aliceBasePrivate); + ECKeyPair aliceBaseKey = new ECKeyPair(aliceBasePublicKey, aliceBasePrivateKey); + ECPublicKey aliceEphemeralPublicKey = Curve.decodePoint(aliceEphemeralPublic, 0); + ECPrivateKey aliceEphemeralPrivateKey = Curve.decodePrivatePoint(aliceEphemeralPrivate); + ECKeyPair aliceEphemeralKey = new ECKeyPair(aliceEphemeralPublicKey, aliceEphemeralPrivateKey); + IdentityKey aliceIdentityPublicKey = new IdentityKey(aliceIdentityPublic, 0); + ECPrivateKey aliceIdentityPrivateKey = Curve.decodePrivatePoint(aliceIdentityPrivate); + IdentityKeyPair aliceIdentityKey = new IdentityKeyPair(aliceIdentityPublicKey, aliceIdentityPrivateKey); + + SessionState session = new InMemorySessionState(); + + RatchetingSession.initializeSession(session, aliceBaseKey, bobBasePublicKey, + aliceEphemeralKey, bobEphemeralPublicKey, + aliceIdentityKey, bobIdentityKey); + + assertTrue(session.getLocalIdentityKey().equals(aliceIdentityKey.getPublicKey())); + assertTrue(session.getRemoteIdentityKey().equals(bobIdentityKey)); + assertTrue(Arrays.equals(session.getReceiverChainKey(bobEphemeralPublicKey).getKey(), + receiverChain)); + + } +} diff --git a/libaxolotl/src/androidTest/java/org/whispersystems/test/ratchet/RootKeyTest.java b/libaxolotl/src/androidTest/java/org/whispersystems/test/ratchet/RootKeyTest.java new file mode 100644 index 000000000..313cd6b36 --- /dev/null +++ b/libaxolotl/src/androidTest/java/org/whispersystems/test/ratchet/RootKeyTest.java @@ -0,0 +1,83 @@ +package org.whispersystems.test.ratchet; + +import android.test.AndroidTestCase; + +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.ratchet.ChainKey; +import org.whispersystems.libaxolotl.ratchet.RootKey; +import org.whispersystems.libaxolotl.util.Pair; + +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; + +public class RootKeyTest extends AndroidTestCase { + + public void testRootKeyDerivation() throws NoSuchAlgorithmException, InvalidKeyException { + byte[] rootKeySeed = {(byte) 0x7b, (byte) 0xa6, (byte) 0xde, (byte) 0xbc, (byte) 0x2b, + (byte) 0xc1, (byte) 0xbb, (byte) 0xf9, (byte) 0x1a, (byte) 0xbb, + (byte) 0xc1, (byte) 0x36, (byte) 0x74, (byte) 0x04, (byte) 0x17, + (byte) 0x6c, (byte) 0xa6, (byte) 0x23, (byte) 0x09, (byte) 0x5b, + (byte) 0x7e, (byte) 0xc6, (byte) 0x6b, (byte) 0x45, (byte) 0xf6, + (byte) 0x02, (byte) 0xd9, (byte) 0x35, (byte) 0x38, (byte) 0x94, + (byte) 0x2d, (byte) 0xcc}; + + byte[] alicePublic = {(byte) 0x05, (byte) 0xee, (byte) 0x4f, (byte) 0xa6, (byte) 0xcd, + (byte) 0xc0, (byte) 0x30, (byte) 0xdf, (byte) 0x49, (byte) 0xec, + (byte) 0xd0, (byte) 0xba, (byte) 0x6c, (byte) 0xfc, (byte) 0xff, + (byte) 0xb2, (byte) 0x33, (byte) 0xd3, (byte) 0x65, (byte) 0xa2, + (byte) 0x7f, (byte) 0xad, (byte) 0xbe, (byte) 0xff, (byte) 0x77, + (byte) 0xe9, (byte) 0x63, (byte) 0xfc, (byte) 0xb1, (byte) 0x62, + (byte) 0x22, (byte) 0xe1, (byte) 0x3a}; + + byte[] alicePrivate = {(byte) 0x21, (byte) 0x68, (byte) 0x22, (byte) 0xec, (byte) 0x67, + (byte) 0xeb, (byte) 0x38, (byte) 0x04, (byte) 0x9e, (byte) 0xba, + (byte) 0xe7, (byte) 0xb9, (byte) 0x39, (byte) 0xba, (byte) 0xea, + (byte) 0xeb, (byte) 0xb1, (byte) 0x51, (byte) 0xbb, (byte) 0xb3, + (byte) 0x2d, (byte) 0xb8, (byte) 0x0f, (byte) 0xd3, (byte) 0x89, + (byte) 0x24, (byte) 0x5a, (byte) 0xc3, (byte) 0x7a, (byte) 0x94, + (byte) 0x8e, (byte) 0x50}; + + byte[] bobPublic = {(byte) 0x05, (byte) 0xab, (byte) 0xb8, (byte) 0xeb, (byte) 0x29, + (byte) 0xcc, (byte) 0x80, (byte) 0xb4, (byte) 0x71, (byte) 0x09, + (byte) 0xa2, (byte) 0x26, (byte) 0x5a, (byte) 0xbe, (byte) 0x97, + (byte) 0x98, (byte) 0x48, (byte) 0x54, (byte) 0x06, (byte) 0xe3, + (byte) 0x2d, (byte) 0xa2, (byte) 0x68, (byte) 0x93, (byte) 0x4a, + (byte) 0x95, (byte) 0x55, (byte) 0xe8, (byte) 0x47, (byte) 0x57, + (byte) 0x70, (byte) 0x8a, (byte) 0x30}; + + byte[] nextRoot = {(byte) 0xb1, (byte) 0x14, (byte) 0xf5, (byte) 0xde, (byte) 0x28, + (byte) 0x01, (byte) 0x19, (byte) 0x85, (byte) 0xe6, (byte) 0xeb, + (byte) 0xa2, (byte) 0x5d, (byte) 0x50, (byte) 0xe7, (byte) 0xec, + (byte) 0x41, (byte) 0xa9, (byte) 0xb0, (byte) 0x2f, (byte) 0x56, + (byte) 0x93, (byte) 0xc5, (byte) 0xc7, (byte) 0x88, (byte) 0xa6, + (byte) 0x3a, (byte) 0x06, (byte) 0xd2, (byte) 0x12, (byte) 0xa2, + (byte) 0xf7, (byte) 0x31}; + + byte[] nextChain = {(byte) 0x9d, (byte) 0x7d, (byte) 0x24, (byte) 0x69, (byte) 0xbc, + (byte) 0x9a, (byte) 0xe5, (byte) 0x3e, (byte) 0xe9, (byte) 0x80, + (byte) 0x5a, (byte) 0xa3, (byte) 0x26, (byte) 0x4d, (byte) 0x24, + (byte) 0x99, (byte) 0xa3, (byte) 0xac, (byte) 0xe8, (byte) 0x0f, + (byte) 0x4c, (byte) 0xca, (byte) 0xe2, (byte) 0xda, (byte) 0x13, + (byte) 0x43, (byte) 0x0c, (byte) 0x5c, (byte) 0x55, (byte) 0xb5, + (byte) 0xca, (byte) 0x5f}; + + ECPublicKey alicePublicKey = Curve.decodePoint(alicePublic, 0); + ECPrivateKey alicePrivateKey = Curve.decodePrivatePoint(alicePrivate); + ECKeyPair aliceKeyPair = new ECKeyPair(alicePublicKey, alicePrivateKey); + + ECPublicKey bobPublicKey = Curve.decodePoint(bobPublic, 0); + RootKey rootKey = new RootKey(rootKeySeed); + + Pair rootKeyChainKeyPair = rootKey.createChain(bobPublicKey, aliceKeyPair); + RootKey nextRootKey = rootKeyChainKeyPair.first(); + ChainKey nextChainKey = rootKeyChainKeyPair.second(); + + assertTrue(Arrays.equals(rootKey.getKeyBytes(), rootKeySeed)); + assertTrue(Arrays.equals(nextRootKey.getKeyBytes(), nextRoot)); + assertTrue(Arrays.equals(nextChainKey.getKey(), nextChain)); + } +} diff --git a/libaxolotl/src/main/AndroidManifest.xml b/libaxolotl/src/main/AndroidManifest.xml new file mode 100644 index 000000000..28d281688 --- /dev/null +++ b/libaxolotl/src/main/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/library/src/org/whispersystems/textsecure/crypto/DuplicateMessageException.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/DuplicateMessageException.java similarity index 73% rename from library/src/org/whispersystems/textsecure/crypto/DuplicateMessageException.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/DuplicateMessageException.java index 0d795f3fc..913c01212 100644 --- a/library/src/org/whispersystems/textsecure/crypto/DuplicateMessageException.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/DuplicateMessageException.java @@ -1,4 +1,4 @@ -package org.whispersystems.textsecure.crypto; +package org.whispersystems.libaxolotl; public class DuplicateMessageException extends Exception { public DuplicateMessageException(String s) { diff --git a/libaxolotl/src/main/java/org/whispersystems/libaxolotl/IdentityKey.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/IdentityKey.java new file mode 100644 index 000000000..35af3394a --- /dev/null +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/IdentityKey.java @@ -0,0 +1,66 @@ +/** + * 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; + + +import org.whispersystems.libaxolotl.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; +import org.whispersystems.libaxolotl.util.Hex; + +/** + * A class for representing an identity key. + * + * @author Moxie Marlinspike + */ + +public class IdentityKey { + + private final ECPublicKey publicKey; + + public IdentityKey(ECPublicKey publicKey) { + this.publicKey = publicKey; + } + + public IdentityKey(byte[] bytes, int offset) throws InvalidKeyException { + this.publicKey = Curve.decodePoint(bytes, offset); + } + + public ECPublicKey getPublicKey() { + return publicKey; + } + + public byte[] serialize() { + return publicKey.serialize(); + } + + public String getFingerprint() { + return Hex.toString(publicKey.serialize()); + } + + @Override + public boolean equals(Object other) { + if (other == null) return false; + if (!(other instanceof IdentityKey)) return false; + + return publicKey.equals(((IdentityKey) other).getPublicKey()); + } + + @Override + public int hashCode() { + return publicKey.hashCode(); + } +} diff --git a/library/src/org/whispersystems/textsecure/crypto/IdentityKeyPair.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/IdentityKeyPair.java similarity index 91% rename from library/src/org/whispersystems/textsecure/crypto/IdentityKeyPair.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/IdentityKeyPair.java index 390fbe208..220be57a6 100644 --- a/library/src/org/whispersystems/textsecure/crypto/IdentityKeyPair.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/IdentityKeyPair.java @@ -14,9 +14,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package org.whispersystems.textsecure.crypto; +package org.whispersystems.libaxolotl; -import org.whispersystems.textsecure.crypto.ecc.ECPrivateKey; +import org.whispersystems.libaxolotl.ecc.ECPrivateKey; /** * Holder for public and private identity key pair. diff --git a/library/src/org/whispersystems/textsecure/crypto/InvalidKeyException.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/InvalidKeyException.java similarity index 76% rename from library/src/org/whispersystems/textsecure/crypto/InvalidKeyException.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/InvalidKeyException.java index 144021dc1..bb70df168 100644 --- a/library/src/org/whispersystems/textsecure/crypto/InvalidKeyException.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/InvalidKeyException.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2011 Whisper Systems + * 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 @@ -14,27 +14,21 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package org.whispersystems.textsecure.crypto; +package org.whispersystems.libaxolotl; public class InvalidKeyException extends Exception { - public InvalidKeyException() { - // TODO Auto-generated constructor stub - } + public InvalidKeyException() {} public InvalidKeyException(String detailMessage) { super(detailMessage); - // TODO Auto-generated constructor stub } public InvalidKeyException(Throwable throwable) { super(throwable); - // TODO Auto-generated constructor stub } public InvalidKeyException(String detailMessage, Throwable throwable) { super(detailMessage, throwable); - // TODO Auto-generated constructor stub } - } diff --git a/library/src/org/whispersystems/textsecure/crypto/InvalidMacException.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/InvalidMacException.java similarity index 67% rename from library/src/org/whispersystems/textsecure/crypto/InvalidMacException.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/InvalidMacException.java index f886ddaa9..0afc6996e 100644 --- a/library/src/org/whispersystems/textsecure/crypto/InvalidMacException.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/InvalidMacException.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2011 Whisper Systems + * 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 @@ -14,27 +14,15 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package org.whispersystems.textsecure.crypto; +package org.whispersystems.libaxolotl; public class InvalidMacException extends Exception { - public InvalidMacException() { - // TODO Auto-generated constructor stub - } - public InvalidMacException(String detailMessage) { super(detailMessage); - // TODO Auto-generated constructor stub } public InvalidMacException(Throwable throwable) { super(throwable); - // TODO Auto-generated constructor stub } - - public InvalidMacException(String detailMessage, Throwable throwable) { - super(detailMessage, throwable); - // TODO Auto-generated constructor stub - } - } diff --git a/library/src/org/whispersystems/textsecure/crypto/InvalidMessageException.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/InvalidMessageException.java similarity index 77% rename from library/src/org/whispersystems/textsecure/crypto/InvalidMessageException.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/InvalidMessageException.java index a978d6020..063eb594a 100644 --- a/library/src/org/whispersystems/textsecure/crypto/InvalidMessageException.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/InvalidMessageException.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2011 Whisper Systems + * 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 @@ -14,27 +14,27 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package org.whispersystems.textsecure.crypto; +package org.whispersystems.libaxolotl; + +import java.util.List; public class InvalidMessageException extends Exception { - public InvalidMessageException() { - // TODO Auto-generated constructor stub - } + public InvalidMessageException() {} public InvalidMessageException(String detailMessage) { super(detailMessage); - // TODO Auto-generated constructor stub } public InvalidMessageException(Throwable throwable) { super(throwable); - // TODO Auto-generated constructor stub } public InvalidMessageException(String detailMessage, Throwable throwable) { super(detailMessage, throwable); - // TODO Auto-generated constructor stub } + public InvalidMessageException(String detailMessage, List exceptions) { + super(detailMessage, exceptions.get(0)); + } } diff --git a/library/src/org/whispersystems/textsecure/crypto/SerializableKey.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/InvalidVersionException.java similarity index 73% rename from library/src/org/whispersystems/textsecure/crypto/SerializableKey.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/InvalidVersionException.java index 4799be688..a13244436 100644 --- a/library/src/org/whispersystems/textsecure/crypto/SerializableKey.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/InvalidVersionException.java @@ -1,6 +1,6 @@ -/** - * Copyright (C) 2011 Whisper Systems - * +/** + * 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 @@ -10,12 +10,14 @@ * 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.textsecure.crypto; +package org.whispersystems.libaxolotl; -public interface SerializableKey { - public byte[] serialize(); +public class InvalidVersionException extends Exception { + public InvalidVersionException(String detailMessage) { + super(detailMessage); + } } diff --git a/library/src/org/whispersystems/textsecure/crypto/LegacyMessageException.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/LegacyMessageException.java similarity index 72% rename from library/src/org/whispersystems/textsecure/crypto/LegacyMessageException.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/LegacyMessageException.java index c396e04d1..dadde7540 100644 --- a/library/src/org/whispersystems/textsecure/crypto/LegacyMessageException.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/LegacyMessageException.java @@ -1,4 +1,4 @@ -package org.whispersystems.textsecure.crypto; +package org.whispersystems.libaxolotl; public class LegacyMessageException extends Exception { public LegacyMessageException(String s) { diff --git a/library/src/org/whispersystems/textsecure/crypto/SessionCipher.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/SessionCipher.java similarity index 69% rename from library/src/org/whispersystems/textsecure/crypto/SessionCipher.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/SessionCipher.java index bf861339a..7b8907a53 100644 --- a/library/src/org/whispersystems/textsecure/crypto/SessionCipher.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/SessionCipher.java @@ -14,29 +14,23 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package org.whispersystems.textsecure.crypto; +package org.whispersystems.libaxolotl; - -import android.content.Context; -import android.util.Log; -import android.util.Pair; - -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECKeyPair; -import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; -import org.whispersystems.textsecure.crypto.protocol.CiphertextMessage; -import org.whispersystems.textsecure.crypto.protocol.PreKeyWhisperMessage; -import org.whispersystems.textsecure.crypto.protocol.WhisperMessage; -import org.whispersystems.textsecure.crypto.ratchet.ChainKey; -import org.whispersystems.textsecure.crypto.ratchet.MessageKeys; -import org.whispersystems.textsecure.crypto.ratchet.RootKey; -import org.whispersystems.textsecure.storage.RecipientDevice; -import org.whispersystems.textsecure.storage.SessionRecordV2; -import org.whispersystems.textsecure.storage.SessionState; -import org.whispersystems.textsecure.util.Conversions; +import org.whispersystems.libaxolotl.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECKeyPair; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; +import org.whispersystems.libaxolotl.protocol.CiphertextMessage; +import org.whispersystems.libaxolotl.protocol.PreKeyWhisperMessage; +import org.whispersystems.libaxolotl.protocol.WhisperMessage; +import org.whispersystems.libaxolotl.ratchet.ChainKey; +import org.whispersystems.libaxolotl.ratchet.MessageKeys; +import org.whispersystems.libaxolotl.ratchet.RootKey; +import org.whispersystems.libaxolotl.util.ByteUtil; +import org.whispersystems.libaxolotl.util.Pair; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; +import java.util.LinkedList; import java.util.List; import javax.crypto.BadPaddingException; @@ -50,36 +44,19 @@ public class SessionCipher { private static final Object SESSION_LOCK = new Object(); - private final Context context; - private final MasterSecret masterSecret; - private final RecipientDevice recipient; + private final SessionStore sessionStore; - public static SessionCipher createFor(Context context, - MasterSecret masterSecret, - RecipientDevice recipient) - { - if (SessionRecordV2.hasSession(context, masterSecret, recipient)) { - return new SessionCipher(context, masterSecret, recipient); - } else { - throw new AssertionError("Attempt to initialize cipher for non-existing session."); - } - } - - - private SessionCipher(Context context, MasterSecret masterSecret, RecipientDevice recipient) { - this.recipient = recipient; - this.masterSecret = masterSecret; - this.context = context; + public SessionCipher(SessionStore sessionStore) { + this.sessionStore = sessionStore; } public CiphertextMessage encrypt(byte[] paddedMessage) { synchronized (SESSION_LOCK) { - SessionRecordV2 sessionRecord = getSessionRecord(); - SessionState sessionState = sessionRecord.getSessionState(); - ChainKey chainKey = sessionState.getSenderChainKey(); - MessageKeys messageKeys = chainKey.getMessageKeys(); - ECPublicKey senderEphemeral = sessionState.getSenderEphemeral(); - int previousCounter = sessionState.getPreviousCounter(); + SessionState sessionState = sessionStore.getSessionState(); + ChainKey chainKey = sessionState.getSenderChainKey(); + MessageKeys messageKeys = chainKey.getMessageKeys(); + ECPublicKey senderEphemeral = sessionState.getSenderEphemeral(); + int previousCounter = sessionState.getPreviousCounter(); byte[] ciphertextBody = getCiphertext(messageKeys, paddedMessage); CiphertextMessage ciphertextMessage = new WhisperMessage(messageKeys.getMacKey(), @@ -90,15 +67,14 @@ public class SessionCipher { Pair pendingPreKey = sessionState.getPendingPreKey(); int localRegistrationId = sessionState.getLocalRegistrationId(); - ciphertextMessage = new PreKeyWhisperMessage(localRegistrationId, pendingPreKey.first, - pendingPreKey.second, + ciphertextMessage = new PreKeyWhisperMessage(localRegistrationId, pendingPreKey.first(), + pendingPreKey.second(), sessionState.getLocalIdentityKey(), (WhisperMessage) ciphertextMessage); } sessionState.setSenderChainKey(chainKey.getNextChainKey()); - sessionRecord.save(); - + sessionStore.save(); return ciphertextMessage; } } @@ -107,32 +83,31 @@ public class SessionCipher { throws InvalidMessageException, DuplicateMessageException, LegacyMessageException { synchronized (SESSION_LOCK) { - SessionRecordV2 sessionRecord = getSessionRecord(); - SessionState sessionState = sessionRecord.getSessionState(); - List previousStates = sessionRecord.getPreviousSessions(); + SessionState sessionState = sessionStore.getSessionState(); + List previousStates = sessionStore.getPreviousSessionStates(); + List exceptions = new LinkedList(); try { byte[] plaintext = decrypt(sessionState, decodedMessage); - sessionRecord.save(); + sessionStore.save(); return plaintext; } catch (InvalidMessageException e) { - Log.w("SessionCipherV2", e); + exceptions.add(e); } for (SessionState previousState : previousStates) { try { - Log.w("SessionCipherV2", "Attempting decrypt on previous state..."); byte[] plaintext = decrypt(previousState, decodedMessage); - sessionRecord.save(); + sessionStore.save(); return plaintext; } catch (InvalidMessageException e) { - Log.w("SessionCipherV2", e); + exceptions.add(e); } } - throw new InvalidMessageException("No valid sessions."); + throw new InvalidMessageException("No valid sessions.", exceptions); } } @@ -162,8 +137,7 @@ public class SessionCipher { public int getRemoteRegistrationId() { synchronized (SESSION_LOCK) { - SessionRecordV2 sessionRecord = getSessionRecord(); - return sessionRecord.getSessionState().getRemoteRegistrationId(); + return sessionStore.getSessionState().getRemoteRegistrationId(); } } @@ -174,18 +148,18 @@ public class SessionCipher { if (sessionState.hasReceiverChain(theirEphemeral)) { return sessionState.getReceiverChainKey(theirEphemeral); } else { - RootKey rootKey = sessionState.getRootKey(); - ECKeyPair ourEphemeral = sessionState.getSenderEphemeralPair(); + RootKey rootKey = sessionState.getRootKey(); + ECKeyPair ourEphemeral = sessionState.getSenderEphemeralPair(); Pair receiverChain = rootKey.createChain(theirEphemeral, ourEphemeral); ECKeyPair ourNewEphemeral = Curve.generateKeyPair(true); - Pair senderChain = receiverChain.first.createChain(theirEphemeral, ourNewEphemeral); + Pair senderChain = receiverChain.first().createChain(theirEphemeral, ourNewEphemeral); - sessionState.setRootKey(senderChain.first); - sessionState.addReceiverChain(theirEphemeral, receiverChain.second); + sessionState.setRootKey(senderChain.first()); + sessionState.addReceiverChain(theirEphemeral, receiverChain.second()); sessionState.setPreviousCounter(sessionState.getSenderChainKey().getIndex()-1); - sessionState.setSenderChain(ourNewEphemeral, senderChain.second); + sessionState.setSenderChain(ourNewEphemeral, senderChain.second()); - return receiverChain.second; + return receiverChain.second(); } } catch (InvalidKeyException e) { throw new InvalidMessageException(e); @@ -252,7 +226,7 @@ public class SessionCipher { Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding"); byte[] ivBytes = new byte[16]; - Conversions.intToByteArray(ivBytes, 0, counter); + ByteUtil.intToByteArray(ivBytes, 0, counter); IvParameterSpec iv = new IvParameterSpec(ivBytes); cipher.init(mode, key, iv); @@ -268,8 +242,4 @@ public class SessionCipher { throw new AssertionError(e); } } - - private SessionRecordV2 getSessionRecord() { - return new SessionRecordV2(context, masterSecret, recipient); - } } \ No newline at end of file diff --git a/libaxolotl/src/main/java/org/whispersystems/libaxolotl/SessionState.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/SessionState.java new file mode 100644 index 000000000..60deab98a --- /dev/null +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/SessionState.java @@ -0,0 +1,54 @@ +package org.whispersystems.libaxolotl; + +import org.whispersystems.libaxolotl.ecc.ECKeyPair; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; +import org.whispersystems.libaxolotl.ratchet.ChainKey; +import org.whispersystems.libaxolotl.ratchet.MessageKeys; +import org.whispersystems.libaxolotl.ratchet.RootKey; +import org.whispersystems.libaxolotl.util.Pair; + +public interface SessionState { + public void setNeedsRefresh(boolean needsRefresh); + public boolean getNeedsRefresh(); + public void setSessionVersion(int version); + public int getSessionVersion(); + public void setRemoteIdentityKey(IdentityKey identityKey); + public void setLocalIdentityKey(IdentityKey identityKey); + public IdentityKey getRemoteIdentityKey(); + public IdentityKey getLocalIdentityKey(); + public int getPreviousCounter(); + public void setPreviousCounter(int previousCounter); + public RootKey getRootKey(); + public void setRootKey(RootKey rootKey); + public ECPublicKey getSenderEphemeral(); + public ECKeyPair getSenderEphemeralPair(); + public boolean hasReceiverChain(ECPublicKey senderEphemeral); + public boolean hasSenderChain(); + public ChainKey getReceiverChainKey(ECPublicKey senderEphemeral); + public void addReceiverChain(ECPublicKey senderEphemeral, ChainKey chainKey); + public void setSenderChain(ECKeyPair senderEphemeralPair, ChainKey chainKey); + public ChainKey getSenderChainKey(); + public void setSenderChainKey(ChainKey nextChainKey); + public boolean hasMessageKeys(ECPublicKey senderEphemeral, int counter); + public MessageKeys removeMessageKeys(ECPublicKey senderEphemeral, int counter); + public void setMessageKeys(ECPublicKey senderEphemeral, MessageKeys messageKeys); + public void setReceiverChainKey(ECPublicKey senderEphemeral, ChainKey chainKey); + public void setPendingKeyExchange(int sequence, + ECKeyPair ourBaseKey, + ECKeyPair ourEphemeralKey, + IdentityKeyPair ourIdentityKey); + public int getPendingKeyExchangeSequence(); + public ECKeyPair getPendingKeyExchangeBaseKey() throws InvalidKeyException; + public ECKeyPair getPendingKeyExchangeEphemeralKey() throws InvalidKeyException; + public IdentityKeyPair getPendingKeyExchangeIdentityKey() throws InvalidKeyException; + public boolean hasPendingKeyExchange(); + public void setPendingPreKey(int preKeyId, ECPublicKey baseKey); + public boolean hasPendingPreKey(); + public Pair getPendingPreKey(); + public void clearPendingPreKey(); + public void setRemoteRegistrationId(int registrationId); + public int getRemoteRegistrationId(); + public void setLocalRegistrationId(int registrationId); + public int getLocalRegistrationId(); + public byte[] serialize(); +} diff --git a/libaxolotl/src/main/java/org/whispersystems/libaxolotl/SessionStore.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/SessionStore.java new file mode 100644 index 000000000..123ae449c --- /dev/null +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/SessionStore.java @@ -0,0 +1,12 @@ +package org.whispersystems.libaxolotl; + +import java.util.List; + +public interface SessionStore { + + public SessionState getSessionState(); + public List getPreviousSessionStates(); + public void save(); + + +} diff --git a/library/src/org/whispersystems/textsecure/crypto/ecc/Curve.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/Curve.java similarity index 90% rename from library/src/org/whispersystems/textsecure/crypto/ecc/Curve.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/Curve.java index 5ae56716e..c69c3b826 100644 --- a/library/src/org/whispersystems/textsecure/crypto/ecc/Curve.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/Curve.java @@ -14,10 +14,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package org.whispersystems.textsecure.crypto.ecc; +package org.whispersystems.libaxolotl.ecc; -import org.whispersystems.textsecure.crypto.InvalidKeyException; -import org.whispersystems.textsecure.crypto.protocol.CiphertextMessage; +import org.whispersystems.libaxolotl.InvalidKeyException; public class Curve { diff --git a/library/src/org/whispersystems/textsecure/crypto/ecc/Curve25519.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/Curve25519.java similarity index 95% rename from library/src/org/whispersystems/textsecure/crypto/ecc/Curve25519.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/Curve25519.java index 94bd71b67..fdefab570 100644 --- a/library/src/org/whispersystems/textsecure/crypto/ecc/Curve25519.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/Curve25519.java @@ -14,9 +14,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package org.whispersystems.textsecure.crypto.ecc; +package org.whispersystems.libaxolotl.ecc; -import org.whispersystems.textsecure.crypto.InvalidKeyException; +import org.whispersystems.libaxolotl.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; diff --git a/library/src/org/whispersystems/textsecure/crypto/ecc/DjbECPrivateKey.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/DjbECPrivateKey.java similarity index 95% rename from library/src/org/whispersystems/textsecure/crypto/ecc/DjbECPrivateKey.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/DjbECPrivateKey.java index fbf37a223..ecb55b4ee 100644 --- a/library/src/org/whispersystems/textsecure/crypto/ecc/DjbECPrivateKey.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/DjbECPrivateKey.java @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package org.whispersystems.textsecure.crypto.ecc; +package org.whispersystems.libaxolotl.ecc; public class DjbECPrivateKey implements ECPrivateKey { diff --git a/library/src/org/whispersystems/textsecure/crypto/ecc/DjbECPublicKey.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/DjbECPublicKey.java similarity index 92% rename from library/src/org/whispersystems/textsecure/crypto/ecc/DjbECPublicKey.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/DjbECPublicKey.java index bd6020741..9f66d4393 100644 --- a/library/src/org/whispersystems/textsecure/crypto/ecc/DjbECPublicKey.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/DjbECPublicKey.java @@ -15,9 +15,9 @@ * along with this program. If not, see . */ -package org.whispersystems.textsecure.crypto.ecc; +package org.whispersystems.libaxolotl.ecc; -import org.whispersystems.textsecure.util.Util; +import org.whispersystems.libaxolotl.util.ByteUtil; import java.math.BigInteger; import java.util.Arrays; @@ -33,7 +33,7 @@ public class DjbECPublicKey implements ECPublicKey { @Override public byte[] serialize() { byte[] type = {Curve.DJB_TYPE}; - return Util.combine(type, publicKey); + return ByteUtil.combine(type, publicKey); } @Override diff --git a/library/src/org/whispersystems/textsecure/crypto/ecc/ECKeyPair.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/ECKeyPair.java similarity index 95% rename from library/src/org/whispersystems/textsecure/crypto/ecc/ECKeyPair.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/ECKeyPair.java index a592080ea..bcaec927d 100644 --- a/library/src/org/whispersystems/textsecure/crypto/ecc/ECKeyPair.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/ECKeyPair.java @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package org.whispersystems.textsecure.crypto.ecc; +package org.whispersystems.libaxolotl.ecc; public class ECKeyPair { diff --git a/library/src/org/whispersystems/textsecure/crypto/ecc/ECPrivateKey.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/ECPrivateKey.java similarity index 94% rename from library/src/org/whispersystems/textsecure/crypto/ecc/ECPrivateKey.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/ECPrivateKey.java index 4892d0e65..922057de7 100644 --- a/library/src/org/whispersystems/textsecure/crypto/ecc/ECPrivateKey.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/ECPrivateKey.java @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package org.whispersystems.textsecure.crypto.ecc; +package org.whispersystems.libaxolotl.ecc; public interface ECPrivateKey { public byte[] serialize(); diff --git a/library/src/org/whispersystems/textsecure/crypto/ecc/ECPublicKey.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/ECPublicKey.java similarity index 94% rename from library/src/org/whispersystems/textsecure/crypto/ecc/ECPublicKey.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/ECPublicKey.java index 42a9ce86d..125768073 100644 --- a/library/src/org/whispersystems/textsecure/crypto/ecc/ECPublicKey.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ecc/ECPublicKey.java @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package org.whispersystems.textsecure.crypto.ecc; +package org.whispersystems.libaxolotl.ecc; public interface ECPublicKey extends Comparable { diff --git a/library/src/org/whispersystems/textsecure/crypto/kdf/DerivedSecrets.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/kdf/DerivedSecrets.java similarity index 95% rename from library/src/org/whispersystems/textsecure/crypto/kdf/DerivedSecrets.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/kdf/DerivedSecrets.java index 294b1b27c..93786947e 100644 --- a/library/src/org/whispersystems/textsecure/crypto/kdf/DerivedSecrets.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/kdf/DerivedSecrets.java @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package org.whispersystems.textsecure.crypto.kdf; +package org.whispersystems.libaxolotl.kdf; import javax.crypto.spec.SecretKeySpec; diff --git a/library/src/org/whispersystems/textsecure/crypto/kdf/HKDF.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/kdf/HKDF.java similarity index 97% rename from library/src/org/whispersystems/textsecure/crypto/kdf/HKDF.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/kdf/HKDF.java index cbad84e54..2370efdd4 100644 --- a/library/src/org/whispersystems/textsecure/crypto/kdf/HKDF.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/kdf/HKDF.java @@ -15,13 +15,11 @@ * along with this program. If not, see . */ -package org.whispersystems.textsecure.crypto.kdf; +package org.whispersystems.libaxolotl.kdf; import java.io.ByteArrayOutputStream; -import java.math.BigInteger; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; -import java.util.List; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; diff --git a/libaxolotl/src/main/java/org/whispersystems/libaxolotl/protocol/CiphertextMessage.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/protocol/CiphertextMessage.java new file mode 100644 index 000000000..b3213126b --- /dev/null +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/protocol/CiphertextMessage.java @@ -0,0 +1,33 @@ +/** + * 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.protocol; + +public interface CiphertextMessage { + + public static final int UNSUPPORTED_VERSION = 1; + public static final int CURRENT_VERSION = 2; + + public static final int WHISPER_TYPE = 2; + public static final int PREKEY_TYPE = 3; + + // This should be the worst case (worse than V2). So not always accurate, but good enough for padding. + public static final int ENCRYPTED_MESSAGE_OVERHEAD = 53; + + public byte[] serialize(); + public int getType(); + +} \ No newline at end of file diff --git a/library/src/org/whispersystems/textsecure/crypto/protocol/PreKeyWhisperMessage.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/protocol/PreKeyWhisperMessage.java similarity index 71% rename from library/src/org/whispersystems/textsecure/crypto/protocol/PreKeyWhisperMessage.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/protocol/PreKeyWhisperMessage.java index 5845dc044..801babf53 100644 --- a/library/src/org/whispersystems/textsecure/crypto/protocol/PreKeyWhisperMessage.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/protocol/PreKeyWhisperMessage.java @@ -1,17 +1,33 @@ -package org.whispersystems.textsecure.crypto.protocol; +/** + * 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.protocol; import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; -import org.whispersystems.textsecure.crypto.IdentityKey; -import org.whispersystems.textsecure.crypto.InvalidKeyException; -import org.whispersystems.textsecure.crypto.InvalidMessageException; -import org.whispersystems.textsecure.crypto.InvalidVersionException; -import org.whispersystems.textsecure.crypto.LegacyMessageException; -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; -import org.whispersystems.textsecure.util.Conversions; -import org.whispersystems.textsecure.util.Util; +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.InvalidMessageException; +import org.whispersystems.libaxolotl.InvalidVersionException; +import org.whispersystems.libaxolotl.LegacyMessageException; +import org.whispersystems.libaxolotl.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; +import org.whispersystems.libaxolotl.util.ByteUtil; + public class PreKeyWhisperMessage implements CiphertextMessage { @@ -27,7 +43,7 @@ public class PreKeyWhisperMessage implements CiphertextMessage { throws InvalidMessageException, InvalidVersionException { try { - this.version = Conversions.highBitsToInt(serialized[0]); + this.version = ByteUtil.highBitsToInt(serialized[0]); if (this.version > CiphertextMessage.CURRENT_VERSION) { throw new InvalidVersionException("Unknown version: " + this.version); @@ -70,7 +86,7 @@ public class PreKeyWhisperMessage implements CiphertextMessage { this.identityKey = identityKey; this.message = message; - byte[] versionBytes = {Conversions.intsToByteHighAndLow(CURRENT_VERSION, this.version)}; + byte[] versionBytes = {ByteUtil.intsToByteHighAndLow(CURRENT_VERSION, this.version)}; byte[] messageBytes = WhisperProtos.PreKeyWhisperMessage.newBuilder() .setPreKeyId(preKeyId) .setBaseKey(ByteString.copyFrom(baseKey.serialize())) @@ -79,7 +95,7 @@ public class PreKeyWhisperMessage implements CiphertextMessage { .setRegistrationId(registrationId) .build().toByteArray(); - this.serialized = Util.combine(versionBytes, messageBytes); + this.serialized = ByteUtil.combine(versionBytes, messageBytes); } public IdentityKey getIdentityKey() { diff --git a/library/src/org/whispersystems/textsecure/crypto/protocol/WhisperMessage.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/protocol/WhisperMessage.java similarity index 65% rename from library/src/org/whispersystems/textsecure/crypto/protocol/WhisperMessage.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/protocol/WhisperMessage.java index 534397ac8..53a9629c8 100644 --- a/library/src/org/whispersystems/textsecure/crypto/protocol/WhisperMessage.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/protocol/WhisperMessage.java @@ -1,15 +1,30 @@ -package org.whispersystems.textsecure.crypto.protocol; +/** + * 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.protocol; import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; -import org.whispersystems.textsecure.crypto.InvalidKeyException; -import org.whispersystems.textsecure.crypto.InvalidMessageException; -import org.whispersystems.textsecure.crypto.LegacyMessageException; -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; -import org.whispersystems.textsecure.util.Conversions; -import org.whispersystems.textsecure.util.Util; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.InvalidMessageException; +import org.whispersystems.libaxolotl.LegacyMessageException; +import org.whispersystems.libaxolotl.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; +import org.whispersystems.libaxolotl.util.ByteUtil; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -30,17 +45,17 @@ public class WhisperMessage implements CiphertextMessage { public WhisperMessage(byte[] serialized) throws InvalidMessageException, LegacyMessageException { try { - byte[][] messageParts = Util.split(serialized, 1, serialized.length - 1 - MAC_LENGTH, MAC_LENGTH); + byte[][] messageParts = ByteUtil.split(serialized, 1, serialized.length - 1 - MAC_LENGTH, MAC_LENGTH); byte version = messageParts[0][0]; byte[] message = messageParts[1]; byte[] mac = messageParts[2]; - if (Conversions.highBitsToInt(version) <= CiphertextMessage.UNSUPPORTED_VERSION) { - throw new LegacyMessageException("Legacy message: " + Conversions.highBitsToInt(version)); + if (ByteUtil.highBitsToInt(version) <= CiphertextMessage.UNSUPPORTED_VERSION) { + throw new LegacyMessageException("Legacy message: " + ByteUtil.highBitsToInt(version)); } - if (Conversions.highBitsToInt(version) != CURRENT_VERSION) { - throw new InvalidMessageException("Unknown version: " + Conversions.highBitsToInt(version)); + if (ByteUtil.highBitsToInt(version) != CURRENT_VERSION) { + throw new InvalidMessageException("Unknown version: " + ByteUtil.highBitsToInt(version)); } WhisperProtos.WhisperMessage whisperMessage = WhisperProtos.WhisperMessage.parseFrom(message); @@ -69,16 +84,16 @@ public class WhisperMessage implements CiphertextMessage { public WhisperMessage(SecretKeySpec macKey, ECPublicKey senderEphemeral, int counter, int previousCounter, byte[] ciphertext) { - byte[] version = {Conversions.intsToByteHighAndLow(CURRENT_VERSION, CURRENT_VERSION)}; + byte[] version = {ByteUtil.intsToByteHighAndLow(CURRENT_VERSION, CURRENT_VERSION)}; byte[] message = WhisperProtos.WhisperMessage.newBuilder() .setEphemeralKey(ByteString.copyFrom(senderEphemeral.serialize())) .setCounter(counter) .setPreviousCounter(previousCounter) .setCiphertext(ByteString.copyFrom(ciphertext)) .build().toByteArray(); - byte[] mac = getMac(macKey, Util.combine(version, message)); + byte[] mac = getMac(macKey, ByteUtil.combine(version, message)); - this.serialized = Util.combine(version, message, mac); + this.serialized = ByteUtil.combine(version, message, mac); this.senderEphemeral = senderEphemeral; this.counter = counter; this.previousCounter = previousCounter; @@ -100,7 +115,7 @@ public class WhisperMessage implements CiphertextMessage { public void verifyMac(SecretKeySpec macKey) throws InvalidMessageException { - byte[][] parts = Util.split(serialized, serialized.length - MAC_LENGTH, MAC_LENGTH); + byte[][] parts = ByteUtil.split(serialized, serialized.length - MAC_LENGTH, MAC_LENGTH); byte[] ourMac = getMac(macKey, parts[0]); byte[] theirMac = parts[1]; @@ -115,7 +130,7 @@ public class WhisperMessage implements CiphertextMessage { mac.init(macKey); byte[] fullMac = mac.doFinal(serialized); - return Util.trim(fullMac, MAC_LENGTH); + return ByteUtil.trim(fullMac, MAC_LENGTH); } catch (NoSuchAlgorithmException e) { throw new AssertionError(e); } catch (java.security.InvalidKeyException e) { @@ -135,7 +150,7 @@ public class WhisperMessage implements CiphertextMessage { public static boolean isLegacy(byte[] message) { return message != null && message.length >= 1 && - Conversions.highBitsToInt(message[0]) <= CiphertextMessage.UNSUPPORTED_VERSION; + ByteUtil.highBitsToInt(message[0]) <= CiphertextMessage.UNSUPPORTED_VERSION; } } diff --git a/library/src/org/whispersystems/textsecure/crypto/protocol/WhisperProtos.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/protocol/WhisperProtos.java similarity index 82% rename from library/src/org/whispersystems/textsecure/crypto/protocol/WhisperProtos.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/protocol/WhisperProtos.java index 4af21a369..f971faddc 100644 --- a/library/src/org/whispersystems/textsecure/crypto/protocol/WhisperProtos.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/protocol/WhisperProtos.java @@ -1,7 +1,7 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! // source: WhisperTextProtocol.proto -package org.whispersystems.textsecure.crypto.protocol; +package org.whispersystems.libaxolotl.protocol; public final class WhisperProtos { private WhisperProtos() {} @@ -47,12 +47,12 @@ public final class WhisperProtos { public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_WhisperMessage_descriptor; + return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_WhisperMessage_descriptor; } protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_WhisperMessage_fieldAccessorTable; + return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_WhisperMessage_fieldAccessorTable; } private int bitField0_; @@ -163,41 +163,41 @@ public final class WhisperProtos { return super.writeReplace(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage parseFrom( com.google.protobuf.ByteString data) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data).buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage parseFrom( com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data, extensionRegistry) .buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseFrom(byte[] data) + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data).buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage parseFrom( byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data, extensionRegistry) .buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseFrom(java.io.InputStream input) + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage parseFrom(java.io.InputStream input) throws java.io.IOException { return newBuilder().mergeFrom(input).buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage parseFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return newBuilder().mergeFrom(input, extensionRegistry) .buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseDelimitedFrom(java.io.InputStream input) + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException { Builder builder = newBuilder(); if (builder.mergeDelimitedFrom(input)) { @@ -206,7 +206,7 @@ public final class WhisperProtos { return null; } } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseDelimitedFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage parseDelimitedFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { @@ -217,12 +217,12 @@ public final class WhisperProtos { return null; } } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage parseFrom( com.google.protobuf.CodedInputStream input) throws java.io.IOException { return newBuilder().mergeFrom(input).buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage parseFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { @@ -232,7 +232,7 @@ public final class WhisperProtos { public static Builder newBuilder() { return Builder.create(); } public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder(org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage prototype) { + public static Builder newBuilder(org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage prototype) { return newBuilder().mergeFrom(prototype); } public Builder toBuilder() { return newBuilder(this); } @@ -245,18 +245,18 @@ public final class WhisperProtos { } public static final class Builder extends com.google.protobuf.GeneratedMessage.Builder - implements org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessageOrBuilder { + implements org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessageOrBuilder { public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_WhisperMessage_descriptor; + return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_WhisperMessage_descriptor; } protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_WhisperMessage_fieldAccessorTable; + return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_WhisperMessage_fieldAccessorTable; } - // Construct using org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage.newBuilder() + // Construct using org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage.newBuilder() private Builder() { maybeForceBuilderInitialization(); } @@ -292,24 +292,24 @@ public final class WhisperProtos { public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage.getDescriptor(); + return org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage.getDescriptor(); } - public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage getDefaultInstanceForType() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage.getDefaultInstance(); + public org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage getDefaultInstanceForType() { + return org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage.getDefaultInstance(); } - public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage build() { - org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage result = buildPartial(); + public org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage build() { + org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException(result); } return result; } - private org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage buildParsed() + private org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage buildParsed() throws com.google.protobuf.InvalidProtocolBufferException { - org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage result = buildPartial(); + org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException( result).asInvalidProtocolBufferException(); @@ -317,8 +317,8 @@ public final class WhisperProtos { return result; } - public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage buildPartial() { - org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage result = new org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage(this); + public org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage buildPartial() { + org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage result = new org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage(this); int from_bitField0_ = bitField0_; int to_bitField0_ = 0; if (((from_bitField0_ & 0x00000001) == 0x00000001)) { @@ -343,16 +343,16 @@ public final class WhisperProtos { } public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage) { - return mergeFrom((org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage)other); + if (other instanceof org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage) { + return mergeFrom((org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage)other); } else { super.mergeFrom(other); return this; } } - public Builder mergeFrom(org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage other) { - if (other == org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage.getDefaultInstance()) return this; + public Builder mergeFrom(org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage other) { + if (other == org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage.getDefaultInstance()) return this; if (other.hasEphemeralKey()) { setEphemeralKey(other.getEphemeralKey()); } @@ -566,12 +566,12 @@ public final class WhisperProtos { public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_PreKeyWhisperMessage_descriptor; + return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_PreKeyWhisperMessage_descriptor; } protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_PreKeyWhisperMessage_fieldAccessorTable; + return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_PreKeyWhisperMessage_fieldAccessorTable; } private int bitField0_; @@ -700,41 +700,41 @@ public final class WhisperProtos { return super.writeReplace(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom( com.google.protobuf.ByteString data) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data).buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom( com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data, extensionRegistry) .buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom(byte[] data) + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data).buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom( byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data, extensionRegistry) .buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom(java.io.InputStream input) + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom(java.io.InputStream input) throws java.io.IOException { return newBuilder().mergeFrom(input).buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return newBuilder().mergeFrom(input, extensionRegistry) .buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseDelimitedFrom(java.io.InputStream input) + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException { Builder builder = newBuilder(); if (builder.mergeDelimitedFrom(input)) { @@ -743,7 +743,7 @@ public final class WhisperProtos { return null; } } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseDelimitedFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage parseDelimitedFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { @@ -754,12 +754,12 @@ public final class WhisperProtos { return null; } } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom( com.google.protobuf.CodedInputStream input) throws java.io.IOException { return newBuilder().mergeFrom(input).buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage parseFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { @@ -769,7 +769,7 @@ public final class WhisperProtos { public static Builder newBuilder() { return Builder.create(); } public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder(org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage prototype) { + public static Builder newBuilder(org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage prototype) { return newBuilder().mergeFrom(prototype); } public Builder toBuilder() { return newBuilder(this); } @@ -782,18 +782,18 @@ public final class WhisperProtos { } public static final class Builder extends com.google.protobuf.GeneratedMessage.Builder - implements org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessageOrBuilder { + implements org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessageOrBuilder { public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_PreKeyWhisperMessage_descriptor; + return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_PreKeyWhisperMessage_descriptor; } protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_PreKeyWhisperMessage_fieldAccessorTable; + return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_PreKeyWhisperMessage_fieldAccessorTable; } - // Construct using org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage.newBuilder() + // Construct using org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage.newBuilder() private Builder() { maybeForceBuilderInitialization(); } @@ -831,24 +831,24 @@ public final class WhisperProtos { public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage.getDescriptor(); + return org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage.getDescriptor(); } - public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage getDefaultInstanceForType() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage.getDefaultInstance(); + public org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage getDefaultInstanceForType() { + return org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage.getDefaultInstance(); } - public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage build() { - org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage result = buildPartial(); + public org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage build() { + org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException(result); } return result; } - private org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage buildParsed() + private org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage buildParsed() throws com.google.protobuf.InvalidProtocolBufferException { - org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage result = buildPartial(); + org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException( result).asInvalidProtocolBufferException(); @@ -856,8 +856,8 @@ public final class WhisperProtos { return result; } - public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage buildPartial() { - org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage result = new org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage(this); + public org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage buildPartial() { + org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage result = new org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage(this); int from_bitField0_ = bitField0_; int to_bitField0_ = 0; if (((from_bitField0_ & 0x00000001) == 0x00000001)) { @@ -886,16 +886,16 @@ public final class WhisperProtos { } public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage) { - return mergeFrom((org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage)other); + if (other instanceof org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage) { + return mergeFrom((org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage)other); } else { super.mergeFrom(other); return this; } } - public Builder mergeFrom(org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage other) { - if (other == org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage.getDefaultInstance()) return this; + public Builder mergeFrom(org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage other) { + if (other == org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage.getDefaultInstance()) return this; if (other.hasRegistrationId()) { setRegistrationId(other.getRegistrationId()); } @@ -1137,12 +1137,12 @@ public final class WhisperProtos { public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_KeyExchangeMessage_descriptor; + return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_KeyExchangeMessage_descriptor; } protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_KeyExchangeMessage_fieldAccessorTable; + return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_KeyExchangeMessage_fieldAccessorTable; } private int bitField0_; @@ -1253,41 +1253,41 @@ public final class WhisperProtos { return super.writeReplace(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage parseFrom( com.google.protobuf.ByteString data) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data).buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage parseFrom( com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data, extensionRegistry) .buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseFrom(byte[] data) + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data).buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage parseFrom( byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data, extensionRegistry) .buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseFrom(java.io.InputStream input) + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage parseFrom(java.io.InputStream input) throws java.io.IOException { return newBuilder().mergeFrom(input).buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage parseFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return newBuilder().mergeFrom(input, extensionRegistry) .buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseDelimitedFrom(java.io.InputStream input) + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException { Builder builder = newBuilder(); if (builder.mergeDelimitedFrom(input)) { @@ -1296,7 +1296,7 @@ public final class WhisperProtos { return null; } } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseDelimitedFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage parseDelimitedFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { @@ -1307,12 +1307,12 @@ public final class WhisperProtos { return null; } } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage parseFrom( com.google.protobuf.CodedInputStream input) throws java.io.IOException { return newBuilder().mergeFrom(input).buildParsed(); } - public static org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage parseFrom( + public static org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage parseFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { @@ -1322,7 +1322,7 @@ public final class WhisperProtos { public static Builder newBuilder() { return Builder.create(); } public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder(org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage prototype) { + public static Builder newBuilder(org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage prototype) { return newBuilder().mergeFrom(prototype); } public Builder toBuilder() { return newBuilder(this); } @@ -1335,18 +1335,18 @@ public final class WhisperProtos { } public static final class Builder extends com.google.protobuf.GeneratedMessage.Builder - implements org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessageOrBuilder { + implements org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessageOrBuilder { public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_KeyExchangeMessage_descriptor; + return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_KeyExchangeMessage_descriptor; } protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.internal_static_textsecure_KeyExchangeMessage_fieldAccessorTable; + return org.whispersystems.libaxolotl.protocol.WhisperProtos.internal_static_textsecure_KeyExchangeMessage_fieldAccessorTable; } - // Construct using org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage.newBuilder() + // Construct using org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage.newBuilder() private Builder() { maybeForceBuilderInitialization(); } @@ -1382,24 +1382,24 @@ public final class WhisperProtos { public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage.getDescriptor(); + return org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage.getDescriptor(); } - public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage getDefaultInstanceForType() { - return org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage.getDefaultInstance(); + public org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage getDefaultInstanceForType() { + return org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage.getDefaultInstance(); } - public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage build() { - org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage result = buildPartial(); + public org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage build() { + org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException(result); } return result; } - private org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage buildParsed() + private org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage buildParsed() throws com.google.protobuf.InvalidProtocolBufferException { - org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage result = buildPartial(); + org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException( result).asInvalidProtocolBufferException(); @@ -1407,8 +1407,8 @@ public final class WhisperProtos { return result; } - public org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage buildPartial() { - org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage result = new org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage(this); + public org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage buildPartial() { + org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage result = new org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage(this); int from_bitField0_ = bitField0_; int to_bitField0_ = 0; if (((from_bitField0_ & 0x00000001) == 0x00000001)) { @@ -1433,16 +1433,16 @@ public final class WhisperProtos { } public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage) { - return mergeFrom((org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage)other); + if (other instanceof org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage) { + return mergeFrom((org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage)other); } else { super.mergeFrom(other); return this; } } - public Builder mergeFrom(org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage other) { - if (other == org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage.getDefaultInstance()) return this; + public Builder mergeFrom(org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage other) { + if (other == org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage.getDefaultInstance()) return this; if (other.hasId()) { setId(other.getId()); } @@ -1648,9 +1648,9 @@ public final class WhisperProtos { "d\030\001 \001(\r\022\017\n\007baseKey\030\002 \001(\014\022\023\n\013identityKey\030" + "\003 \001(\014\022\017\n\007message\030\004 \001(\014\"\\\n\022KeyExchangeMes" + "sage\022\n\n\002id\030\001 \001(\r\022\017\n\007baseKey\030\002 \001(\014\022\024\n\014eph" + - "emeralKey\030\003 \001(\014\022\023\n\013identityKey\030\004 \001(\014B>\n-" + - "org.whispersystems.textsecure.crypto.pro", - "tocolB\rWhisperProtos" + "emeralKey\030\003 \001(\014\022\023\n\013identityKey\030\004 \001(\014B7\n&" + + "org.whispersystems.libaxolotl.protocolB\r", + "WhisperProtos" }; com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { @@ -1663,24 +1663,24 @@ public final class WhisperProtos { com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_textsecure_WhisperMessage_descriptor, new java.lang.String[] { "EphemeralKey", "Counter", "PreviousCounter", "Ciphertext", }, - org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage.class, - org.whispersystems.textsecure.crypto.protocol.WhisperProtos.WhisperMessage.Builder.class); + org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage.class, + org.whispersystems.libaxolotl.protocol.WhisperProtos.WhisperMessage.Builder.class); internal_static_textsecure_PreKeyWhisperMessage_descriptor = getDescriptor().getMessageTypes().get(1); internal_static_textsecure_PreKeyWhisperMessage_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_textsecure_PreKeyWhisperMessage_descriptor, new java.lang.String[] { "RegistrationId", "PreKeyId", "BaseKey", "IdentityKey", "Message", }, - org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage.class, - org.whispersystems.textsecure.crypto.protocol.WhisperProtos.PreKeyWhisperMessage.Builder.class); + org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage.class, + org.whispersystems.libaxolotl.protocol.WhisperProtos.PreKeyWhisperMessage.Builder.class); internal_static_textsecure_KeyExchangeMessage_descriptor = getDescriptor().getMessageTypes().get(2); internal_static_textsecure_KeyExchangeMessage_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_textsecure_KeyExchangeMessage_descriptor, new java.lang.String[] { "Id", "BaseKey", "EphemeralKey", "IdentityKey", }, - org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage.class, - org.whispersystems.textsecure.crypto.protocol.WhisperProtos.KeyExchangeMessage.Builder.class); + org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage.class, + org.whispersystems.libaxolotl.protocol.WhisperProtos.KeyExchangeMessage.Builder.class); return null; } }; diff --git a/library/src/org/whispersystems/textsecure/crypto/ratchet/ChainKey.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/ChainKey.java similarity index 58% rename from library/src/org/whispersystems/textsecure/crypto/ratchet/ChainKey.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/ChainKey.java index c3c8b26ff..3f4daa710 100644 --- a/library/src/org/whispersystems/textsecure/crypto/ratchet/ChainKey.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/ChainKey.java @@ -1,7 +1,24 @@ -package org.whispersystems.textsecure.crypto.ratchet; +/** + * 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.textsecure.crypto.kdf.DerivedSecrets; -import org.whispersystems.textsecure.crypto.kdf.HKDF; + +import org.whispersystems.libaxolotl.kdf.DerivedSecrets; +import org.whispersystems.libaxolotl.kdf.HKDF; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; @@ -49,9 +66,7 @@ public class ChainKey { mac.init(new SecretKeySpec(key, "HmacSHA256")); return mac.doFinal(seed); - } catch (NoSuchAlgorithmException e) { - throw new AssertionError(e); - } catch (InvalidKeyException e) { + } catch (NoSuchAlgorithmException | InvalidKeyException e) { throw new AssertionError(e); } } diff --git a/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/MessageKeys.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/MessageKeys.java new file mode 100644 index 000000000..e4aed3df7 --- /dev/null +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/MessageKeys.java @@ -0,0 +1,44 @@ +/** + * 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.SecretKeySpec; + +public class MessageKeys { + + private final SecretKeySpec cipherKey; + private final SecretKeySpec macKey; + private final int counter; + + public MessageKeys(SecretKeySpec cipherKey, SecretKeySpec macKey, int counter) { + this.cipherKey = cipherKey; + this.macKey = macKey; + this.counter = counter; + } + + public SecretKeySpec getCipherKey() { + return cipherKey; + } + + public SecretKeySpec getMacKey() { + return macKey; + } + + public int getCounter() { + return counter; + } +} diff --git a/library/src/org/whispersystems/textsecure/crypto/ratchet/RatchetingSession.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/RatchetingSession.java similarity index 74% rename from library/src/org/whispersystems/textsecure/crypto/ratchet/RatchetingSession.java rename to libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/RatchetingSession.java index c2f34fffa..9a7a5e20f 100644 --- a/library/src/org/whispersystems/textsecure/crypto/ratchet/RatchetingSession.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/RatchetingSession.java @@ -1,16 +1,34 @@ -package org.whispersystems.textsecure.crypto.ratchet; +/** + * 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 android.util.Pair; +import android.util.Log; -import org.whispersystems.textsecure.crypto.IdentityKey; -import org.whispersystems.textsecure.crypto.IdentityKeyPair; -import org.whispersystems.textsecure.crypto.InvalidKeyException; -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECKeyPair; -import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; -import org.whispersystems.textsecure.crypto.kdf.DerivedSecrets; -import org.whispersystems.textsecure.crypto.kdf.HKDF; -import org.whispersystems.textsecure.storage.SessionState; +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.libaxolotl.IdentityKeyPair; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.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.Hex; +import org.whispersystems.libaxolotl.util.Pair; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -47,11 +65,11 @@ public class RatchetingSession { ECKeyPair sendingKey = Curve.generateKeyPair(true); Pair receivingChain = calculate3DHE(true, ourBaseKey, theirBaseKey, ourIdentityKey, theirIdentityKey); - Pair sendingChain = receivingChain.first.createChain(theirEphemeralKey, sendingKey); + Pair sendingChain = receivingChain.first().createChain(theirEphemeralKey, sendingKey); - sessionState.addReceiverChain(theirEphemeralKey, receivingChain.second); - sessionState.setSenderChain(sendingKey, sendingChain.second); - sessionState.setRootKey(sendingChain.first); + sessionState.addReceiverChain(theirEphemeralKey, receivingChain.second()); + sessionState.setSenderChain(sendingKey, sendingChain.second()); + sessionState.setRootKey(sendingChain.first()); } private static void initializeSessionAsBob(SessionState sessionState, @@ -67,8 +85,8 @@ public class RatchetingSession { Pair sendingChain = calculate3DHE(false, ourBaseKey, theirBaseKey, ourIdentityKey, theirIdentityKey); - sessionState.setSenderChain(ourEphemeralKey, sendingChain.second); - sessionState.setRootKey(sendingChain.first); + sessionState.setSenderChain(ourEphemeralKey, sendingChain.second()); + sessionState.setRootKey(sendingChain.first()); } private static Pair calculate3DHE(boolean isAlice, diff --git a/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/RootKey.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/RootKey.java new file mode 100644 index 000000000..9d59f133d --- /dev/null +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/ratchet/RootKey.java @@ -0,0 +1,50 @@ +/** + * 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.DerivedSecrets; +import org.whispersystems.libaxolotl.kdf.HKDF; +import org.whispersystems.libaxolotl.util.Pair; + +public class RootKey { + + private final byte[] key; + + public RootKey(byte[] key) { + this.key = key; + } + + public byte[] getKeyBytes() { + return key; + } + + public Pair createChain(ECPublicKey theirEphemeral, ECKeyPair ourEphemeral) + throws InvalidKeyException + { + HKDF kdf = new HKDF(); + byte[] sharedSecret = Curve.calculateAgreement(theirEphemeral, ourEphemeral.getPrivateKey()); + DerivedSecrets keys = kdf.deriveSecrets(sharedSecret, key, "WhisperRatchet".getBytes()); + RootKey newRootKey = new RootKey(keys.getCipherKey().getEncoded()); + ChainKey newChainKey = new ChainKey(keys.getMacKey().getEncoded(), 0); + + return new Pair<>(newRootKey, newChainKey); + } +} diff --git a/libaxolotl/src/main/java/org/whispersystems/libaxolotl/util/ByteUtil.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/util/ByteUtil.java new file mode 100644 index 000000000..e22b584d0 --- /dev/null +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/util/ByteUtil.java @@ -0,0 +1,241 @@ +/** + * 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.util; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.text.ParseException; + +public class ByteUtil { + + public static byte[] combine(byte[]... elements) { + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + for (byte[] element : elements) { + baos.write(element); + } + + return baos.toByteArray(); + } catch (IOException e) { + throw new AssertionError(e); + } + } + + public static byte[][] split(byte[] input, int firstLength, int secondLength) { + byte[][] parts = new byte[2][]; + + parts[0] = new byte[firstLength]; + System.arraycopy(input, 0, parts[0], 0, firstLength); + + parts[1] = new byte[secondLength]; + System.arraycopy(input, firstLength, parts[1], 0, secondLength); + + return parts; + } + + public static byte[][] split(byte[] input, int firstLength, int secondLength, int thirdLength) + throws ParseException + { + if (input == null || firstLength < 0 || secondLength < 0 || thirdLength < 0 || + input.length < firstLength + secondLength + thirdLength) + { + throw new ParseException("Input too small: " + (input == null ? null : Hex.toString(input)), 0); + } + + byte[][] parts = new byte[3][]; + + parts[0] = new byte[firstLength]; + System.arraycopy(input, 0, parts[0], 0, firstLength); + + parts[1] = new byte[secondLength]; + System.arraycopy(input, firstLength, parts[1], 0, secondLength); + + parts[2] = new byte[thirdLength]; + System.arraycopy(input, firstLength + secondLength, parts[2], 0, thirdLength); + + return parts; + } + + public static byte[] trim(byte[] input, int length) { + byte[] result = new byte[length]; + System.arraycopy(input, 0, result, 0, result.length); + + return result; + } + + public static byte intsToByteHighAndLow(int highValue, int lowValue) { + return (byte)((highValue << 4 | lowValue) & 0xFF); + } + + public static int highBitsToInt(byte value) { + return (value & 0xFF) >> 4; + } + + public static int lowBitsToInt(byte value) { + return (value & 0xF); + } + + public static int highBitsToMedium(int value) { + return (value >> 12); + } + + public static int lowBitsToMedium(int value) { + return (value & 0xFFF); + } + + public static byte[] shortToByteArray(int value) { + byte[] bytes = new byte[2]; + shortToByteArray(bytes, 0, value); + return bytes; + } + + public static int shortToByteArray(byte[] bytes, int offset, int value) { + bytes[offset+1] = (byte)value; + bytes[offset] = (byte)(value >> 8); + return 2; + } + + public static int shortToLittleEndianByteArray(byte[] bytes, int offset, int value) { + bytes[offset] = (byte)value; + bytes[offset+1] = (byte)(value >> 8); + return 2; + } + + public static byte[] mediumToByteArray(int value) { + byte[] bytes = new byte[3]; + mediumToByteArray(bytes, 0, value); + return bytes; + } + + public static int mediumToByteArray(byte[] bytes, int offset, int value) { + bytes[offset + 2] = (byte)value; + bytes[offset + 1] = (byte)(value >> 8); + bytes[offset] = (byte)(value >> 16); + return 3; + } + + public static byte[] intToByteArray(int value) { + byte[] bytes = new byte[4]; + intToByteArray(bytes, 0, value); + return bytes; + } + + public static int intToByteArray(byte[] bytes, int offset, int value) { + bytes[offset + 3] = (byte)value; + bytes[offset + 2] = (byte)(value >> 8); + bytes[offset + 1] = (byte)(value >> 16); + bytes[offset] = (byte)(value >> 24); + return 4; + } + + public static int intToLittleEndianByteArray(byte[] bytes, int offset, int value) { + bytes[offset] = (byte)value; + bytes[offset+1] = (byte)(value >> 8); + bytes[offset+2] = (byte)(value >> 16); + bytes[offset+3] = (byte)(value >> 24); + return 4; + } + + public static byte[] longToByteArray(long l) { + byte[] bytes = new byte[8]; + longToByteArray(bytes, 0, l); + return bytes; + } + + public static int longToByteArray(byte[] bytes, int offset, long value) { + bytes[offset + 7] = (byte)value; + bytes[offset + 6] = (byte)(value >> 8); + bytes[offset + 5] = (byte)(value >> 16); + bytes[offset + 4] = (byte)(value >> 24); + bytes[offset + 3] = (byte)(value >> 32); + bytes[offset + 2] = (byte)(value >> 40); + bytes[offset + 1] = (byte)(value >> 48); + bytes[offset] = (byte)(value >> 56); + return 8; + } + + public static int longTo4ByteArray(byte[] bytes, int offset, long value) { + bytes[offset + 3] = (byte)value; + bytes[offset + 2] = (byte)(value >> 8); + bytes[offset + 1] = (byte)(value >> 16); + bytes[offset + 0] = (byte)(value >> 24); + return 4; + } + + public static int byteArrayToShort(byte[] bytes) { + return byteArrayToShort(bytes, 0); + } + + public static int byteArrayToShort(byte[] bytes, int offset) { + return + (bytes[offset] & 0xff) << 8 | (bytes[offset + 1] & 0xff); + } + + // The SSL patented 3-byte Value. + public static int byteArrayToMedium(byte[] bytes, int offset) { + return + (bytes[offset] & 0xff) << 16 | + (bytes[offset + 1] & 0xff) << 8 | + (bytes[offset + 2] & 0xff); + } + + public static int byteArrayToInt(byte[] bytes) { + return byteArrayToInt(bytes, 0); + } + + public static int byteArrayToInt(byte[] bytes, int offset) { + return + (bytes[offset] & 0xff) << 24 | + (bytes[offset + 1] & 0xff) << 16 | + (bytes[offset + 2] & 0xff) << 8 | + (bytes[offset + 3] & 0xff); + } + + public static int byteArrayToIntLittleEndian(byte[] bytes, int offset) { + return + (bytes[offset + 3] & 0xff) << 24 | + (bytes[offset + 2] & 0xff) << 16 | + (bytes[offset + 1] & 0xff) << 8 | + (bytes[offset] & 0xff); + } + + public static long byteArrayToLong(byte[] bytes) { + return byteArrayToLong(bytes, 0); + } + + public static long byteArray4ToLong(byte[] bytes, int offset) { + return + ((bytes[offset + 0] & 0xffL) << 24) | + ((bytes[offset + 1] & 0xffL) << 16) | + ((bytes[offset + 2] & 0xffL) << 8) | + ((bytes[offset + 3] & 0xffL)); + } + + public static long byteArrayToLong(byte[] bytes, int offset) { + return + ((bytes[offset] & 0xffL) << 56) | + ((bytes[offset + 1] & 0xffL) << 48) | + ((bytes[offset + 2] & 0xffL) << 40) | + ((bytes[offset + 3] & 0xffL) << 32) | + ((bytes[offset + 4] & 0xffL) << 24) | + ((bytes[offset + 5] & 0xffL) << 16) | + ((bytes[offset + 6] & 0xffL) << 8) | + ((bytes[offset + 7] & 0xffL)); + } + +} diff --git a/libaxolotl/src/main/java/org/whispersystems/libaxolotl/util/Hex.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/util/Hex.java new file mode 100644 index 000000000..0d71e342a --- /dev/null +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/util/Hex.java @@ -0,0 +1,78 @@ +/** + * 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.util; + +import java.io.IOException; + +/** + * Utility for generating hex dumps. + */ +public class Hex { + + private final static char[] HEX_DIGITS = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' + }; + + public static String toString(byte[] bytes) { + return toString(bytes, 0, bytes.length); + } + + public static String toString(byte[] bytes, int offset, int length) { + StringBuffer buf = new StringBuffer(); + for (int i = 0; i < length; i++) { + buf.append("(byte)0x"); + appendHexChar(buf, bytes[offset + i]); + buf.append(", "); + } + return buf.toString(); + } + + public static String toStringCondensed(byte[] bytes) { + StringBuffer buf = new StringBuffer(); + for (int i=0;i> 1]; + + for (int i = 0, j = 0; j < len; i++) { + int f = Character.digit(data[j], 16) << 4; + j++; + f = f | Character.digit(data[j], 16); + j++; + out[i] = (byte) (f & 0xFF); + } + + return out; + } + + private static void appendHexChar(StringBuffer buf, int b) { + buf.append(HEX_DIGITS[(b >> 4) & 0xf]); + buf.append(HEX_DIGITS[b & 0xf]); + } + +} diff --git a/libaxolotl/src/main/java/org/whispersystems/libaxolotl/util/Pair.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/util/Pair.java new file mode 100644 index 000000000..0476d9326 --- /dev/null +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/util/Pair.java @@ -0,0 +1,51 @@ +/** + * Copyright (C) 2014 Open WhisperSystems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.whispersystems.libaxolotl.util; + +public class Pair { + private final T1 v1; + private final T2 v2; + + public Pair(T1 v1, T2 v2) { + this.v1 = v1; + this.v2 = v2; + } + + public T1 first(){ + return v1; + } + + public T2 second(){ + return v2; + } + + public boolean equals(Object o) { + return o instanceof Pair && + equal(((Pair) o).first(), first()) && + equal(((Pair) o).second(), second()); + } + + public int hashCode() { + return first().hashCode() ^ second().hashCode(); + } + + private boolean equal(Object first, Object second) { + if (first == null && second == null) return true; + if (first == null || second == null) return false; + return first.equals(second); + } +} diff --git a/library/build.gradle b/library/build.gradle index 61b3c590d..131cb7ed9 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -23,6 +23,8 @@ dependencies { compile 'com.madgag:sc-light-jdk15on:1.47.0.2' compile 'com.googlecode.libphonenumber:libphonenumber:6.1' compile 'org.whispersystems:gson:2.2.4' + + compile project(':libaxolotl') } android { @@ -45,6 +47,12 @@ android { } } +tasks.whenTaskAdded { task -> + if (task.name.equals("lint")) { + task.enabled = false + } +} + version '0.1' group 'org.whispersystems.textsecure' archivesBaseName = 'textsecure-library' diff --git a/library/src/org/whispersystems/textsecure/crypto/AttachmentCipher.java b/library/src/org/whispersystems/textsecure/crypto/AttachmentCipher.java index 04c3ada6b..9ad4f3e98 100644 --- a/library/src/org/whispersystems/textsecure/crypto/AttachmentCipher.java +++ b/library/src/org/whispersystems/textsecure/crypto/AttachmentCipher.java @@ -18,6 +18,8 @@ package org.whispersystems.textsecure.crypto; import android.util.Log; +import org.whispersystems.libaxolotl.InvalidMacException; +import org.whispersystems.libaxolotl.InvalidMessageException; import org.whispersystems.textsecure.util.Hex; import org.whispersystems.textsecure.util.Util; diff --git a/library/src/org/whispersystems/textsecure/crypto/AttachmentCipherInputStream.java b/library/src/org/whispersystems/textsecure/crypto/AttachmentCipherInputStream.java index 1be3eded0..c28554656 100644 --- a/library/src/org/whispersystems/textsecure/crypto/AttachmentCipherInputStream.java +++ b/library/src/org/whispersystems/textsecure/crypto/AttachmentCipherInputStream.java @@ -18,6 +18,8 @@ package org.whispersystems.textsecure.crypto; import android.util.Log; +import org.whispersystems.libaxolotl.InvalidMacException; +import org.whispersystems.libaxolotl.InvalidMessageException; import org.whispersystems.textsecure.util.Util; import java.io.File; diff --git a/library/src/org/whispersystems/textsecure/crypto/IdentityKey.java b/library/src/org/whispersystems/textsecure/crypto/IdentityKey.java deleted file mode 100644 index 875bd3bfb..000000000 --- a/library/src/org/whispersystems/textsecure/crypto/IdentityKey.java +++ /dev/null @@ -1,113 +0,0 @@ -/** - * Copyright (C) 2011 Whisper Systems - * Copyright (C) 2013 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.textsecure.crypto; - -import android.os.Parcel; -import android.os.Parcelable; - -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; -import org.whispersystems.textsecure.util.Hex; - -/** - * A class for representing an identity key. - * - * @author Moxie Marlinspike - */ - -public class IdentityKey implements Parcelable, SerializableKey { - - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public IdentityKey createFromParcel(Parcel in) { - try { - return new IdentityKey(in); - } catch (InvalidKeyException e) { - throw new AssertionError(e); - } - } - - public IdentityKey[] newArray(int size) { - return new IdentityKey[size]; - } - }; - - public static final int NIST_SIZE = 1 + ECPublicKey.KEY_SIZE; - - private ECPublicKey publicKey; - - public IdentityKey(ECPublicKey publicKey) { - this.publicKey = publicKey; - } - - public IdentityKey(Parcel in) throws InvalidKeyException { - int length = in.readInt(); - byte[] serialized = new byte[length]; - - in.readByteArray(serialized); - initializeFromSerialized(serialized, 0); - } - - public IdentityKey(byte[] bytes, int offset) throws InvalidKeyException { - initializeFromSerialized(bytes, offset); - } - - public ECPublicKey getPublicKey() { - return publicKey; - } - - private void initializeFromSerialized(byte[] bytes, int offset) throws InvalidKeyException { - if ((bytes[offset] & 0xff) == 1) { - this.publicKey = Curve.decodePoint(bytes, offset +1); - } else { - this.publicKey = Curve.decodePoint(bytes, offset); - } - } - - public byte[] serialize() { - return publicKey.serialize(); - } - - public String getFingerprint() { - return Hex.toString(publicKey.serialize()); - } - - @Override - public boolean equals(Object other) { - if (other == null) return false; - if (!(other instanceof IdentityKey)) return false; - - return publicKey.equals(((IdentityKey) other).getPublicKey()); - } - - @Override - public int hashCode() { - return publicKey.hashCode(); - } - - public int describeContents() { - // TODO Auto-generated method stub - return 0; - } - - public void writeToParcel(Parcel dest, int flags) { - byte[] serialized = this.serialize(); - dest.writeInt(serialized.length); - dest.writeByteArray(serialized); - } - -} diff --git a/library/src/org/whispersystems/textsecure/crypto/IdentityKeyParcelable.java b/library/src/org/whispersystems/textsecure/crypto/IdentityKeyParcelable.java new file mode 100644 index 000000000..c646609bc --- /dev/null +++ b/library/src/org/whispersystems/textsecure/crypto/IdentityKeyParcelable.java @@ -0,0 +1,69 @@ +/** + * 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.textsecure.crypto; + +import android.os.Parcel; +import android.os.Parcelable; + +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.libaxolotl.InvalidKeyException; + +public class IdentityKeyParcelable implements Parcelable { + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public IdentityKeyParcelable createFromParcel(Parcel in) { + try { + return new IdentityKeyParcelable(in); + } catch (InvalidKeyException e) { + throw new AssertionError(e); + } + } + + public IdentityKeyParcelable[] newArray(int size) { + return new IdentityKeyParcelable[size]; + } + }; + + private final IdentityKey identityKey; + + public IdentityKeyParcelable(IdentityKey identityKey) { + this.identityKey = identityKey; + } + + public IdentityKeyParcelable(Parcel in) throws InvalidKeyException { + int serializedLength = in.readInt(); + byte[] serialized = new byte[serializedLength]; + + in.readByteArray(serialized); + this.identityKey = new IdentityKey(serialized, 0); + } + + public IdentityKey get() { + return identityKey; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(identityKey.serialize().length); + dest.writeByteArray(identityKey.serialize()); + } +} diff --git a/library/src/org/whispersystems/textsecure/crypto/InvalidVersionException.java b/library/src/org/whispersystems/textsecure/crypto/InvalidVersionException.java deleted file mode 100644 index 6194b1c3c..000000000 --- a/library/src/org/whispersystems/textsecure/crypto/InvalidVersionException.java +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (C) 2011 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.textsecure.crypto; - -public class InvalidVersionException extends Exception { - - public InvalidVersionException() { - // TODO Auto-generated constructor stub - } - - public InvalidVersionException(String detailMessage) { - super(detailMessage); - // TODO Auto-generated constructor stub - } - - public InvalidVersionException(Throwable throwable) { - super(throwable); - // TODO Auto-generated constructor stub - } - - public InvalidVersionException(String detailMessage, Throwable throwable) { - super(detailMessage, throwable); - // TODO Auto-generated constructor stub - } - -} diff --git a/library/src/org/whispersystems/textsecure/crypto/MasterCipher.java b/library/src/org/whispersystems/textsecure/crypto/MasterCipher.java index 78b3918e5..80d682754 100644 --- a/library/src/org/whispersystems/textsecure/crypto/MasterCipher.java +++ b/library/src/org/whispersystems/textsecure/crypto/MasterCipher.java @@ -19,8 +19,9 @@ package org.whispersystems.textsecure.crypto; import android.util.Log; -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECPrivateKey; +import org.whispersystems.libaxolotl.InvalidMessageException; +import org.whispersystems.libaxolotl.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECPrivateKey; import org.whispersystems.textsecure.util.Base64; import org.whispersystems.textsecure.util.Hex; @@ -84,12 +85,12 @@ public class MasterCipher { } public ECPrivateKey decryptKey(byte[] key) - throws org.whispersystems.textsecure.crypto.InvalidKeyException + throws org.whispersystems.libaxolotl.InvalidKeyException { try { return Curve.decodePrivatePoint(decryptBytes(key)); } catch (InvalidMessageException ime) { - throw new org.whispersystems.textsecure.crypto.InvalidKeyException(ime); + throw new org.whispersystems.libaxolotl.InvalidKeyException(ime); } } diff --git a/library/src/org/whispersystems/textsecure/crypto/PreKeyUtil.java b/library/src/org/whispersystems/textsecure/crypto/PreKeyUtil.java index e137b97c0..7574d4db7 100644 --- a/library/src/org/whispersystems/textsecure/crypto/PreKeyUtil.java +++ b/library/src/org/whispersystems/textsecure/crypto/PreKeyUtil.java @@ -22,8 +22,8 @@ import android.util.Log; import com.google.thoughtcrimegson.Gson; -import org.whispersystems.textsecure.crypto.ecc.Curve25519; -import org.whispersystems.textsecure.crypto.ecc.ECKeyPair; +import org.whispersystems.libaxolotl.ecc.Curve25519; +import org.whispersystems.libaxolotl.ecc.ECKeyPair; import org.whispersystems.textsecure.storage.InvalidKeyIdException; import org.whispersystems.textsecure.storage.PreKeyRecord; import org.whispersystems.textsecure.util.Medium; diff --git a/library/src/org/whispersystems/textsecure/crypto/PublicKey.java b/library/src/org/whispersystems/textsecure/crypto/PublicKey.java index 293b18d32..2540877de 100644 --- a/library/src/org/whispersystems/textsecure/crypto/PublicKey.java +++ b/library/src/org/whispersystems/textsecure/crypto/PublicKey.java @@ -19,8 +19,9 @@ package org.whispersystems.textsecure.crypto; import android.util.Log; -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; import org.whispersystems.textsecure.util.Conversions; import org.whispersystems.textsecure.util.Hex; import org.whispersystems.textsecure.util.Util; diff --git a/library/src/org/whispersystems/textsecure/crypto/SessionCipherFactory.java b/library/src/org/whispersystems/textsecure/crypto/SessionCipherFactory.java new file mode 100644 index 000000000..e3a5dacad --- /dev/null +++ b/library/src/org/whispersystems/textsecure/crypto/SessionCipherFactory.java @@ -0,0 +1,39 @@ +/** + * Copyright (C) 2013 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.textsecure.crypto; + + +import android.content.Context; + +import org.whispersystems.libaxolotl.SessionCipher; +import org.whispersystems.textsecure.storage.RecipientDevice; +import org.whispersystems.textsecure.storage.SessionRecordV2; + +public class SessionCipherFactory { + + public static SessionCipher getInstance(Context context, + MasterSecret masterSecret, + RecipientDevice recipient) + { + if (SessionRecordV2.hasSession(context, masterSecret, recipient)) { + SessionRecordV2 record = new SessionRecordV2(context, masterSecret, recipient); + return new SessionCipher(record); + } else { + throw new AssertionError("Attempt to initialize cipher for non-existing session."); + } + } +} \ No newline at end of file diff --git a/library/src/org/whispersystems/textsecure/crypto/kdf/NKDF.java b/library/src/org/whispersystems/textsecure/crypto/kdf/NKDF.java deleted file mode 100644 index 1ae591374..000000000 --- a/library/src/org/whispersystems/textsecure/crypto/kdf/NKDF.java +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Copyright (C) 2013 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.textsecure.crypto.kdf; - -import android.util.Log; - -import org.whispersystems.textsecure.util.Conversions; - -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -import javax.crypto.spec.SecretKeySpec; - -public class NKDF { - - public static final int LEGACY_CIPHER_KEY_LENGTH = 16; - public static final int LEGACY_MAC_KEY_LENGTH = 20; - - public DerivedSecrets deriveSecrets(byte[] sharedSecret, boolean isLowEnd) - { - SecretKeySpec cipherKey = deriveCipherSecret(isLowEnd, sharedSecret); - SecretKeySpec macKey = deriveMacSecret(cipherKey); - - return new DerivedSecrets(cipherKey, macKey); - } - - private SecretKeySpec deriveCipherSecret(boolean isLowEnd, byte[] sharedSecret) { - byte[] derivedBytes = deriveBytes(sharedSecret, LEGACY_CIPHER_KEY_LENGTH * 2); - byte[] cipherSecret = new byte[LEGACY_CIPHER_KEY_LENGTH]; - - if (isLowEnd) { - System.arraycopy(derivedBytes, LEGACY_CIPHER_KEY_LENGTH, cipherSecret, 0, LEGACY_CIPHER_KEY_LENGTH); - } else { - System.arraycopy(derivedBytes, 0, cipherSecret, 0, LEGACY_CIPHER_KEY_LENGTH); - } - - return new SecretKeySpec(cipherSecret, "AES"); - } - - private SecretKeySpec deriveMacSecret(SecretKeySpec key) { - try { - MessageDigest md = MessageDigest.getInstance("SHA-1"); - byte[] secret = md.digest(key.getEncoded()); - - return new SecretKeySpec(secret, "HmacSHA1"); - } catch (NoSuchAlgorithmException e) { - throw new IllegalArgumentException("SHA-1 Not Supported!",e); - } - } - - private byte[] deriveBytes(byte[] seed, int bytesNeeded) { - MessageDigest md; - - try { - md = MessageDigest.getInstance("SHA-256"); - } catch (NoSuchAlgorithmException e) { - Log.w("NKDF", e); - throw new IllegalArgumentException("SHA-256 Not Supported!"); - } - - int rounds = bytesNeeded / md.getDigestLength(); - - for (int i=1;i<=rounds;i++) { - byte[] roundBytes = Conversions.intToByteArray(i); - md.update(roundBytes); - md.update(seed); - } - - return md.digest(); - } -} diff --git a/library/src/org/whispersystems/textsecure/crypto/protocol/CiphertextMessage.java b/library/src/org/whispersystems/textsecure/crypto/protocol/CiphertextMessage.java deleted file mode 100644 index 7bed17ad0..000000000 --- a/library/src/org/whispersystems/textsecure/crypto/protocol/CiphertextMessage.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.whispersystems.textsecure.crypto.protocol; - -public interface CiphertextMessage { - - public static final int UNSUPPORTED_VERSION = 1; - public static final int CURRENT_VERSION = 2; - - public static final int WHISPER_TYPE = 2; - public static final int PREKEY_TYPE = 3; - - // This should be the worst case (worse than V2). So not always accurate, but good enough for padding. - public static final int ENCRYPTED_MESSAGE_OVERHEAD = 53; - - public byte[] serialize(); - public int getType(); - -} \ No newline at end of file diff --git a/library/src/org/whispersystems/textsecure/crypto/ratchet/MessageKeys.java b/library/src/org/whispersystems/textsecure/crypto/ratchet/MessageKeys.java deleted file mode 100644 index 1ab6208de..000000000 --- a/library/src/org/whispersystems/textsecure/crypto/ratchet/MessageKeys.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.whispersystems.textsecure.crypto.ratchet; - -import javax.crypto.spec.SecretKeySpec; - -public class MessageKeys { - - private final SecretKeySpec cipherKey; - private final SecretKeySpec macKey; - private final int counter; - - public MessageKeys(SecretKeySpec cipherKey, SecretKeySpec macKey, int counter) { - this.cipherKey = cipherKey; - this.macKey = macKey; - this.counter = counter; - } - - public SecretKeySpec getCipherKey() { - return cipherKey; - } - - public SecretKeySpec getMacKey() { - return macKey; - } - - public int getCounter() { - return counter; - } -} diff --git a/library/src/org/whispersystems/textsecure/crypto/ratchet/RootKey.java b/library/src/org/whispersystems/textsecure/crypto/ratchet/RootKey.java deleted file mode 100644 index 5ba19bc13..000000000 --- a/library/src/org/whispersystems/textsecure/crypto/ratchet/RootKey.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.whispersystems.textsecure.crypto.ratchet; - -import android.util.Pair; - -import org.whispersystems.textsecure.crypto.InvalidKeyException; -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECKeyPair; -import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; -import org.whispersystems.textsecure.crypto.kdf.DerivedSecrets; -import org.whispersystems.textsecure.crypto.kdf.HKDF; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; - -public class RootKey { - - private final byte[] key; - - public RootKey(byte[] key) { - this.key = key; - } - - public byte[] getKeyBytes() { - return key; - } - - public Pair createChain(ECPublicKey theirEphemeral, ECKeyPair ourEphemeral) - throws InvalidKeyException - { - HKDF kdf = new HKDF(); - byte[] sharedSecret = Curve.calculateAgreement(theirEphemeral, ourEphemeral.getPrivateKey()); - DerivedSecrets keys = kdf.deriveSecrets(sharedSecret, key, "WhisperRatchet".getBytes()); - RootKey newRootKey = new RootKey(keys.getCipherKey().getEncoded()); - ChainKey newChainKey = new ChainKey(keys.getMacKey().getEncoded(), 0); - - return new Pair(newRootKey, newChainKey); - } -} diff --git a/library/src/org/whispersystems/textsecure/push/IncomingEncryptedPushMessage.java b/library/src/org/whispersystems/textsecure/push/IncomingEncryptedPushMessage.java index 45d173a64..3e34128ca 100644 --- a/library/src/org/whispersystems/textsecure/push/IncomingEncryptedPushMessage.java +++ b/library/src/org/whispersystems/textsecure/push/IncomingEncryptedPushMessage.java @@ -2,7 +2,7 @@ package org.whispersystems.textsecure.push; import android.util.Log; -import org.whispersystems.textsecure.crypto.InvalidVersionException; +import org.whispersystems.libaxolotl.InvalidVersionException; import org.whispersystems.textsecure.util.Base64; import org.whispersystems.textsecure.push.PushMessageProtos.IncomingPushMessageSignal; import org.whispersystems.textsecure.util.Hex; diff --git a/library/src/org/whispersystems/textsecure/push/PreKeyEntity.java b/library/src/org/whispersystems/textsecure/push/PreKeyEntity.java index fd0559509..1955dc322 100644 --- a/library/src/org/whispersystems/textsecure/push/PreKeyEntity.java +++ b/library/src/org/whispersystems/textsecure/push/PreKeyEntity.java @@ -10,10 +10,10 @@ import com.google.thoughtcrimegson.JsonSerializationContext; import com.google.thoughtcrimegson.JsonSerializer; import com.google.thoughtcrimegson.annotations.Expose; -import org.whispersystems.textsecure.crypto.IdentityKey; -import org.whispersystems.textsecure.crypto.InvalidKeyException; -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; import org.whispersystems.textsecure.util.Base64; import java.io.IOException; diff --git a/library/src/org/whispersystems/textsecure/push/PushServiceSocket.java b/library/src/org/whispersystems/textsecure/push/PushServiceSocket.java index f9c88e763..9304d8d1f 100644 --- a/library/src/org/whispersystems/textsecure/push/PushServiceSocket.java +++ b/library/src/org/whispersystems/textsecure/push/PushServiceSocket.java @@ -23,7 +23,7 @@ import com.google.thoughtcrimegson.Gson; import com.google.thoughtcrimegson.JsonParseException; import org.apache.http.conn.ssl.StrictHostnameVerifier; -import org.whispersystems.textsecure.crypto.IdentityKey; +import org.whispersystems.libaxolotl.IdentityKey; import org.whispersystems.textsecure.storage.PreKeyRecord; import org.whispersystems.textsecure.util.Base64; import org.whispersystems.textsecure.util.BlacklistingTrustManager; diff --git a/library/src/org/whispersystems/textsecure/storage/PreKeyRecord.java b/library/src/org/whispersystems/textsecure/storage/PreKeyRecord.java index 2018e2d92..edf52ce16 100644 --- a/library/src/org/whispersystems/textsecure/storage/PreKeyRecord.java +++ b/library/src/org/whispersystems/textsecure/storage/PreKeyRecord.java @@ -5,14 +5,14 @@ import android.util.Log; import com.google.protobuf.ByteString; -import org.whispersystems.textsecure.crypto.InvalidKeyException; -import org.whispersystems.textsecure.crypto.InvalidMessageException; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.InvalidMessageException; +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.textsecure.crypto.MasterCipher; import org.whispersystems.textsecure.crypto.MasterSecret; -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECKeyPair; -import org.whispersystems.textsecure.crypto.ecc.ECPrivateKey; -import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; import java.io.FileInputStream; import java.io.FileNotFoundException; diff --git a/library/src/org/whispersystems/textsecure/storage/Record.java b/library/src/org/whispersystems/textsecure/storage/Record.java index 35f941b71..88f9439bb 100644 --- a/library/src/org/whispersystems/textsecure/storage/Record.java +++ b/library/src/org/whispersystems/textsecure/storage/Record.java @@ -30,7 +30,7 @@ import java.nio.channels.FileChannel; public abstract class Record { - protected static final String SESSIONS_DIRECTORY = "sessions"; + public static final String SESSIONS_DIRECTORY = "sessions"; protected static final String SESSIONS_DIRECTORY_V2 = "sessions-v2"; public static final String PREKEY_DIRECTORY = "prekeys"; @@ -48,7 +48,7 @@ public abstract class Record { delete(this.context, this.directory, this.address); } - protected static void delete(Context context, String directory, String address) { + public static void delete(Context context, String directory, String address) { getAddressFile(context, directory, address).delete(); } diff --git a/library/src/org/whispersystems/textsecure/storage/Session.java b/library/src/org/whispersystems/textsecure/storage/Session.java index 5bf5bb261..c47015484 100644 --- a/library/src/org/whispersystems/textsecure/storage/Session.java +++ b/library/src/org/whispersystems/textsecure/storage/Session.java @@ -3,8 +3,11 @@ package org.whispersystems.textsecure.storage; import android.content.Context; import android.util.Log; -import org.whispersystems.textsecure.crypto.IdentityKey; +import org.whispersystems.libaxolotl.IdentityKey; import org.whispersystems.textsecure.crypto.MasterSecret; +import org.whispersystems.textsecure.storage.legacy.LocalKeyRecord; +import org.whispersystems.textsecure.storage.legacy.RemoteKeyRecord; +import org.whispersystems.textsecure.storage.legacy.SessionRecordV1; /** * Helper class for generating key pairs and calculating ECDH agreements. diff --git a/library/src/org/whispersystems/textsecure/storage/SessionKey.java b/library/src/org/whispersystems/textsecure/storage/SessionKey.java deleted file mode 100644 index 05b24e7db..000000000 --- a/library/src/org/whispersystems/textsecure/storage/SessionKey.java +++ /dev/null @@ -1,115 +0,0 @@ -/** - * Copyright (C) 2011 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.textsecure.storage; - -import org.whispersystems.textsecure.crypto.InvalidMessageException; -import org.whispersystems.textsecure.crypto.MasterCipher; -import org.whispersystems.textsecure.crypto.MasterSecret; -import org.whispersystems.textsecure.crypto.kdf.NKDF; -import org.whispersystems.textsecure.util.Conversions; -import org.whispersystems.textsecure.util.Util; - -import javax.crypto.spec.SecretKeySpec; - -/** - * Represents the currently negotiated session key for a given - * local key id and remote key id. This is stored encrypted on - * disk. - * - * @author Moxie Marlinspike - */ - -public class SessionKey { - - private int mode; - private int localKeyId; - private int remoteKeyId; - private SecretKeySpec cipherKey; - private SecretKeySpec macKey; - private MasterCipher masterCipher; - - public SessionKey(int mode, int localKeyId, int remoteKeyId, - SecretKeySpec cipherKey, SecretKeySpec macKey, - MasterSecret masterSecret) - { - this.mode = mode; - this.localKeyId = localKeyId; - this.remoteKeyId = remoteKeyId; - this.cipherKey = cipherKey; - this.macKey = macKey; - this.masterCipher = new MasterCipher(masterSecret); - } - - public SessionKey(byte[] bytes, MasterSecret masterSecret) throws InvalidMessageException { - this.masterCipher = new MasterCipher(masterSecret); - deserialize(bytes); - } - - public byte[] serialize() { - byte[] localKeyIdBytes = Conversions.mediumToByteArray(localKeyId); - byte[] remoteKeyIdBytes = Conversions.mediumToByteArray(remoteKeyId); - byte[] cipherKeyBytes = cipherKey.getEncoded(); - byte[] macKeyBytes = macKey.getEncoded(); - byte[] modeBytes = {(byte)mode}; - byte[] combined = Util.combine(localKeyIdBytes, remoteKeyIdBytes, - cipherKeyBytes, macKeyBytes, modeBytes); - - return masterCipher.encryptBytes(combined); - } - - private void deserialize(byte[] bytes) throws InvalidMessageException { - byte[] decrypted = masterCipher.decryptBytes(bytes); - - this.localKeyId = Conversions.byteArrayToMedium(decrypted, 0); - this.remoteKeyId = Conversions.byteArrayToMedium(decrypted, 3); - - byte[] keyBytes = new byte[NKDF.LEGACY_CIPHER_KEY_LENGTH]; - System.arraycopy(decrypted, 6, keyBytes, 0, keyBytes.length); - - byte[] macBytes = new byte[NKDF.LEGACY_MAC_KEY_LENGTH]; - System.arraycopy(decrypted, 6 + keyBytes.length, macBytes, 0, macBytes.length); - - if (decrypted.length < 6 + NKDF.LEGACY_CIPHER_KEY_LENGTH + NKDF.LEGACY_MAC_KEY_LENGTH + 1) { - throw new InvalidMessageException("No mode included"); - } - - this.mode = decrypted[6 + keyBytes.length + macBytes.length]; - - this.cipherKey = new SecretKeySpec(keyBytes, "AES"); - this.macKey = new SecretKeySpec(macBytes, "HmacSHA1"); - } - - public int getLocalKeyId() { - return this.localKeyId; - } - - public int getRemoteKeyId() { - return this.remoteKeyId; - } - - public SecretKeySpec getCipherKey() { - return this.cipherKey; - } - - public SecretKeySpec getMacKey() { - return this.macKey; - } - - public int getMode() { - return mode; - } -} diff --git a/library/src/org/whispersystems/textsecure/storage/SessionRecordV2.java b/library/src/org/whispersystems/textsecure/storage/SessionRecordV2.java index 46fec98a6..05d141833 100644 --- a/library/src/org/whispersystems/textsecure/storage/SessionRecordV2.java +++ b/library/src/org/whispersystems/textsecure/storage/SessionRecordV2.java @@ -19,7 +19,9 @@ package org.whispersystems.textsecure.storage; import android.content.Context; import android.util.Log; -import org.whispersystems.textsecure.crypto.InvalidMessageException; +import org.whispersystems.libaxolotl.InvalidMessageException; +import org.whispersystems.libaxolotl.SessionState; +import org.whispersystems.libaxolotl.SessionStore; import org.whispersystems.textsecure.crypto.MasterCipher; import org.whispersystems.textsecure.crypto.MasterSecret; @@ -41,7 +43,7 @@ import static org.whispersystems.textsecure.storage.StorageProtos.SessionStructu * @author Moxie Marlinspike */ -public class SessionRecordV2 extends Record { +public class SessionRecordV2 extends Record implements SessionStore { private static final Object FILE_LOCK = new Object(); @@ -51,8 +53,8 @@ public class SessionRecordV2 extends Record { private final MasterSecret masterSecret; - private SessionState sessionState = new SessionState(SessionStructure.newBuilder().build()); - private List previousStates = new LinkedList(); + private TextSecureSessionState sessionState = new TextSecureSessionState(SessionStructure.newBuilder().build()); + private List previousStates = new LinkedList(); public SessionRecordV2(Context context, MasterSecret masterSecret, RecipientDevice peer) { this(context, masterSecret, peer.getRecipientId(), peer.getDeviceId()); @@ -68,12 +70,12 @@ public class SessionRecordV2 extends Record { return recipientId + (deviceId == RecipientDevice.DEFAULT_DEVICE_ID ? "" : "." + deviceId); } - public SessionState getSessionState() { + public TextSecureSessionState getSessionState() { return sessionState; } - public List getPreviousSessions() { + public List getPreviousSessionStates() { return previousStates; } @@ -139,13 +141,13 @@ public class SessionRecordV2 extends Record { } public void clear() { - this.sessionState = new SessionState(SessionStructure.newBuilder().build()); + this.sessionState = new TextSecureSessionState(SessionStructure.newBuilder().build()); this.previousStates = new LinkedList(); } public void archiveCurrentState() { this.previousStates.add(sessionState); - this.sessionState = new SessionState(SessionStructure.newBuilder().build()); + this.sessionState = new TextSecureSessionState(SessionStructure.newBuilder().build()); } public void save() { @@ -154,7 +156,7 @@ public class SessionRecordV2 extends Record { List previousStructures = new LinkedList(); for (SessionState previousState : previousStates) { - previousStructures.add(previousState.getStructure()); + previousStructures.add(((TextSecureSessionState)previousState).getStructure()); } RecordStructure record = RecordStructure.newBuilder() @@ -194,16 +196,16 @@ public class SessionRecordV2 extends Record { if (versionMarker == SINGLE_STATE_VERSION) { byte[] plaintextBytes = cipher.decryptBytes(encryptedBlob); SessionStructure sessionStructure = SessionStructure.parseFrom(plaintextBytes); - this.sessionState = new SessionState(sessionStructure); + this.sessionState = new TextSecureSessionState(sessionStructure); } else if (versionMarker == ARCHIVE_STATES_VERSION) { byte[] plaintextBytes = cipher.decryptBytes(encryptedBlob); RecordStructure recordStructure = RecordStructure.parseFrom(plaintextBytes); - this.sessionState = new SessionState(recordStructure.getCurrentSession()); + this.sessionState = new TextSecureSessionState(recordStructure.getCurrentSession()); this.previousStates = new LinkedList(); for (SessionStructure sessionStructure : recordStructure.getPreviousSessionsList()) { - this.previousStates.add(new SessionState(sessionStructure)); + this.previousStates.add(new TextSecureSessionState(sessionStructure)); } } else { throw new AssertionError("Unknown version: " + versionMarker); @@ -217,8 +219,9 @@ public class SessionRecordV2 extends Record { } catch (IOException ioe) { Log.w("SessionRecordV2", ioe); // XXX - } catch (InvalidMessageException e) { - Log.w("SessionRecordV2", e); + } catch (InvalidMessageException ime) { + Log.w("SessionRecordV2", ime); + // XXX } } } diff --git a/library/src/org/whispersystems/textsecure/storage/SessionState.java b/library/src/org/whispersystems/textsecure/storage/TextSecureSessionState.java similarity index 90% rename from library/src/org/whispersystems/textsecure/storage/SessionState.java rename to library/src/org/whispersystems/textsecure/storage/TextSecureSessionState.java index 9ddc009d6..f5a317bba 100644 --- a/library/src/org/whispersystems/textsecure/storage/SessionState.java +++ b/library/src/org/whispersystems/textsecure/storage/TextSecureSessionState.java @@ -1,20 +1,37 @@ +/** + * 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.textsecure.storage; import android.util.Log; -import android.util.Pair; import com.google.protobuf.ByteString; -import org.whispersystems.textsecure.crypto.IdentityKey; -import org.whispersystems.textsecure.crypto.IdentityKeyPair; -import org.whispersystems.textsecure.crypto.InvalidKeyException; -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECKeyPair; -import org.whispersystems.textsecure.crypto.ecc.ECPrivateKey; -import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; -import org.whispersystems.textsecure.crypto.ratchet.ChainKey; -import org.whispersystems.textsecure.crypto.ratchet.MessageKeys; -import org.whispersystems.textsecure.crypto.ratchet.RootKey; +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.libaxolotl.IdentityKeyPair; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.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.ChainKey; +import org.whispersystems.libaxolotl.ratchet.MessageKeys; +import org.whispersystems.libaxolotl.ratchet.RootKey; +import org.whispersystems.libaxolotl.util.Pair; import org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.Chain; import org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingKeyExchange; import org.whispersystems.textsecure.storage.StorageProtos.SessionStructure.PendingPreKey; @@ -27,11 +44,11 @@ import javax.crypto.spec.SecretKeySpec; import static org.whispersystems.textsecure.storage.StorageProtos.SessionStructure; -public class SessionState { +public class TextSecureSessionState implements SessionState { private SessionStructure sessionStructure; - public SessionState(SessionStructure sessionStructure) { + public TextSecureSessionState(SessionStructure sessionStructure) { this.sessionStructure = sessionStructure; } @@ -160,7 +177,7 @@ public class SessionState { public ChainKey getReceiverChainKey(ECPublicKey senderEphemeral) { Pair receiverChainAndIndex = getReceiverChain(senderEphemeral); - Chain receiverChain = receiverChainAndIndex.first; + Chain receiverChain = receiverChainAndIndex.first(); if (receiverChain == null) { return null; @@ -225,7 +242,7 @@ public class SessionState { public boolean hasMessageKeys(ECPublicKey senderEphemeral, int counter) { Pair chainAndIndex = getReceiverChain(senderEphemeral); - Chain chain = chainAndIndex.first; + Chain chain = chainAndIndex.first(); if (chain == null) { return false; @@ -244,7 +261,7 @@ public class SessionState { public MessageKeys removeMessageKeys(ECPublicKey senderEphemeral, int counter) { Pair chainAndIndex = getReceiverChain(senderEphemeral); - Chain chain = chainAndIndex.first; + Chain chain = chainAndIndex.first(); if (chain == null) { return null; @@ -272,7 +289,7 @@ public class SessionState { .build(); this.sessionStructure = this.sessionStructure.toBuilder() - .setReceiverChains(chainAndIndex.second, updatedChain) + .setReceiverChains(chainAndIndex.second(), updatedChain) .build(); return result; @@ -280,7 +297,7 @@ public class SessionState { public void setMessageKeys(ECPublicKey senderEphemeral, MessageKeys messageKeys) { Pair chainAndIndex = getReceiverChain(senderEphemeral); - Chain chain = chainAndIndex.first; + Chain chain = chainAndIndex.first(); Chain.MessageKey messageKeyStructure = Chain.MessageKey.newBuilder() .setCipherKey(ByteString.copyFrom(messageKeys.getCipherKey().getEncoded())) .setMacKey(ByteString.copyFrom(messageKeys.getMacKey().getEncoded())) @@ -292,13 +309,13 @@ public class SessionState { .build(); this.sessionStructure = this.sessionStructure.toBuilder() - .setReceiverChains(chainAndIndex.second, updatedChain) + .setReceiverChains(chainAndIndex.second(), updatedChain) .build(); } public void setReceiverChainKey(ECPublicKey senderEphemeral, ChainKey chainKey) { Pair chainAndIndex = getReceiverChain(senderEphemeral); - Chain chain = chainAndIndex.first; + Chain chain = chainAndIndex.first(); Chain.ChainKey chainKeyStructure = Chain.ChainKey.newBuilder() .setKey(ByteString.copyFrom(chainKey.getKey())) @@ -308,7 +325,7 @@ public class SessionState { Chain updatedChain = chain.toBuilder().setChainKey(chainKeyStructure).build(); this.sessionStructure = this.sessionStructure.toBuilder() - .setReceiverChains(chainAndIndex.second, updatedChain) + .setReceiverChains(chainAndIndex.second(), updatedChain) .build(); } diff --git a/library/src/org/whispersystems/textsecure/storage/LocalKeyRecord.java b/library/src/org/whispersystems/textsecure/storage/legacy/LocalKeyRecord.java similarity index 86% rename from library/src/org/whispersystems/textsecure/storage/LocalKeyRecord.java rename to library/src/org/whispersystems/textsecure/storage/legacy/LocalKeyRecord.java index a3d4714ba..cea52de04 100644 --- a/library/src/org/whispersystems/textsecure/storage/LocalKeyRecord.java +++ b/library/src/org/whispersystems/textsecure/storage/legacy/LocalKeyRecord.java @@ -15,10 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package org.whispersystems.textsecure.storage; +package org.whispersystems.textsecure.storage.legacy; import android.content.Context; +import org.whispersystems.textsecure.storage.CanonicalRecipient; +import org.whispersystems.textsecure.storage.Record; + public class LocalKeyRecord { public static void delete(Context context, CanonicalRecipient recipient) { diff --git a/library/src/org/whispersystems/textsecure/storage/RemoteKeyRecord.java b/library/src/org/whispersystems/textsecure/storage/legacy/RemoteKeyRecord.java similarity index 73% rename from library/src/org/whispersystems/textsecure/storage/RemoteKeyRecord.java rename to library/src/org/whispersystems/textsecure/storage/legacy/RemoteKeyRecord.java index 1cc5ff5a5..89563d392 100644 --- a/library/src/org/whispersystems/textsecure/storage/RemoteKeyRecord.java +++ b/library/src/org/whispersystems/textsecure/storage/legacy/RemoteKeyRecord.java @@ -14,21 +14,12 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package org.whispersystems.textsecure.storage; +package org.whispersystems.textsecure.storage.legacy; import android.content.Context; -import android.util.Log; -import org.whispersystems.textsecure.crypto.InvalidKeyException; -import org.whispersystems.textsecure.crypto.PublicKey; -import org.whispersystems.textsecure.util.Hex; -import org.whispersystems.textsecure.util.Medium; - -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.nio.channels.FileChannel; +import org.whispersystems.textsecure.storage.CanonicalRecipient; +import org.whispersystems.textsecure.storage.Record; /** * Represents the current and last public key belonging to the "remote" diff --git a/library/src/org/whispersystems/textsecure/storage/SessionRecordV1.java b/library/src/org/whispersystems/textsecure/storage/legacy/SessionRecordV1.java similarity index 65% rename from library/src/org/whispersystems/textsecure/storage/SessionRecordV1.java rename to library/src/org/whispersystems/textsecure/storage/legacy/SessionRecordV1.java index 7edca3e7f..c85c9c1ee 100644 --- a/library/src/org/whispersystems/textsecure/storage/SessionRecordV1.java +++ b/library/src/org/whispersystems/textsecure/storage/legacy/SessionRecordV1.java @@ -1,7 +1,10 @@ -package org.whispersystems.textsecure.storage; +package org.whispersystems.textsecure.storage.legacy; import android.content.Context; +import org.whispersystems.textsecure.storage.CanonicalRecipient; +import org.whispersystems.textsecure.storage.Record; + /** * A disk record representing a current session. * diff --git a/settings.gradle b/settings.gradle index d8f14a134..7caf8cfc8 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':library' +include ':library', ':libaxolotl' diff --git a/src/org/thoughtcrime/securesms/ConversationActivity.java b/src/org/thoughtcrime/securesms/ConversationActivity.java index d73f4d43d..9d8541ee5 100644 --- a/src/org/thoughtcrime/securesms/ConversationActivity.java +++ b/src/org/thoughtcrime/securesms/ConversationActivity.java @@ -102,7 +102,7 @@ import org.thoughtcrime.securesms.util.EncryptedCharacterCalculator; import org.thoughtcrime.securesms.util.GroupUtil; import org.thoughtcrime.securesms.util.MemoryCleaner; import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.whispersystems.textsecure.crypto.InvalidMessageException; +import org.whispersystems.libaxolotl.InvalidMessageException; import org.whispersystems.textsecure.crypto.MasterCipher; import org.whispersystems.textsecure.crypto.MasterSecret; import org.whispersystems.textsecure.storage.RecipientDevice; diff --git a/src/org/thoughtcrime/securesms/KeyScanningActivity.java b/src/org/thoughtcrime/securesms/KeyScanningActivity.java index 020a62f29..fe29b0579 100644 --- a/src/org/thoughtcrime/securesms/KeyScanningActivity.java +++ b/src/org/thoughtcrime/securesms/KeyScanningActivity.java @@ -20,7 +20,7 @@ import android.content.Intent; import android.os.Bundle; import android.widget.Toast; -import org.whispersystems.textsecure.crypto.SerializableKey; +import org.whispersystems.libaxolotl.IdentityKey; import org.whispersystems.textsecure.util.Base64; import org.thoughtcrime.securesms.util.Dialogs; import org.thoughtcrime.securesms.util.DynamicTheme; @@ -112,8 +112,8 @@ public abstract class KeyScanningActivity extends PassphraseRequiredSherlockActi protected abstract String getNotVerifiedTitle(); protected abstract String getNotVerifiedMessage(); - protected abstract SerializableKey getIdentityKeyToCompare(); - protected abstract SerializableKey getIdentityKeyToDisplay(); + protected abstract IdentityKey getIdentityKeyToCompare(); + protected abstract IdentityKey getIdentityKeyToDisplay(); protected abstract String getVerifiedTitle(); protected abstract String getVerifiedMessage(); diff --git a/src/org/thoughtcrime/securesms/ReceiveKeyActivity.java b/src/org/thoughtcrime/securesms/ReceiveKeyActivity.java index d53e988c2..ce6b07ba0 100644 --- a/src/org/thoughtcrime/securesms/ReceiveKeyActivity.java +++ b/src/org/thoughtcrime/securesms/ReceiveKeyActivity.java @@ -34,20 +34,21 @@ import org.thoughtcrime.securesms.crypto.DecryptingQueue; import org.thoughtcrime.securesms.crypto.KeyExchangeProcessor; import org.thoughtcrime.securesms.crypto.KeyExchangeProcessorV2; import org.thoughtcrime.securesms.crypto.protocol.KeyExchangeMessage; -import org.whispersystems.textsecure.crypto.LegacyMessageException; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.service.SendReceiveService; import org.thoughtcrime.securesms.sms.SmsTransportDetails; import org.thoughtcrime.securesms.util.MemoryCleaner; import org.thoughtcrime.securesms.util.Util; -import org.whispersystems.textsecure.crypto.IdentityKey; -import org.whispersystems.textsecure.crypto.InvalidKeyException; -import org.whispersystems.textsecure.crypto.InvalidMessageException; -import org.whispersystems.textsecure.crypto.InvalidVersionException; +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.InvalidMessageException; +import org.whispersystems.libaxolotl.InvalidVersionException; +import org.whispersystems.libaxolotl.LegacyMessageException; +import org.whispersystems.libaxolotl.protocol.CiphertextMessage; +import org.whispersystems.libaxolotl.protocol.PreKeyWhisperMessage; +import org.whispersystems.textsecure.crypto.IdentityKeyParcelable; import org.whispersystems.textsecure.crypto.MasterSecret; -import org.whispersystems.textsecure.crypto.protocol.CiphertextMessage; -import org.whispersystems.textsecure.crypto.protocol.PreKeyWhisperMessage; import org.whispersystems.textsecure.push.IncomingPushMessage; import org.whispersystems.textsecure.storage.InvalidKeyIdException; import org.whispersystems.textsecure.storage.RecipientDevice; @@ -136,7 +137,7 @@ public class ReceiveKeyActivity extends Activity { Intent intent = new Intent(ReceiveKeyActivity.this, VerifyIdentityActivity.class); intent.putExtra("recipient", recipient); intent.putExtra("master_secret", masterSecret); - intent.putExtra("remote_identity", remoteIdentity); + intent.putExtra("remote_identity", new IdentityKeyParcelable(remoteIdentity)); startActivity(intent); } }, getString(R.string.ReceiveKeyActivity_the_signature_on_this_key_exchange_is_different).length() +1, diff --git a/src/org/thoughtcrime/securesms/VerifyIdentityActivity.java b/src/org/thoughtcrime/securesms/VerifyIdentityActivity.java index ef89115d9..66eaa5db3 100644 --- a/src/org/thoughtcrime/securesms/VerifyIdentityActivity.java +++ b/src/org/thoughtcrime/securesms/VerifyIdentityActivity.java @@ -26,7 +26,8 @@ import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.DynamicLanguage; import org.thoughtcrime.securesms.util.DynamicTheme; import org.thoughtcrime.securesms.util.MemoryCleaner; -import org.whispersystems.textsecure.crypto.IdentityKey; +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.textsecure.crypto.IdentityKeyParcelable; import org.whispersystems.textsecure.crypto.MasterSecret; import org.whispersystems.textsecure.storage.Session; @@ -83,7 +84,12 @@ public class VerifyIdentityActivity extends KeyScanningActivity { } private void initializeRemoteIdentityKey() { - IdentityKey identityKey = getIntent().getParcelableExtra("remote_identity"); + IdentityKeyParcelable identityKeyParcelable = getIntent().getParcelableExtra("remote_identity"); + IdentityKey identityKey = null; + + if (identityKeyParcelable != null) { + identityKey = identityKeyParcelable.get(); + } if (identityKey == null) { identityKey = Session.getRemoteIdentityKey(this, masterSecret, recipient); diff --git a/src/org/thoughtcrime/securesms/ViewIdentityActivity.java b/src/org/thoughtcrime/securesms/ViewIdentityActivity.java index 4db357f14..a919f1190 100644 --- a/src/org/thoughtcrime/securesms/ViewIdentityActivity.java +++ b/src/org/thoughtcrime/securesms/ViewIdentityActivity.java @@ -19,7 +19,8 @@ package org.thoughtcrime.securesms; import android.os.Bundle; import android.widget.TextView; -import org.whispersystems.textsecure.crypto.IdentityKey; +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.textsecure.crypto.IdentityKeyParcelable; /** * Activity for displaying an identity key. @@ -28,6 +29,9 @@ import org.whispersystems.textsecure.crypto.IdentityKey; */ public class ViewIdentityActivity extends KeyScanningActivity { + public static final String IDENTITY_KEY = "identity_key"; + public static final String TITLE = "title"; + private TextView identityFingerprint; private IdentityKey identityKey; @@ -54,12 +58,18 @@ public class ViewIdentityActivity extends KeyScanningActivity { } private void initializeResources() { - this.identityKey = (IdentityKey)getIntent().getParcelableExtra("identity_key"); + IdentityKeyParcelable identityKeyParcelable = getIntent().getParcelableExtra(IDENTITY_KEY); + + if (identityKeyParcelable == null) { + throw new AssertionError("No identity key!"); + } + + this.identityKey = identityKeyParcelable.get(); this.identityFingerprint = (TextView)findViewById(R.id.identity_fingerprint); - String title = getIntent().getStringExtra("title"); + String title = getIntent().getStringExtra(TITLE); if (title != null) { - getSupportActionBar().setTitle(getIntent().getStringExtra("title")); + getSupportActionBar().setTitle(getIntent().getStringExtra(TITLE)); } } diff --git a/src/org/thoughtcrime/securesms/ViewLocalIdentityActivity.java b/src/org/thoughtcrime/securesms/ViewLocalIdentityActivity.java index 4a0cf56e4..87a39bc7f 100644 --- a/src/org/thoughtcrime/securesms/ViewLocalIdentityActivity.java +++ b/src/org/thoughtcrime/securesms/ViewLocalIdentityActivity.java @@ -17,20 +17,14 @@ */ package org.thoughtcrime.securesms; -import android.app.AlertDialog; -import android.app.ProgressDialog; -import android.content.DialogInterface; -import android.os.AsyncTask; import android.os.Bundle; -import android.widget.Toast; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuInflater; import com.actionbarsherlock.view.MenuItem; import org.thoughtcrime.securesms.crypto.IdentityKeyUtil; -import org.thoughtcrime.securesms.util.Dialogs; -import org.whispersystems.textsecure.crypto.MasterSecret; +import org.whispersystems.textsecure.crypto.IdentityKeyParcelable; /** * Activity that displays the local identity key and offers the option to regenerate it. @@ -39,13 +33,11 @@ import org.whispersystems.textsecure.crypto.MasterSecret; */ public class ViewLocalIdentityActivity extends ViewIdentityActivity { - private MasterSecret masterSecret; - public void onCreate(Bundle bundle) { - this.masterSecret = getIntent().getParcelableExtra("master_secret"); - - getIntent().putExtra("identity_key", IdentityKeyUtil.getIdentityKey(this)); - getIntent().putExtra("title", getString(R.string.ViewIdentityActivity_my_identity_fingerprint)); + getIntent().putExtra(ViewIdentityActivity.IDENTITY_KEY, + new IdentityKeyParcelable(IdentityKeyUtil.getIdentityKey(this))); + getIntent().putExtra(ViewIdentityActivity.TITLE, + getString(R.string.ViewIdentityActivity_my_identity_fingerprint)); super.onCreate(bundle); } @@ -64,62 +56,9 @@ public class ViewLocalIdentityActivity extends ViewIdentityActivity { super.onOptionsItemSelected(item); switch (item.getItemId()) { -// case R.id.menu_regenerate_key: promptToRegenerateIdentityKey(); return true; - case android.R.id.home: finish(); return true; + case android.R.id.home:finish(); return true; } return false; } - - private void promptToRegenerateIdentityKey() { - AlertDialog.Builder dialog = new AlertDialog.Builder(this); - dialog.setIcon(Dialogs.resolveIcon(this, R.attr.dialog_alert_icon)); - dialog.setTitle(getString(R.string.ViewLocalIdentityActivity_reset_identity_key)); - dialog.setMessage(getString(R.string.ViewLocalIdentityActivity_by_regenerating_your_identity_key_your_existing_contacts_will_receive_warnings)); - dialog.setNegativeButton(getString(R.string.ViewLocalIdentityActivity_cancel), null); - dialog.setPositiveButton(getString(R.string.ViewLocalIdentityActivity_continue), - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - regenerateIdentityKey(); - } - }); - dialog.show(); - } - - private void regenerateIdentityKey() { - new AsyncTask() { - private ProgressDialog progressDialog; - - @Override - protected void onPreExecute() { - progressDialog = ProgressDialog.show(ViewLocalIdentityActivity.this, - getString(R.string.ViewLocalIdentityActivity_regenerating), - getString(R.string.ViewLocalIdentityActivity_regenerating_identity_key), - true, false); - } - - @Override - public Void doInBackground(Void... params) { - IdentityKeyUtil.generateIdentityKeys(ViewLocalIdentityActivity.this, masterSecret); - return null; - } - - @Override - protected void onPostExecute(Void result) { - if (progressDialog != null) - progressDialog.dismiss(); - - Toast.makeText(ViewLocalIdentityActivity.this, - getString(R.string.ViewLocalIdentityActivity_regenerated), - Toast.LENGTH_LONG).show(); - - getIntent().putExtra("identity_key", - IdentityKeyUtil.getIdentityKey(ViewLocalIdentityActivity.this)); - initialize(); - } - - }.execute(); - } - } diff --git a/src/org/thoughtcrime/securesms/contacts/ContactAccessor.java b/src/org/thoughtcrime/securesms/contacts/ContactAccessor.java index 03b5addd1..1d20354de 100644 --- a/src/org/thoughtcrime/securesms/contacts/ContactAccessor.java +++ b/src/org/thoughtcrime/securesms/contacts/ContactAccessor.java @@ -17,7 +17,6 @@ package org.thoughtcrime.securesms.contacts; import android.content.ContentResolver; -import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.MergeCursor; @@ -25,7 +24,6 @@ import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; import android.provider.ContactsContract; -import android.provider.ContactsContract.CommonDataKinds.Im; import android.provider.ContactsContract.CommonDataKinds.Phone; import android.provider.ContactsContract.Contacts; import android.provider.ContactsContract.Data; @@ -33,15 +31,9 @@ import android.provider.ContactsContract.PhoneLookup; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; import android.telephony.PhoneNumberUtils; -import android.util.Log; -import org.whispersystems.textsecure.crypto.IdentityKey; -import org.whispersystems.textsecure.crypto.InvalidKeyException; import org.whispersystems.textsecure.directory.Directory; -import org.whispersystems.textsecure.util.Base64; -import java.io.IOException; -import java.lang.Long; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedList; @@ -248,49 +240,6 @@ public class ContactAccessor { return Phone.getTypeLabel(mContext.getResources(), type, label); } - public void insertIdentityKey(Context context, List rawContactIds, IdentityKey identityKey) { - for (long rawContactId : rawContactIds) { - Log.w("ContactAccessorNewApi", "Inserting data for raw contact id: " + rawContactId); - ContentValues contentValues = new ContentValues(); - contentValues.put(Data.RAW_CONTACT_ID, rawContactId); - contentValues.put(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE); - contentValues.put(Im.PROTOCOL, Im.PROTOCOL_CUSTOM); - contentValues.put(Im.CUSTOM_PROTOCOL, "TextSecure-IdentityKey"); - contentValues.put(Im.DATA, Base64.encodeBytes(identityKey.serialize())); - - context.getContentResolver().insert(Data.CONTENT_URI, contentValues); - } - } - - public IdentityKey importIdentityKey(Context context, Uri uri) { - long contactId = getContactIdFromLookupUri(context, uri); - String selection = Im.CONTACT_ID + " = ? AND " + Im.PROTOCOL + " = ? AND " + Im.CUSTOM_PROTOCOL + " = ?"; - String[] selectionArgs = new String[] {contactId+"", Im.PROTOCOL_CUSTOM+"", "TextSecure-IdentityKey"}; - - Cursor cursor = context.getContentResolver().query(Data.CONTENT_URI, null, selection, selectionArgs, null); - - try { - if (cursor != null && cursor.moveToFirst()) { - String data = cursor.getString(cursor.getColumnIndexOrThrow(Im.DATA)); - - if (data != null) - return new IdentityKey(Base64.decode(data), 0); - - } - } catch (InvalidKeyException e) { - Log.w("ContactAccessorNewApi", e); - return null; - } catch (IOException e) { - Log.w("ContactAccessorNewApi", e); - return null; - } finally { - if (cursor != null) - cursor.close(); - } - - return null; - } - private long getContactIdFromLookupUri(Context context, Uri uri) { Cursor cursor = null; diff --git a/src/org/thoughtcrime/securesms/crypto/AsymmetricMasterCipher.java b/src/org/thoughtcrime/securesms/crypto/AsymmetricMasterCipher.java index 2e0d05b86..a60cf7388 100644 --- a/src/org/thoughtcrime/securesms/crypto/AsymmetricMasterCipher.java +++ b/src/org/thoughtcrime/securesms/crypto/AsymmetricMasterCipher.java @@ -17,15 +17,15 @@ */ package org.thoughtcrime.securesms.crypto; -import org.whispersystems.textsecure.crypto.InvalidKeyException; -import org.whispersystems.textsecure.crypto.InvalidMessageException; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.InvalidMessageException; +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.textsecure.crypto.MasterCipher; import org.whispersystems.textsecure.crypto.MasterSecret; import org.whispersystems.textsecure.crypto.PublicKey; -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECKeyPair; -import org.whispersystems.textsecure.crypto.ecc.ECPrivateKey; -import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; import org.whispersystems.textsecure.util.Base64; import org.whispersystems.textsecure.util.Conversions; import org.whispersystems.textsecure.util.Util; diff --git a/src/org/thoughtcrime/securesms/crypto/AsymmetricMasterSecret.java b/src/org/thoughtcrime/securesms/crypto/AsymmetricMasterSecret.java index 1f620be74..bc82032e3 100644 --- a/src/org/thoughtcrime/securesms/crypto/AsymmetricMasterSecret.java +++ b/src/org/thoughtcrime/securesms/crypto/AsymmetricMasterSecret.java @@ -17,9 +17,8 @@ */ package org.thoughtcrime.securesms.crypto; -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECPrivateKey; -import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; +import org.whispersystems.libaxolotl.ecc.ECPrivateKey; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; /** * When a user first initializes TextSecure, a few secrets @@ -40,7 +39,7 @@ import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; public class AsymmetricMasterSecret { - private final ECPublicKey djbPublicKey; + private final ECPublicKey djbPublicKey; private final ECPrivateKey djbPrivateKey; diff --git a/src/org/thoughtcrime/securesms/crypto/DecryptingQueue.java b/src/org/thoughtcrime/securesms/crypto/DecryptingQueue.java index 36955d91e..6af3ed5e6 100644 --- a/src/org/thoughtcrime/securesms/crypto/DecryptingQueue.java +++ b/src/org/thoughtcrime/securesms/crypto/DecryptingQueue.java @@ -23,7 +23,6 @@ import android.database.Cursor; import android.util.Log; import org.thoughtcrime.securesms.crypto.protocol.KeyExchangeMessage; -import org.whispersystems.textsecure.crypto.LegacyMessageException; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.EncryptingSmsDatabase; import org.thoughtcrime.securesms.database.MmsDatabase; @@ -41,13 +40,15 @@ import org.thoughtcrime.securesms.service.PushReceiver; import org.thoughtcrime.securesms.service.SendReceiveService; import org.thoughtcrime.securesms.sms.SmsTransportDetails; import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.whispersystems.textsecure.crypto.DuplicateMessageException; -import org.whispersystems.textsecure.crypto.InvalidKeyException; -import org.whispersystems.textsecure.crypto.InvalidMessageException; -import org.whispersystems.textsecure.crypto.InvalidVersionException; +import org.whispersystems.libaxolotl.DuplicateMessageException; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.InvalidMessageException; +import org.whispersystems.libaxolotl.InvalidVersionException; +import org.whispersystems.libaxolotl.LegacyMessageException; +import org.whispersystems.libaxolotl.SessionCipher; +import org.whispersystems.libaxolotl.protocol.WhisperMessage; import org.whispersystems.textsecure.crypto.MasterSecret; -import org.whispersystems.textsecure.crypto.SessionCipher; -import org.whispersystems.textsecure.crypto.protocol.WhisperMessage; +import org.whispersystems.textsecure.crypto.SessionCipherFactory; import org.whispersystems.textsecure.push.IncomingPushMessage; import org.whispersystems.textsecure.storage.RecipientDevice; import org.whispersystems.textsecure.storage.Session; @@ -205,7 +206,7 @@ public class DecryptingQueue { return; } - SessionCipher sessionCipher = SessionCipher.createFor(context, masterSecret, recipientDevice); + SessionCipher sessionCipher = SessionCipherFactory.getInstance(context, masterSecret, recipientDevice); byte[] plaintextBody = sessionCipher.decrypt(message.getBody()); message = message.withBody(plaintextBody); @@ -290,7 +291,7 @@ public class DecryptingQueue { Log.w("DecryptingQueue", "Decrypting: " + Hex.toString(ciphertextPduBytes)); TextTransport transportDetails = new TextTransport(); - SessionCipher sessionCipher = SessionCipher.createFor(context, masterSecret, recipientDevice); + SessionCipher sessionCipher = SessionCipherFactory.getInstance(context, masterSecret, recipientDevice); byte[] decodedCiphertext = transportDetails.getDecodedMessage(ciphertextPduBytes); try { @@ -385,7 +386,7 @@ public class DecryptingQueue { return; } - SessionCipher sessionCipher = SessionCipher.createFor(context, masterSecret, recipientDevice); + SessionCipher sessionCipher = SessionCipherFactory.getInstance(context, masterSecret, recipientDevice); byte[] paddedPlaintext = sessionCipher.decrypt(decodedCiphertext); plaintextBody = new String(transportDetails.getStrippedPaddingMessageBody(paddedPlaintext)); diff --git a/src/org/thoughtcrime/securesms/crypto/IdentityKeyUtil.java b/src/org/thoughtcrime/securesms/crypto/IdentityKeyUtil.java index 9c5832ae8..482873d1b 100644 --- a/src/org/thoughtcrime/securesms/crypto/IdentityKeyUtil.java +++ b/src/org/thoughtcrime/securesms/crypto/IdentityKeyUtil.java @@ -22,14 +22,14 @@ import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.util.Log; -import org.whispersystems.textsecure.crypto.IdentityKey; -import org.whispersystems.textsecure.crypto.IdentityKeyPair; -import org.whispersystems.textsecure.crypto.InvalidKeyException; +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.libaxolotl.IdentityKeyPair; +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.textsecure.crypto.MasterCipher; import org.whispersystems.textsecure.crypto.MasterSecret; -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECKeyPair; -import org.whispersystems.textsecure.crypto.ecc.ECPrivateKey; import org.whispersystems.textsecure.util.Base64; import java.io.IOException; diff --git a/src/org/thoughtcrime/securesms/crypto/KeyExchangeInitiator.java b/src/org/thoughtcrime/securesms/crypto/KeyExchangeInitiator.java index 6921f05e6..979f19c04 100644 --- a/src/org/thoughtcrime/securesms/crypto/KeyExchangeInitiator.java +++ b/src/org/thoughtcrime/securesms/crypto/KeyExchangeInitiator.java @@ -27,10 +27,10 @@ import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.sms.MessageSender; import org.thoughtcrime.securesms.sms.OutgoingKeyExchangeMessage; import org.thoughtcrime.securesms.util.Dialogs; -import org.whispersystems.textsecure.crypto.IdentityKeyPair; +import org.whispersystems.libaxolotl.IdentityKeyPair; +import org.whispersystems.libaxolotl.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECKeyPair; import org.whispersystems.textsecure.crypto.MasterSecret; -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECKeyPair; import org.whispersystems.textsecure.storage.RecipientDevice; import org.whispersystems.textsecure.storage.SessionRecordV2; diff --git a/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessor.java b/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessor.java index ba1d23dd9..165e95726 100644 --- a/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessor.java +++ b/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessor.java @@ -21,10 +21,8 @@ import android.content.Context; import android.content.Intent; import org.thoughtcrime.securesms.crypto.protocol.KeyExchangeMessage; -import org.thoughtcrime.securesms.recipients.Recipient; -import org.thoughtcrime.securesms.recipients.RecipientFactory; import org.thoughtcrime.securesms.service.KeyCachingService; -import org.whispersystems.textsecure.crypto.InvalidMessageException; +import org.whispersystems.libaxolotl.InvalidMessageException; import org.whispersystems.textsecure.crypto.MasterSecret; import org.whispersystems.textsecure.storage.RecipientDevice; diff --git a/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessorV2.java b/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessorV2.java index e8bae0820..36477fa17 100644 --- a/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessorV2.java +++ b/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessorV2.java @@ -12,16 +12,16 @@ import org.thoughtcrime.securesms.service.PreKeyService; import org.thoughtcrime.securesms.sms.MessageSender; import org.thoughtcrime.securesms.sms.OutgoingKeyExchangeMessage; import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.whispersystems.textsecure.crypto.IdentityKey; -import org.whispersystems.textsecure.crypto.IdentityKeyPair; -import org.whispersystems.textsecure.crypto.InvalidKeyException; -import org.whispersystems.textsecure.crypto.InvalidMessageException; +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.libaxolotl.IdentityKeyPair; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.InvalidMessageException; +import org.whispersystems.libaxolotl.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECKeyPair; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; +import org.whispersystems.libaxolotl.protocol.PreKeyWhisperMessage; +import org.whispersystems.libaxolotl.ratchet.RatchetingSession; import org.whispersystems.textsecure.crypto.MasterSecret; -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECKeyPair; -import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; -import org.whispersystems.textsecure.crypto.protocol.PreKeyWhisperMessage; -import org.whispersystems.textsecure.crypto.ratchet.RatchetingSession; import org.whispersystems.textsecure.push.PreKeyEntity; import org.whispersystems.textsecure.storage.InvalidKeyIdException; import org.whispersystems.textsecure.storage.PreKeyRecord; diff --git a/src/org/thoughtcrime/securesms/crypto/MasterSecretUtil.java b/src/org/thoughtcrime/securesms/crypto/MasterSecretUtil.java index 231588a07..02c1032fa 100644 --- a/src/org/thoughtcrime/securesms/crypto/MasterSecretUtil.java +++ b/src/org/thoughtcrime/securesms/crypto/MasterSecretUtil.java @@ -21,13 +21,13 @@ import android.content.Context; import android.content.SharedPreferences; import android.util.Log; -import org.whispersystems.textsecure.crypto.InvalidKeyException; +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.textsecure.crypto.MasterCipher; import org.whispersystems.textsecure.crypto.MasterSecret; -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECKeyPair; -import org.whispersystems.textsecure.crypto.ecc.ECPrivateKey; -import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; import org.whispersystems.textsecure.util.Base64; import org.whispersystems.textsecure.util.Util; @@ -129,8 +129,8 @@ public class MasterSecretUtil { byte[] djbPublicBytes = retrieve(context, ASYMMETRIC_LOCAL_PUBLIC_DJB); byte[] djbPrivateBytes = retrieve(context, ASYMMETRIC_LOCAL_PRIVATE_DJB); - ECPublicKey djbPublicKey = null; - ECPrivateKey djbPrivateKey = null; + ECPublicKey djbPublicKey = null; + ECPrivateKey djbPrivateKey = null; if (djbPublicBytes != null) { djbPublicKey = Curve.decodePoint(djbPublicBytes, 0); diff --git a/src/org/thoughtcrime/securesms/crypto/protocol/KeyExchangeMessage.java b/src/org/thoughtcrime/securesms/crypto/protocol/KeyExchangeMessage.java index df3cdb474..beef2064e 100644 --- a/src/org/thoughtcrime/securesms/crypto/protocol/KeyExchangeMessage.java +++ b/src/org/thoughtcrime/securesms/crypto/protocol/KeyExchangeMessage.java @@ -17,12 +17,12 @@ */ package org.thoughtcrime.securesms.crypto.protocol; -import org.whispersystems.textsecure.crypto.IdentityKey; -import org.whispersystems.textsecure.crypto.InvalidKeyException; -import org.whispersystems.textsecure.crypto.InvalidMessageException; -import org.whispersystems.textsecure.crypto.InvalidVersionException; -import org.whispersystems.textsecure.crypto.LegacyMessageException; +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.InvalidMessageException; +import org.whispersystems.libaxolotl.InvalidVersionException; +import org.whispersystems.libaxolotl.LegacyMessageException; public abstract class KeyExchangeMessage { public abstract IdentityKey getIdentityKey(); diff --git a/src/org/thoughtcrime/securesms/crypto/protocol/KeyExchangeMessageV2.java b/src/org/thoughtcrime/securesms/crypto/protocol/KeyExchangeMessageV2.java index 32f67b911..c8b74459f 100644 --- a/src/org/thoughtcrime/securesms/crypto/protocol/KeyExchangeMessageV2.java +++ b/src/org/thoughtcrime/securesms/crypto/protocol/KeyExchangeMessageV2.java @@ -3,15 +3,15 @@ package org.thoughtcrime.securesms.crypto.protocol; import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; -import org.whispersystems.textsecure.crypto.IdentityKey; -import org.whispersystems.textsecure.crypto.InvalidKeyException; -import org.whispersystems.textsecure.crypto.InvalidMessageException; -import org.whispersystems.textsecure.crypto.InvalidVersionException; -import org.whispersystems.textsecure.crypto.LegacyMessageException; -import org.whispersystems.textsecure.crypto.ecc.Curve; -import org.whispersystems.textsecure.crypto.ecc.ECPublicKey; -import org.whispersystems.textsecure.crypto.protocol.CiphertextMessage; -import org.whispersystems.textsecure.crypto.protocol.WhisperProtos; +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.InvalidMessageException; +import org.whispersystems.libaxolotl.InvalidVersionException; +import org.whispersystems.libaxolotl.LegacyMessageException; +import org.whispersystems.libaxolotl.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; +import org.whispersystems.libaxolotl.protocol.CiphertextMessage; +import org.whispersystems.libaxolotl.protocol.WhisperProtos; import org.whispersystems.textsecure.util.Base64; import org.whispersystems.textsecure.util.Conversions; import org.whispersystems.textsecure.util.Util; diff --git a/src/org/thoughtcrime/securesms/database/DatabaseFactory.java b/src/org/thoughtcrime/securesms/database/DatabaseFactory.java index b142ba098..411487a08 100644 --- a/src/org/thoughtcrime/securesms/database/DatabaseFactory.java +++ b/src/org/thoughtcrime/securesms/database/DatabaseFactory.java @@ -28,11 +28,11 @@ import org.thoughtcrime.securesms.DatabaseUpgradeActivity; import org.thoughtcrime.securesms.crypto.DecryptingPartInputStream; import org.thoughtcrime.securesms.crypto.DecryptingQueue; import org.thoughtcrime.securesms.crypto.MasterSecretUtil; -import org.whispersystems.textsecure.crypto.IdentityKey; -import org.whispersystems.textsecure.crypto.InvalidMessageException; +import org.thoughtcrime.securesms.notifications.MessageNotifier; +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.libaxolotl.InvalidMessageException; import org.whispersystems.textsecure.crypto.MasterCipher; import org.whispersystems.textsecure.crypto.MasterSecret; -import org.thoughtcrime.securesms.notifications.MessageNotifier; import org.whispersystems.textsecure.storage.Session; import org.whispersystems.textsecure.util.Base64; import org.whispersystems.textsecure.util.Util; diff --git a/src/org/thoughtcrime/securesms/database/DraftDatabase.java b/src/org/thoughtcrime/securesms/database/DraftDatabase.java index 487e03a07..5c2fd1c8c 100644 --- a/src/org/thoughtcrime/securesms/database/DraftDatabase.java +++ b/src/org/thoughtcrime/securesms/database/DraftDatabase.java @@ -7,7 +7,7 @@ import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.util.Log; -import org.whispersystems.textsecure.crypto.InvalidMessageException; +import org.whispersystems.libaxolotl.InvalidMessageException; import org.whispersystems.textsecure.crypto.MasterCipher; import java.util.LinkedList; diff --git a/src/org/thoughtcrime/securesms/database/EncryptingSmsDatabase.java b/src/org/thoughtcrime/securesms/database/EncryptingSmsDatabase.java index db263c0f0..53971238b 100644 --- a/src/org/thoughtcrime/securesms/database/EncryptingSmsDatabase.java +++ b/src/org/thoughtcrime/securesms/database/EncryptingSmsDatabase.java @@ -28,7 +28,7 @@ import org.thoughtcrime.securesms.database.model.DisplayRecord; import org.thoughtcrime.securesms.sms.IncomingTextMessage; import org.thoughtcrime.securesms.sms.OutgoingTextMessage; import org.thoughtcrime.securesms.util.LRUCache; -import org.whispersystems.textsecure.crypto.InvalidMessageException; +import org.whispersystems.libaxolotl.InvalidMessageException; import org.whispersystems.textsecure.crypto.MasterCipher; import org.whispersystems.textsecure.crypto.MasterSecret; diff --git a/src/org/thoughtcrime/securesms/database/IdentityDatabase.java b/src/org/thoughtcrime/securesms/database/IdentityDatabase.java index ce980c626..1d47226cd 100644 --- a/src/org/thoughtcrime/securesms/database/IdentityDatabase.java +++ b/src/org/thoughtcrime/securesms/database/IdentityDatabase.java @@ -24,14 +24,12 @@ import android.database.sqlite.SQLiteOpenHelper; import android.net.Uri; import android.util.Log; -import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientFactory; import org.thoughtcrime.securesms.recipients.Recipients; -import org.whispersystems.textsecure.crypto.IdentityKey; -import org.whispersystems.textsecure.crypto.InvalidKeyException; +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.libaxolotl.InvalidKeyException; import org.whispersystems.textsecure.crypto.MasterCipher; import org.whispersystems.textsecure.crypto.MasterSecret; -import org.whispersystems.textsecure.crypto.ecc.Curve; import org.whispersystems.textsecure.util.Base64; import java.io.IOException; diff --git a/src/org/thoughtcrime/securesms/database/MmsDatabase.java b/src/org/thoughtcrime/securesms/database/MmsDatabase.java index fed8abb75..955d7b971 100644 --- a/src/org/thoughtcrime/securesms/database/MmsDatabase.java +++ b/src/org/thoughtcrime/securesms/database/MmsDatabase.java @@ -32,7 +32,7 @@ import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage; import org.thoughtcrime.securesms.mms.OutgoingMediaMessage; import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.whispersystems.textsecure.crypto.InvalidMessageException; +import org.whispersystems.libaxolotl.InvalidMessageException; import org.whispersystems.textsecure.crypto.MasterCipher; import org.whispersystems.textsecure.crypto.MasterSecret; import org.thoughtcrime.securesms.database.model.DisplayRecord; diff --git a/src/org/thoughtcrime/securesms/database/ThreadDatabase.java b/src/org/thoughtcrime/securesms/database/ThreadDatabase.java index 8d5a1ac78..ff48730dc 100644 --- a/src/org/thoughtcrime/securesms/database/ThreadDatabase.java +++ b/src/org/thoughtcrime/securesms/database/ThreadDatabase.java @@ -29,7 +29,7 @@ import org.thoughtcrime.securesms.database.model.ThreadRecord; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientFactory; import org.thoughtcrime.securesms.recipients.Recipients; -import org.whispersystems.textsecure.crypto.InvalidMessageException; +import org.whispersystems.libaxolotl.InvalidMessageException; import org.whispersystems.textsecure.crypto.MasterCipher; import org.whispersystems.textsecure.util.Util; diff --git a/src/org/thoughtcrime/securesms/gcm/GcmBroadcastReceiver.java b/src/org/thoughtcrime/securesms/gcm/GcmBroadcastReceiver.java index 14c372d86..0dc21c554 100644 --- a/src/org/thoughtcrime/securesms/gcm/GcmBroadcastReceiver.java +++ b/src/org/thoughtcrime/securesms/gcm/GcmBroadcastReceiver.java @@ -9,7 +9,7 @@ import com.google.android.gms.gcm.GoogleCloudMessaging; import org.thoughtcrime.securesms.service.SendReceiveService; import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.whispersystems.textsecure.crypto.InvalidVersionException; +import org.whispersystems.libaxolotl.InvalidVersionException; import org.whispersystems.textsecure.directory.Directory; import org.whispersystems.textsecure.directory.NotInDirectoryException; import org.whispersystems.textsecure.push.ContactTokenDetails; diff --git a/src/org/thoughtcrime/securesms/service/AvatarDownloader.java b/src/org/thoughtcrime/securesms/service/AvatarDownloader.java index 666ba6e3c..050bcc3bd 100644 --- a/src/org/thoughtcrime/securesms/service/AvatarDownloader.java +++ b/src/org/thoughtcrime/securesms/service/AvatarDownloader.java @@ -15,8 +15,8 @@ import org.thoughtcrime.securesms.recipients.RecipientFormattingException; import org.thoughtcrime.securesms.util.BitmapDecodingException; import org.thoughtcrime.securesms.util.BitmapUtil; import org.thoughtcrime.securesms.util.GroupUtil; +import org.whispersystems.libaxolotl.InvalidMessageException; import org.whispersystems.textsecure.crypto.AttachmentCipherInputStream; -import org.whispersystems.textsecure.crypto.InvalidMessageException; import org.whispersystems.textsecure.crypto.MasterSecret; import org.whispersystems.textsecure.push.PushServiceSocket; diff --git a/src/org/thoughtcrime/securesms/service/PreKeyService.java b/src/org/thoughtcrime/securesms/service/PreKeyService.java index b21174e84..11998c721 100644 --- a/src/org/thoughtcrime/securesms/service/PreKeyService.java +++ b/src/org/thoughtcrime/securesms/service/PreKeyService.java @@ -9,10 +9,9 @@ import android.util.Log; import org.thoughtcrime.securesms.crypto.IdentityKeyUtil; import org.thoughtcrime.securesms.push.PushServiceSocketFactory; import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.whispersystems.textsecure.crypto.IdentityKey; +import org.whispersystems.libaxolotl.IdentityKey; import org.whispersystems.textsecure.crypto.MasterSecret; import org.whispersystems.textsecure.crypto.PreKeyUtil; -import org.whispersystems.textsecure.crypto.ecc.Curve; import org.whispersystems.textsecure.push.PushServiceSocket; import org.whispersystems.textsecure.storage.PreKeyRecord; diff --git a/src/org/thoughtcrime/securesms/service/PushDownloader.java b/src/org/thoughtcrime/securesms/service/PushDownloader.java index 1aa49878d..967c80bdf 100644 --- a/src/org/thoughtcrime/securesms/service/PushDownloader.java +++ b/src/org/thoughtcrime/securesms/service/PushDownloader.java @@ -12,8 +12,8 @@ import org.thoughtcrime.securesms.database.EncryptingPartDatabase; import org.thoughtcrime.securesms.database.PartDatabase; import org.thoughtcrime.securesms.push.PushServiceSocketFactory; import org.thoughtcrime.securesms.util.Util; +import org.whispersystems.libaxolotl.InvalidMessageException; import org.whispersystems.textsecure.crypto.AttachmentCipherInputStream; -import org.whispersystems.textsecure.crypto.InvalidMessageException; import org.whispersystems.textsecure.crypto.MasterCipher; import org.whispersystems.textsecure.crypto.MasterSecret; import org.whispersystems.textsecure.push.NotFoundException; diff --git a/src/org/thoughtcrime/securesms/service/PushReceiver.java b/src/org/thoughtcrime/securesms/service/PushReceiver.java index c38d1a949..aa7d4c262 100644 --- a/src/org/thoughtcrime/securesms/service/PushReceiver.java +++ b/src/org/thoughtcrime/securesms/service/PushReceiver.java @@ -25,11 +25,11 @@ import org.thoughtcrime.securesms.sms.IncomingKeyExchangeMessage; import org.thoughtcrime.securesms.sms.IncomingPreKeyBundleMessage; import org.thoughtcrime.securesms.sms.IncomingTextMessage; import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.whispersystems.textsecure.crypto.InvalidKeyException; -import org.whispersystems.textsecure.crypto.InvalidMessageException; -import org.whispersystems.textsecure.crypto.InvalidVersionException; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.InvalidMessageException; +import org.whispersystems.libaxolotl.InvalidVersionException; +import org.whispersystems.libaxolotl.protocol.PreKeyWhisperMessage; import org.whispersystems.textsecure.crypto.MasterSecret; -import org.whispersystems.textsecure.crypto.protocol.PreKeyWhisperMessage; import org.whispersystems.textsecure.push.IncomingPushMessage; import org.whispersystems.textsecure.push.PushMessageProtos.PushMessageContent; import org.whispersystems.textsecure.storage.InvalidKeyIdException; diff --git a/src/org/thoughtcrime/securesms/service/RegistrationService.java b/src/org/thoughtcrime/securesms/service/RegistrationService.java index ef59d4825..f0de43cd6 100644 --- a/src/org/thoughtcrime/securesms/service/RegistrationService.java +++ b/src/org/thoughtcrime/securesms/service/RegistrationService.java @@ -17,7 +17,7 @@ import org.thoughtcrime.securesms.crypto.IdentityKeyUtil; import org.thoughtcrime.securesms.push.PushServiceSocketFactory; import org.thoughtcrime.securesms.util.DirectoryHelper; import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.whispersystems.textsecure.crypto.IdentityKey; +import org.whispersystems.libaxolotl.IdentityKey; import org.whispersystems.textsecure.crypto.MasterSecret; import org.whispersystems.textsecure.crypto.PreKeyUtil; import org.whispersystems.textsecure.push.ExpectationFailedException; diff --git a/src/org/thoughtcrime/securesms/service/SmsReceiver.java b/src/org/thoughtcrime/securesms/service/SmsReceiver.java index 4d1676998..8b5cda76c 100644 --- a/src/org/thoughtcrime/securesms/service/SmsReceiver.java +++ b/src/org/thoughtcrime/securesms/service/SmsReceiver.java @@ -26,7 +26,6 @@ import org.thoughtcrime.securesms.crypto.KeyExchangeProcessor; import org.thoughtcrime.securesms.crypto.KeyExchangeProcessorV2; import org.thoughtcrime.securesms.crypto.MasterSecretUtil; import org.thoughtcrime.securesms.crypto.protocol.KeyExchangeMessage; -import org.whispersystems.textsecure.crypto.LegacyMessageException; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.EncryptingSmsDatabase; import org.thoughtcrime.securesms.database.SmsDatabase; @@ -42,12 +41,13 @@ import org.thoughtcrime.securesms.sms.IncomingTextMessage; import org.thoughtcrime.securesms.sms.MultipartSmsMessageHandler; import org.thoughtcrime.securesms.sms.SmsTransportDetails; import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.whispersystems.textsecure.crypto.InvalidKeyException; -import org.whispersystems.textsecure.crypto.InvalidMessageException; -import org.whispersystems.textsecure.crypto.InvalidVersionException; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.InvalidMessageException; +import org.whispersystems.libaxolotl.InvalidVersionException; +import org.whispersystems.libaxolotl.LegacyMessageException; +import org.whispersystems.libaxolotl.protocol.PreKeyWhisperMessage; +import org.whispersystems.libaxolotl.protocol.WhisperMessage; import org.whispersystems.textsecure.crypto.MasterSecret; -import org.whispersystems.textsecure.crypto.protocol.PreKeyWhisperMessage; -import org.whispersystems.textsecure.crypto.protocol.WhisperMessage; import org.whispersystems.textsecure.storage.InvalidKeyIdException; import org.whispersystems.textsecure.storage.RecipientDevice; diff --git a/src/org/thoughtcrime/securesms/sms/IncomingIdentityUpdateMessage.java b/src/org/thoughtcrime/securesms/sms/IncomingIdentityUpdateMessage.java index 36cdb5729..7bbdcc38f 100644 --- a/src/org/thoughtcrime/securesms/sms/IncomingIdentityUpdateMessage.java +++ b/src/org/thoughtcrime/securesms/sms/IncomingIdentityUpdateMessage.java @@ -1,6 +1,6 @@ package org.thoughtcrime.securesms.sms; -import org.whispersystems.textsecure.crypto.IdentityKey; +import org.whispersystems.libaxolotl.IdentityKey; import org.whispersystems.textsecure.util.Base64; public class IncomingIdentityUpdateMessage extends IncomingKeyExchangeMessage { diff --git a/src/org/thoughtcrime/securesms/sms/SmsTransportDetails.java b/src/org/thoughtcrime/securesms/sms/SmsTransportDetails.java index 150b164d9..d40235b07 100644 --- a/src/org/thoughtcrime/securesms/sms/SmsTransportDetails.java +++ b/src/org/thoughtcrime/securesms/sms/SmsTransportDetails.java @@ -19,8 +19,8 @@ package org.thoughtcrime.securesms.sms; import android.util.Log; import org.thoughtcrime.securesms.protocol.WirePrefix; +import org.whispersystems.libaxolotl.protocol.CiphertextMessage; import org.whispersystems.textsecure.crypto.TransportDetails; -import org.whispersystems.textsecure.crypto.protocol.CiphertextMessage; import org.whispersystems.textsecure.util.Base64; import java.io.IOException; diff --git a/src/org/thoughtcrime/securesms/transport/MmsTransport.java b/src/org/thoughtcrime/securesms/transport/MmsTransport.java index 0683bedfe..0b272cf24 100644 --- a/src/org/thoughtcrime/securesms/transport/MmsTransport.java +++ b/src/org/thoughtcrime/securesms/transport/MmsTransport.java @@ -33,9 +33,10 @@ import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientFactory; import org.thoughtcrime.securesms.recipients.RecipientFormattingException; import org.thoughtcrime.securesms.util.NumberUtil; +import org.whispersystems.libaxolotl.SessionCipher; +import org.whispersystems.libaxolotl.protocol.CiphertextMessage; import org.whispersystems.textsecure.crypto.MasterSecret; -import org.whispersystems.textsecure.crypto.SessionCipher; -import org.whispersystems.textsecure.crypto.protocol.CiphertextMessage; +import org.whispersystems.textsecure.crypto.SessionCipherFactory; import org.whispersystems.textsecure.storage.RecipientDevice; import org.whispersystems.textsecure.storage.Session; import org.whispersystems.textsecure.util.Hex; @@ -177,7 +178,7 @@ public class MmsTransport { throw new InsecureFallbackApprovalException("No session exists for this secure message."); } - SessionCipher sessionCipher = SessionCipher.createFor(context, masterSecret, recipientDevice); + SessionCipher sessionCipher = SessionCipherFactory.getInstance(context, masterSecret, recipientDevice); CiphertextMessage ciphertextMessage = sessionCipher.encrypt(pduBytes); return transportDetails.getEncodedMessage(ciphertextMessage.serialize()); diff --git a/src/org/thoughtcrime/securesms/transport/PushTransport.java b/src/org/thoughtcrime/securesms/transport/PushTransport.java index b6f885e42..221bdfdb6 100644 --- a/src/org/thoughtcrime/securesms/transport/PushTransport.java +++ b/src/org/thoughtcrime/securesms/transport/PushTransport.java @@ -35,11 +35,12 @@ import org.thoughtcrime.securesms.recipients.RecipientFormattingException; import org.thoughtcrime.securesms.recipients.Recipients; import org.thoughtcrime.securesms.util.GroupUtil; import org.thoughtcrime.securesms.util.Util; +import org.whispersystems.libaxolotl.InvalidKeyException; +import org.whispersystems.libaxolotl.SessionCipher; +import org.whispersystems.libaxolotl.protocol.CiphertextMessage; import org.whispersystems.textsecure.crypto.AttachmentCipher; -import org.whispersystems.textsecure.crypto.InvalidKeyException; import org.whispersystems.textsecure.crypto.MasterSecret; -import org.whispersystems.textsecure.crypto.SessionCipher; -import org.whispersystems.textsecure.crypto.protocol.CiphertextMessage; +import org.whispersystems.textsecure.crypto.SessionCipherFactory; import org.whispersystems.textsecure.push.MismatchedDevices; import org.whispersystems.textsecure.push.MismatchedDevicesException; import org.whispersystems.textsecure.push.OutgoingPushMessage; @@ -348,9 +349,9 @@ public class PushTransport extends BaseTransport { } } - SessionCipher cipher = SessionCipher.createFor(context, masterSecret, pushAddress); - CiphertextMessage message = cipher.encrypt(plaintext); - int remoteRegistrationId = cipher.getRemoteRegistrationId(); + SessionCipher cipher = SessionCipherFactory.getInstance(context, masterSecret, pushAddress); + CiphertextMessage message = cipher.encrypt(plaintext); + int remoteRegistrationId = cipher.getRemoteRegistrationId(); if (message.getType() == CiphertextMessage.PREKEY_TYPE) { return new PushBody(IncomingPushMessageSignal.Type.PREKEY_BUNDLE_VALUE, remoteRegistrationId, message.serialize()); diff --git a/src/org/thoughtcrime/securesms/transport/SmsTransport.java b/src/org/thoughtcrime/securesms/transport/SmsTransport.java index 2709c5815..e56f1d61c 100644 --- a/src/org/thoughtcrime/securesms/transport/SmsTransport.java +++ b/src/org/thoughtcrime/securesms/transport/SmsTransport.java @@ -30,9 +30,10 @@ import org.thoughtcrime.securesms.sms.OutgoingTextMessage; import org.thoughtcrime.securesms.sms.SmsTransportDetails; import org.thoughtcrime.securesms.util.NumberUtil; import org.thoughtcrime.securesms.util.TextSecurePreferences; +import org.whispersystems.libaxolotl.SessionCipher; +import org.whispersystems.libaxolotl.protocol.CiphertextMessage; import org.whispersystems.textsecure.crypto.MasterSecret; -import org.whispersystems.textsecure.crypto.SessionCipher; -import org.whispersystems.textsecure.crypto.protocol.CiphertextMessage; +import org.whispersystems.textsecure.crypto.SessionCipherFactory; import org.whispersystems.textsecure.storage.RecipientDevice; import org.whispersystems.textsecure.storage.Session; @@ -179,7 +180,7 @@ public class SmsTransport extends BaseTransport { String body = message.getMessageBody(); SmsTransportDetails transportDetails = new SmsTransportDetails(); - SessionCipher sessionCipher = SessionCipher.createFor(context, masterSecret, recipientDevice); + SessionCipher sessionCipher = SessionCipherFactory.getInstance(context, masterSecret, recipientDevice); byte[] paddedPlaintext = transportDetails.getPaddedMessageBody(body.getBytes()); CiphertextMessage ciphertextMessage = sessionCipher.encrypt(paddedPlaintext); String encodedCiphertext = new String(transportDetails.getEncodedMessage(ciphertextMessage.serialize())); diff --git a/src/org/thoughtcrime/securesms/transport/UntrustedIdentityException.java b/src/org/thoughtcrime/securesms/transport/UntrustedIdentityException.java index ac322f392..195bcd14c 100644 --- a/src/org/thoughtcrime/securesms/transport/UntrustedIdentityException.java +++ b/src/org/thoughtcrime/securesms/transport/UntrustedIdentityException.java @@ -1,7 +1,6 @@ package org.thoughtcrime.securesms.transport; -import org.whispersystems.textsecure.crypto.IdentityKey; -import org.whispersystems.textsecure.push.UnregisteredUserException; +import org.whispersystems.libaxolotl.IdentityKey; public class UntrustedIdentityException extends Exception {