diff --git a/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java b/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java index e453c9eeae..6ff9b5a691 100644 --- a/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java +++ b/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java @@ -336,7 +336,7 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA case PREFERENCE_CATEGORY_LINKED_DEVICES: break; case PREFERENCE_CATEGORY_SEED: try { - String hexEncodedSeed = IdentityKeyUtil.retrieve(getContext(), IdentityKeyUtil.lokiSeedKey); + String hexEncodedSeed = IdentityKeyUtil.retrieve(getContext(), IdentityKeyUtil.LOKI_SEED); if (hexEncodedSeed == null) { hexEncodedSeed = HexEncodingKt.getHexEncodedPrivateKey(IdentityKeyUtil.getIdentityKeyPair(getContext())); // Legacy account } diff --git a/src/org/thoughtcrime/securesms/crypto/IdentityKeyUtil.java b/src/org/thoughtcrime/securesms/crypto/IdentityKeyUtil.java index b8b5dd6518..9d3877fc75 100644 --- a/src/org/thoughtcrime/securesms/crypto/IdentityKeyUtil.java +++ b/src/org/thoughtcrime/securesms/crypto/IdentityKeyUtil.java @@ -53,8 +53,7 @@ public class IdentityKeyUtil { public static final String IDENTITY_PRIVATE_KEY_PREF = "pref_identity_private_v3"; public static final String ED25519_PUBLIC_KEY = "pref_ed25519_public_key"; public static final String ED25519_SECRET_KEY = "pref_ed25519_secret_key"; - - public static final String lokiSeedKey = "loki_seed"; + public static final String LOKI_SEED = "loki_seed"; public static boolean hasIdentityKey(Context context) { SharedPreferences preferences = context.getSharedPreferences(MasterSecretUtil.PREFERENCES_NAME, 0); diff --git a/src/org/thoughtcrime/securesms/loki/activities/LandingActivity.kt b/src/org/thoughtcrime/securesms/loki/activities/LandingActivity.kt index 383a39352e..43901fa7b3 100644 --- a/src/org/thoughtcrime/securesms/loki/activities/LandingActivity.kt +++ b/src/org/thoughtcrime/securesms/loki/activities/LandingActivity.kt @@ -85,7 +85,7 @@ class LandingActivity : BaseActionBarActivity(), LinkDeviceSlaveModeDialogDelega seed = seedCandidate } generateKeyPair() - IdentityKeyUtil.save(this, IdentityKeyUtil.lokiSeedKey, Hex.toStringCondensed(seed)) + IdentityKeyUtil.save(this, IdentityKeyUtil.LOKI_SEED, Hex.toStringCondensed(seed)) IdentityKeyUtil.save(this, IdentityKeyUtil.IDENTITY_PUBLIC_KEY_PREF, Base64.encodeBytes(keyPair!!.publicKey.serialize())) IdentityKeyUtil.save(this, IdentityKeyUtil.IDENTITY_PRIVATE_KEY_PREF, Base64.encodeBytes(keyPair!!.privateKey.serialize())) val userHexEncodedPublicKey = keyPair!!.hexEncodedPublicKey @@ -140,7 +140,7 @@ class LandingActivity : BaseActionBarActivity(), LinkDeviceSlaveModeDialogDelega } private fun reset() { - IdentityKeyUtil.delete(this, IdentityKeyUtil.lokiSeedKey) + IdentityKeyUtil.delete(this, IdentityKeyUtil.LOKI_SEED) TextSecurePreferences.removeLocalNumber(this) TextSecurePreferences.setHasSeenWelcomeScreen(this, false) TextSecurePreferences.setPromptedPushRegistration(this, false) diff --git a/src/org/thoughtcrime/securesms/loki/activities/RegisterActivity.kt b/src/org/thoughtcrime/securesms/loki/activities/RegisterActivity.kt index 1737b01e5d..e7b242627c 100644 --- a/src/org/thoughtcrime/securesms/loki/activities/RegisterActivity.kt +++ b/src/org/thoughtcrime/securesms/loki/activities/RegisterActivity.kt @@ -26,6 +26,7 @@ import org.thoughtcrime.securesms.crypto.IdentityKeyUtil import org.thoughtcrime.securesms.database.Address import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.database.IdentityDatabase +import org.thoughtcrime.securesms.loki.utilities.KeyPairUtilities import org.thoughtcrime.securesms.loki.utilities.push import org.thoughtcrime.securesms.loki.utilities.setUpActionBarSessionLogo import org.thoughtcrime.securesms.util.Base64 @@ -37,7 +38,6 @@ import org.whispersystems.libsignal.util.KeyHelper import org.whispersystems.signalservice.loki.utilities.hexEncodedPublicKey class RegisterActivity : BaseActionBarActivity() { - private val sodium = LazySodiumAndroid(SodiumAndroid()) private var seed: ByteArray? = null private var ed25519KeyPair: KeyPair? = null private var x25519KeyPair: ECKeyPair? = null @@ -73,16 +73,10 @@ class RegisterActivity : BaseActionBarActivity() { // region Updating private fun updateKeyPair() { - val seedCandidate = Curve25519.getInstance(Curve25519.BEST).generateSeed(16) - try { - val padding = ByteArray(16) { 0 } - ed25519KeyPair = sodium.cryptoSignSeedKeypair(seedCandidate + padding) - val x25519KeyPair = sodium.convertKeyPairEd25519ToCurve25519(ed25519KeyPair) - this.x25519KeyPair = ECKeyPair(DjbECPublicKey(x25519KeyPair.publicKey.asBytes), DjbECPrivateKey(x25519KeyPair.secretKey.asBytes)) - } catch (exception: Exception) { - return updateKeyPair() - } - seed = seedCandidate + val keyPairGenerationResult = KeyPairUtilities.generate() + seed = keyPairGenerationResult.seed + ed25519KeyPair = keyPairGenerationResult.ed25519KeyPair + x25519KeyPair = keyPairGenerationResult.x25519KeyPair } private fun updatePublicKeyTextView() { @@ -117,11 +111,7 @@ class RegisterActivity : BaseActionBarActivity() { // region Interaction private fun register() { - IdentityKeyUtil.save(this, IdentityKeyUtil.lokiSeedKey, Hex.toStringCondensed(seed)) - IdentityKeyUtil.save(this, IdentityKeyUtil.IDENTITY_PUBLIC_KEY_PREF, Base64.encodeBytes(x25519KeyPair!!.publicKey.serialize())) - IdentityKeyUtil.save(this, IdentityKeyUtil.IDENTITY_PRIVATE_KEY_PREF, Base64.encodeBytes(x25519KeyPair!!.privateKey.serialize())) - IdentityKeyUtil.save(this, IdentityKeyUtil.ED25519_PUBLIC_KEY, Base64.encodeBytes(ed25519KeyPair!!.publicKey.asBytes)) - IdentityKeyUtil.save(this, IdentityKeyUtil.ED25519_SECRET_KEY, Base64.encodeBytes(ed25519KeyPair!!.secretKey.asBytes)) + KeyPairUtilities.store(this, seed!!, ed25519KeyPair!!, x25519KeyPair!!) val userHexEncodedPublicKey = x25519KeyPair!!.hexEncodedPublicKey val registrationID = KeyHelper.generateRegistrationId(false) TextSecurePreferences.setLocalRegistrationId(this, registrationID) diff --git a/src/org/thoughtcrime/securesms/loki/activities/RestoreActivity.kt b/src/org/thoughtcrime/securesms/loki/activities/RestoreActivity.kt index 5c4ffa7863..46f6c38f47 100644 --- a/src/org/thoughtcrime/securesms/loki/activities/RestoreActivity.kt +++ b/src/org/thoughtcrime/securesms/loki/activities/RestoreActivity.kt @@ -18,18 +18,15 @@ import org.thoughtcrime.securesms.crypto.IdentityKeyUtil import org.thoughtcrime.securesms.database.Address import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.database.IdentityDatabase +import org.thoughtcrime.securesms.loki.utilities.KeyPairUtilities import org.thoughtcrime.securesms.loki.utilities.MnemonicUtilities import org.thoughtcrime.securesms.loki.utilities.push import org.thoughtcrime.securesms.loki.utilities.setUpActionBarSessionLogo -import org.thoughtcrime.securesms.util.Base64 import org.thoughtcrime.securesms.util.Hex import org.thoughtcrime.securesms.util.TextSecurePreferences -import org.whispersystems.libsignal.ecc.Curve import org.whispersystems.libsignal.util.KeyHelper import org.whispersystems.signalservice.loki.crypto.MnemonicCodec import org.whispersystems.signalservice.loki.utilities.hexEncodedPublicKey -import java.io.File -import java.io.FileOutputStream class RestoreActivity : BaseActionBarActivity() { @@ -68,13 +65,11 @@ class RestoreActivity : BaseActionBarActivity() { MnemonicUtilities.loadFileContents(this, fileName) } val hexEncodedSeed = MnemonicCodec(loadFileContents).decode(mnemonic) - var seed = Hex.fromStringCondensed(hexEncodedSeed) - IdentityKeyUtil.save(this, IdentityKeyUtil.lokiSeedKey, Hex.toStringCondensed(seed)) - if (seed.size == 16) { seed = seed + seed } - val keyPair = Curve.generateKeyPair(seed) - IdentityKeyUtil.save(this, IdentityKeyUtil.IDENTITY_PUBLIC_KEY_PREF, Base64.encodeBytes(keyPair.publicKey.serialize())) - IdentityKeyUtil.save(this, IdentityKeyUtil.IDENTITY_PRIVATE_KEY_PREF, Base64.encodeBytes(keyPair.privateKey.serialize())) - val userHexEncodedPublicKey = keyPair.hexEncodedPublicKey + val seed = Hex.fromStringCondensed(hexEncodedSeed) + val keyPairGenerationResult = KeyPairUtilities.generate(seed) + val x25519KeyPair = keyPairGenerationResult.x25519KeyPair + KeyPairUtilities.store(this, seed, keyPairGenerationResult.ed25519KeyPair, x25519KeyPair) + val userHexEncodedPublicKey = x25519KeyPair.hexEncodedPublicKey val registrationID = KeyHelper.generateRegistrationId(false) TextSecurePreferences.setLocalRegistrationId(this, registrationID) DatabaseFactory.getIdentityDatabase(this).saveIdentity(Address.fromSerialized(userHexEncodedPublicKey), diff --git a/src/org/thoughtcrime/securesms/loki/activities/SeedActivity.kt b/src/org/thoughtcrime/securesms/loki/activities/SeedActivity.kt index c91113aa98..762bf9e422 100644 --- a/src/org/thoughtcrime/securesms/loki/activities/SeedActivity.kt +++ b/src/org/thoughtcrime/securesms/loki/activities/SeedActivity.kt @@ -7,7 +7,6 @@ import android.os.Bundle import android.text.Spannable import android.text.SpannableString import android.text.style.ForegroundColorSpan -import android.util.Log import android.widget.LinearLayout import android.widget.Toast import kotlinx.android.synthetic.main.activity_seed.* @@ -19,12 +18,11 @@ import org.thoughtcrime.securesms.loki.utilities.getColorWithID import org.thoughtcrime.securesms.util.TextSecurePreferences import org.whispersystems.signalservice.loki.crypto.MnemonicCodec import org.whispersystems.signalservice.loki.utilities.hexEncodedPrivateKey -import java.io.File class SeedActivity : BaseActionBarActivity() { private val seed by lazy { - var hexEncodedSeed = IdentityKeyUtil.retrieve(this, IdentityKeyUtil.lokiSeedKey) + var hexEncodedSeed = IdentityKeyUtil.retrieve(this, IdentityKeyUtil.LOKI_SEED) if (hexEncodedSeed == null) { hexEncodedSeed = IdentityKeyUtil.getIdentityKeyPair(this).hexEncodedPrivateKey // Legacy account } diff --git a/src/org/thoughtcrime/securesms/loki/dialogs/SeedDialog.kt b/src/org/thoughtcrime/securesms/loki/dialogs/SeedDialog.kt index 097342332c..077e8529c7 100644 --- a/src/org/thoughtcrime/securesms/loki/dialogs/SeedDialog.kt +++ b/src/org/thoughtcrime/securesms/loki/dialogs/SeedDialog.kt @@ -8,7 +8,6 @@ import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle import android.view.LayoutInflater -import android.view.WindowManager import android.widget.Toast import androidx.appcompat.app.AlertDialog import androidx.fragment.app.DialogFragment @@ -23,7 +22,7 @@ import org.whispersystems.signalservice.loki.utilities.hexEncodedPrivateKey class SeedDialog : DialogFragment() { private val seed by lazy { - var hexEncodedSeed = IdentityKeyUtil.retrieve(requireContext(), IdentityKeyUtil.lokiSeedKey) + var hexEncodedSeed = IdentityKeyUtil.retrieve(requireContext(), IdentityKeyUtil.LOKI_SEED) if (hexEncodedSeed == null) { hexEncodedSeed = IdentityKeyUtil.getIdentityKeyPair(requireContext()).hexEncodedPrivateKey // Legacy account } diff --git a/src/org/thoughtcrime/securesms/loki/utilities/KeyPairUtilities.kt b/src/org/thoughtcrime/securesms/loki/utilities/KeyPairUtilities.kt new file mode 100644 index 0000000000..0f8cc44c33 --- /dev/null +++ b/src/org/thoughtcrime/securesms/loki/utilities/KeyPairUtilities.kt @@ -0,0 +1,48 @@ +package org.thoughtcrime.securesms.loki.utilities + +import android.content.Context +import com.goterl.lazycode.lazysodium.LazySodiumAndroid +import com.goterl.lazycode.lazysodium.SodiumAndroid +import com.goterl.lazycode.lazysodium.utils.KeyPair +import org.thoughtcrime.securesms.crypto.IdentityKeyUtil +import org.thoughtcrime.securesms.util.Base64 +import org.thoughtcrime.securesms.util.Hex +import org.whispersystems.curve25519.Curve25519 +import org.whispersystems.libsignal.ecc.DjbECPrivateKey +import org.whispersystems.libsignal.ecc.DjbECPublicKey +import org.whispersystems.libsignal.ecc.ECKeyPair + +object KeyPairUtilities { + + data class KeyPairGenerationResult( + val seed: ByteArray, + val ed25519KeyPair: KeyPair, + val x25519KeyPair: ECKeyPair + ) + + fun generate(): KeyPairGenerationResult { + val seed = Curve25519.getInstance(Curve25519.BEST).generateSeed(16) + try { + return generate(seed) + } catch (exception: Exception) { + return generate() + } + } + + fun generate(seed: ByteArray): KeyPairGenerationResult { + val sodium = LazySodiumAndroid(SodiumAndroid()) + val padding = ByteArray(16) { 0 } + val ed25519KeyPair = sodium.cryptoSignSeedKeypair(seed + padding) + val sodiumX25519KeyPair = sodium.convertKeyPairEd25519ToCurve25519(ed25519KeyPair) + val x25519KeyPair = ECKeyPair(DjbECPublicKey(sodiumX25519KeyPair.publicKey.asBytes), DjbECPrivateKey(sodiumX25519KeyPair.secretKey.asBytes)) + return KeyPairGenerationResult(seed, ed25519KeyPair, x25519KeyPair) + } + + fun store(context: Context, seed: ByteArray, ed25519KeyPair: KeyPair, x25519KeyPair: ECKeyPair) { + IdentityKeyUtil.save(context, IdentityKeyUtil.LOKI_SEED, Hex.toStringCondensed(seed)) + IdentityKeyUtil.save(context, IdentityKeyUtil.IDENTITY_PUBLIC_KEY_PREF, Base64.encodeBytes(x25519KeyPair.publicKey.serialize())) + IdentityKeyUtil.save(context, IdentityKeyUtil.IDENTITY_PRIVATE_KEY_PREF, Base64.encodeBytes(x25519KeyPair.privateKey.serialize())) + IdentityKeyUtil.save(context, IdentityKeyUtil.ED25519_PUBLIC_KEY, Base64.encodeBytes(ed25519KeyPair.publicKey.asBytes)) + IdentityKeyUtil.save(context, IdentityKeyUtil.ED25519_SECRET_KEY, Base64.encodeBytes(ed25519KeyPair.secretKey.asBytes)) + } +} \ No newline at end of file