diff --git a/library/jni/curve25519-donna-jni.c b/library/jni/curve25519-donna-jni.c index bcda8a4a5a..4ce32bb632 100644 --- a/library/jni/curve25519-donna-jni.c +++ b/library/jni/curve25519-donna-jni.c @@ -22,11 +22,16 @@ #include "curve25519-donna.h" JNIEXPORT jbyteArray JNICALL Java_org_whispersystems_textsecure_crypto_ecc_Curve25519_generatePrivateKey - (JNIEnv *env, jclass clazz, jbyteArray random) + (JNIEnv *env, jclass clazz, jbyteArray random, jboolean ephemeral) { uint8_t* privateKey = (uint8_t*)(*env)->GetByteArrayElements(env, random, 0); privateKey[0] &= 248; + + if (ephemeral) { + privateKey[0] |= 1; + } + privateKey[31] &= 127; privateKey[31] |= 64; diff --git a/library/jni/curve25519-donna.c b/library/jni/curve25519-donna.c index bb1262e5e9..b84c9e0ff1 100644 --- a/library/jni/curve25519-donna.c +++ b/library/jni/curve25519-donna.c @@ -720,9 +720,6 @@ curve25519_donna(u8 *mypublic, const u8 *secret, const u8 *basepoint) { int i; for (i = 0; i < 32; ++i) e[i] = secret[i]; - e[0] &= 248; - e[31] &= 127; - e[31] |= 64; fexpand(bp, basepoint); cmult(x, z, e, bp); diff --git a/library/libs/armeabi-v7a/libcurve25519.so b/library/libs/armeabi-v7a/libcurve25519.so index 16f42b116a..3fa1b15aa8 100755 Binary files a/library/libs/armeabi-v7a/libcurve25519.so and b/library/libs/armeabi-v7a/libcurve25519.so differ diff --git a/library/libs/armeabi/libcurve25519.so b/library/libs/armeabi/libcurve25519.so index 4c019bead8..f109b7eb4a 100755 Binary files a/library/libs/armeabi/libcurve25519.so and b/library/libs/armeabi/libcurve25519.so differ diff --git a/library/libs/x86/libcurve25519.so b/library/libs/x86/libcurve25519.so index bc0779fc22..bb80ed1ea8 100755 Binary files a/library/libs/x86/libcurve25519.so and b/library/libs/x86/libcurve25519.so differ diff --git a/library/src/org/whispersystems/textsecure/crypto/PreKeyUtil.java b/library/src/org/whispersystems/textsecure/crypto/PreKeyUtil.java index 146ade1078..e137b97c09 100644 --- a/library/src/org/whispersystems/textsecure/crypto/PreKeyUtil.java +++ b/library/src/org/whispersystems/textsecure/crypto/PreKeyUtil.java @@ -48,7 +48,7 @@ public class PreKeyUtil { for (int i=0;i receiverChain = rootKey.createChain(theirEphemeral, ourEphemeral); - ECKeyPair ourNewEphemeral = Curve.generateKeyPairForType(Curve.DJB_TYPE); + ECKeyPair ourNewEphemeral = Curve.generateKeyPairForType(Curve.DJB_TYPE, true); Pair senderChain = receiverChain.first.createChain(theirEphemeral, ourNewEphemeral); sessionState.setRootKey(senderChain.first); diff --git a/library/src/org/whispersystems/textsecure/crypto/ecc/Curve.java b/library/src/org/whispersystems/textsecure/crypto/ecc/Curve.java index aa9381969a..097d6930a2 100644 --- a/library/src/org/whispersystems/textsecure/crypto/ecc/Curve.java +++ b/library/src/org/whispersystems/textsecure/crypto/ecc/Curve.java @@ -25,9 +25,9 @@ public class Curve { private static final int NIST_TYPE2 = 0x03; public static final int DJB_TYPE = 0x05; - public static ECKeyPair generateKeyPairForType(int keyType) { + public static ECKeyPair generateKeyPairForType(int keyType, boolean ephemeral) { if (keyType == DJB_TYPE) { - return Curve25519.generateKeyPair(); + return Curve25519.generateKeyPair(ephemeral); } else if (keyType == NIST_TYPE || keyType == NIST_TYPE2) { return CurveP256.generateKeyPair(); } else { @@ -35,11 +35,11 @@ public class Curve { } } - public static ECKeyPair generateKeyPairForSession(int messageVersion) { + public static ECKeyPair generateKeyPairForSession(int messageVersion, boolean ephemeral) { if (messageVersion <= CiphertextMessage.LEGACY_VERSION) { - return generateKeyPairForType(NIST_TYPE); + return generateKeyPairForType(NIST_TYPE, ephemeral); } else { - return generateKeyPairForType(DJB_TYPE); + return generateKeyPairForType(DJB_TYPE, ephemeral); } } diff --git a/library/src/org/whispersystems/textsecure/crypto/ecc/Curve25519.java b/library/src/org/whispersystems/textsecure/crypto/ecc/Curve25519.java index 64dc5e7b27..94bd71b67d 100644 --- a/library/src/org/whispersystems/textsecure/crypto/ecc/Curve25519.java +++ b/library/src/org/whispersystems/textsecure/crypto/ecc/Curve25519.java @@ -37,10 +37,10 @@ public class Curve25519 { private static native byte[] calculateAgreement(byte[] ourPrivate, byte[] theirPublic); private static native byte[] generatePublicKey(byte[] privateKey); - private static native byte[] generatePrivateKey(byte[] random); + private static native byte[] generatePrivateKey(byte[] random, boolean ephemeral); - public static ECKeyPair generateKeyPair() { - byte[] privateKey = generatePrivateKey(); + public static ECKeyPair generateKeyPair(boolean ephemeral) { + byte[] privateKey = generatePrivateKey(ephemeral); byte[] publicKey = generatePublicKey(privateKey); return new ECKeyPair(new DjbECPublicKey(publicKey), new DjbECPrivateKey(privateKey)); @@ -65,11 +65,11 @@ public class Curve25519 { return new DjbECPublicKey(keyBytes); } - private static byte[] generatePrivateKey() { + private static byte[] generatePrivateKey(boolean ephemeral) { byte[] privateKey = new byte[32]; random.nextBytes(privateKey); - return generatePrivateKey(privateKey); + return generatePrivateKey(privateKey, ephemeral); } } diff --git a/library/src/org/whispersystems/textsecure/crypto/ratchet/RatchetingSession.java b/library/src/org/whispersystems/textsecure/crypto/ratchet/RatchetingSession.java index 924b163935..a7f716bacd 100644 --- a/library/src/org/whispersystems/textsecure/crypto/ratchet/RatchetingSession.java +++ b/library/src/org/whispersystems/textsecure/crypto/ratchet/RatchetingSession.java @@ -45,7 +45,7 @@ public class RatchetingSession { sessionState.setRemoteIdentityKey(theirIdentityKey); sessionState.setLocalIdentityKey(ourIdentityKey.getPublicKey()); - ECKeyPair sendingKey = Curve.generateKeyPairForType(ourIdentityKey.getPublicKey().getPublicKey().getType()); + ECKeyPair sendingKey = Curve.generateKeyPairForType(ourIdentityKey.getPublicKey().getPublicKey().getType(), true); Pair receivingChain = calculate3DHE(true, ourBaseKey, theirBaseKey, ourIdentityKey, theirIdentityKey); Pair sendingChain = receivingChain.first.createChain(theirEphemeralKey, sendingKey); diff --git a/library/src/org/whispersystems/textsecure/storage/LocalKeyRecord.java b/library/src/org/whispersystems/textsecure/storage/LocalKeyRecord.java index 97810179a7..3f1aafd070 100644 --- a/library/src/org/whispersystems/textsecure/storage/LocalKeyRecord.java +++ b/library/src/org/whispersystems/textsecure/storage/LocalKeyRecord.java @@ -70,7 +70,7 @@ public class LocalKeyRecord extends Record { this.localCurrentKeyPair = this.localNextKeyPair; this.localNextKeyPair = new KeyPair((this.localNextKeyPair.getId()+1) % Medium.MAX_VALUE, - Curve.generateKeyPairForType(keyType), + Curve.generateKeyPairForType(keyType, true), masterSecret); } } diff --git a/src/org/thoughtcrime/securesms/crypto/AsymmetricMasterCipher.java b/src/org/thoughtcrime/securesms/crypto/AsymmetricMasterCipher.java index 4c6588a664..1b521e114b 100644 --- a/src/org/thoughtcrime/securesms/crypto/AsymmetricMasterCipher.java +++ b/src/org/thoughtcrime/securesms/crypto/AsymmetricMasterCipher.java @@ -93,7 +93,7 @@ public class AsymmetricMasterCipher { theirPublic = asymmetricMasterSecret.getNistPublicKey(); } - ECKeyPair ourKeyPair = Curve.generateKeyPairForType(theirPublic.getType()); + ECKeyPair ourKeyPair = Curve.generateKeyPairForType(theirPublic.getType(), true); byte[] secret = Curve.calculateAgreement(theirPublic, ourKeyPair.getPrivateKey()); MasterCipher masterCipher = getMasterCipherForSecret(secret); byte[] encryptedBodyBytes = masterCipher.encryptBytes(body.getBytes()); diff --git a/src/org/thoughtcrime/securesms/crypto/IdentityKeyUtil.java b/src/org/thoughtcrime/securesms/crypto/IdentityKeyUtil.java index d7bf6da1eb..ed63b477c4 100644 --- a/src/org/thoughtcrime/securesms/crypto/IdentityKeyUtil.java +++ b/src/org/thoughtcrime/securesms/crypto/IdentityKeyUtil.java @@ -135,8 +135,8 @@ public class IdentityKeyUtil { } public static void generateIdentityKeys(Context context, MasterSecret masterSecret) { - ECKeyPair nistKeyPair = Curve.generateKeyPairForType(Curve.NIST_TYPE); - ECKeyPair djbKeyPair = Curve.generateKeyPairForType(Curve.DJB_TYPE); + ECKeyPair nistKeyPair = Curve.generateKeyPairForType(Curve.NIST_TYPE, false); + ECKeyPair djbKeyPair = Curve.generateKeyPairForType(Curve.DJB_TYPE, false); MasterCipher masterCipher = new MasterCipher(masterSecret); IdentityKey nistIdentityKey = new IdentityKey(nistKeyPair.getPublicKey()); @@ -160,7 +160,7 @@ public class IdentityKeyUtil { public static void generateCurve25519IdentityKeys(Context context, MasterSecret masterSecret) { MasterCipher masterCipher = new MasterCipher(masterSecret); - ECKeyPair djbKeyPair = Curve.generateKeyPairForType(Curve.DJB_TYPE); + ECKeyPair djbKeyPair = Curve.generateKeyPairForType(Curve.DJB_TYPE, false); IdentityKey djbIdentityKey = new IdentityKey(djbKeyPair.getPublicKey()); byte[] djbPrivateKey = masterCipher.encryptKey(djbKeyPair.getPrivateKey()); diff --git a/src/org/thoughtcrime/securesms/crypto/KeyExchangeInitiator.java b/src/org/thoughtcrime/securesms/crypto/KeyExchangeInitiator.java index e6e697427a..3bb1ac9a19 100644 --- a/src/org/thoughtcrime/securesms/crypto/KeyExchangeInitiator.java +++ b/src/org/thoughtcrime/securesms/crypto/KeyExchangeInitiator.java @@ -62,8 +62,8 @@ public class KeyExchangeInitiator { private static void initiateKeyExchange(Context context, MasterSecret masterSecret, Recipient recipient) { int sequence = getRandomSequence(); int flags = KeyExchangeMessageV2.INITIATE_FLAG; - ECKeyPair baseKey = Curve.generateKeyPairForSession(CiphertextMessage.CURRENT_VERSION); - ECKeyPair ephemeralKey = Curve.generateKeyPairForSession(CiphertextMessage.CURRENT_VERSION); + ECKeyPair baseKey = Curve.generateKeyPairForSession(CiphertextMessage.CURRENT_VERSION, true); + ECKeyPair ephemeralKey = Curve.generateKeyPairForSession(CiphertextMessage.CURRENT_VERSION, true); IdentityKeyPair identityKey = IdentityKeyUtil.getIdentityKeyPair(context, masterSecret, Curve.DJB_TYPE); KeyExchangeMessageV2 message = new KeyExchangeMessageV2(sequence, flags, diff --git a/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessorV1.java b/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessorV1.java index d0219407c0..44367f6a4a 100644 --- a/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessorV1.java +++ b/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessorV1.java @@ -136,8 +136,8 @@ public class KeyExchangeProcessorV1 extends KeyExchangeProcessor { SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG"); int initialId = secureRandom.nextInt(4094) + 1; - KeyPair currentPair = new KeyPair(initialId, Curve.generateKeyPairForSession(1), masterSecret); - KeyPair nextPair = new KeyPair(initialId + 1, Curve.generateKeyPairForSession(1), masterSecret); + KeyPair currentPair = new KeyPair(initialId, Curve.generateKeyPairForSession(1, true), masterSecret); + KeyPair nextPair = new KeyPair(initialId + 1, Curve.generateKeyPairForSession(1, true), masterSecret); LocalKeyRecord record = new LocalKeyRecord(context, masterSecret, recipient); record.setCurrentKeyPair(currentPair); diff --git a/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessorV2.java b/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessorV2.java index 2bbf886a82..c09b05f067 100644 --- a/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessorV2.java +++ b/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessorV2.java @@ -131,8 +131,8 @@ public class KeyExchangeProcessorV2 extends KeyExchangeProcessor { public void processKeyExchangeMessage(PreKeyEntity message, long threadId) throws InvalidKeyException { - ECKeyPair ourBaseKey = Curve.generateKeyPairForSession(2); - ECKeyPair ourEphemeralKey = Curve.generateKeyPairForSession(2); + ECKeyPair ourBaseKey = Curve.generateKeyPairForSession(2, true); + ECKeyPair ourEphemeralKey = Curve.generateKeyPairForSession(2, true); ECPublicKey theirBaseKey = message.getPublicKey(); ECPublicKey theirEphemeralKey = theirBaseKey; IdentityKey theirIdentityKey = message.getIdentityKey(); @@ -184,8 +184,8 @@ public class KeyExchangeProcessorV2 extends KeyExchangeProcessor { if (!sessionRecord.getSessionState().hasPendingKeyExchange()) { Log.w("KeyExchangeProcessorV2", "We don't have a pending initiate..."); - ourBaseKey = Curve.generateKeyPairForType(message.getBaseKey().getType()); - ourEphemeralKey = Curve.generateKeyPairForType(message.getBaseKey().getType()); + ourBaseKey = Curve.generateKeyPairForType(message.getBaseKey().getType(), true); + ourEphemeralKey = Curve.generateKeyPairForType(message.getBaseKey().getType(), true); ourIdentityKey = IdentityKeyUtil.getIdentityKeyPair(context, masterSecret, message.getBaseKey().getType()); sessionRecord.getSessionState().setPendingKeyExchange(message.getSequence(), ourBaseKey, diff --git a/src/org/thoughtcrime/securesms/crypto/MasterSecretUtil.java b/src/org/thoughtcrime/securesms/crypto/MasterSecretUtil.java index 146925a8c9..d1803344f3 100644 --- a/src/org/thoughtcrime/securesms/crypto/MasterSecretUtil.java +++ b/src/org/thoughtcrime/securesms/crypto/MasterSecretUtil.java @@ -160,7 +160,7 @@ public class MasterSecretUtil { MasterSecret masterSecret) { MasterCipher masterCipher = new MasterCipher(masterSecret); - ECKeyPair keyPair = Curve.generateKeyPairForType(Curve.DJB_TYPE); + ECKeyPair keyPair = Curve.generateKeyPairForType(Curve.DJB_TYPE, true); save(context, ASYMMETRIC_LOCAL_PUBLIC_DJB, keyPair.getPublicKey().serialize()); save(context, ASYMMETRIC_LOCAL_PRIVATE_DJB, masterCipher.encryptKey(keyPair.getPrivateKey()));