feat: upgrade to keystore sealed identity key preferences

This commit is contained in:
Harris 2021-06-07 11:53:17 +10:00
parent 3bf5a50439
commit 91aefb7c87
15 changed files with 96 additions and 45 deletions

View File

@ -27,6 +27,7 @@ import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.ProcessLifecycleOwner;
import androidx.multidex.MultiDexApplication;
import org.conscrypt.Conscrypt;
import org.session.libsession.avatars.AvatarHelper;
import org.session.libsession.messaging.MessagingModuleConfiguration;
@ -47,6 +48,7 @@ import org.session.libsignal.utilities.Log;
import org.session.libsignal.utilities.ThreadUtils;
import org.signal.aesgcmprovider.AesGcmProvider;
import org.thoughtcrime.securesms.components.TypingStatusSender;
import org.thoughtcrime.securesms.crypto.KeyPairUtilities;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.dependencies.InjectableType;
import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule;
@ -84,12 +86,14 @@ import org.webrtc.PeerConnectionFactory;
import org.webrtc.PeerConnectionFactory.InitializationOptions;
import org.webrtc.voiceengine.WebRtcAudioManager;
import org.webrtc.voiceengine.WebRtcAudioUtils;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.security.Security;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import dagger.ObjectGraph;
import kotlin.Unit;
import kotlinx.coroutines.Job;
@ -154,8 +158,10 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
conversationListNotificationHandler = new Handler(Looper.getMainLooper());
LokiAPIDatabase apiDB = DatabaseFactory.getLokiAPIDatabase(this);
MessagingModuleConfiguration.Companion.configure(this,
DatabaseFactory.getStorage(this),
DatabaseFactory.getAttachmentProvider(this));
DatabaseFactory.getStorage(this),
DatabaseFactory.getAttachmentProvider(this),
()-> KeyPairUtilities.INSTANCE.getUserED25519KeyPair(this)
);
SnodeModule.Companion.configure(apiDB, broadcaster);
String userPublicKey = TextSecurePreferences.getLocalNumber(this);
if (userPublicKey != null) {

View File

@ -15,21 +15,22 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.session.libsession.utilities;
package org.thoughtcrime.securesms.crypto;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Build;
import androidx.annotation.NonNull;
import org.session.libsignal.crypto.ecc.ECPublicKey;
import org.session.libsignal.crypto.IdentityKey;
import org.session.libsignal.crypto.IdentityKeyPair;
import org.session.libsignal.exceptions.InvalidKeyException;
import org.session.libsignal.crypto.ecc.Curve;
import org.session.libsignal.crypto.ecc.ECKeyPair;
import org.session.libsignal.crypto.ecc.ECPrivateKey;
import org.session.libsignal.crypto.ecc.ECPublicKey;
import org.session.libsignal.exceptions.InvalidKeyException;
import org.session.libsignal.utilities.Base64;
import java.io.IOException;
@ -45,6 +46,7 @@ public class IdentityKeyUtil {
@SuppressWarnings("unused")
private static final String TAG = IdentityKeyUtil.class.getSimpleName();
private static final String ENCRYPTED_SUFFIX = "_encrypted";
public static final String IDENTITY_PUBLIC_KEY_PREF = "pref_identity_public_v3";
public static final String IDENTITY_PRIVATE_KEY_PREF = "pref_identity_private_v3";
@ -56,8 +58,10 @@ public class IdentityKeyUtil {
SharedPreferences preferences = context.getSharedPreferences(MASTER_SECRET_UTIL_PREFERENCES_NAME, 0);
return
preferences.contains(IDENTITY_PUBLIC_KEY_PREF) &&
preferences.contains(IDENTITY_PRIVATE_KEY_PREF);
(preferences.contains(IDENTITY_PUBLIC_KEY_PREF) &&
preferences.contains(IDENTITY_PRIVATE_KEY_PREF))
|| (preferences.contains(IDENTITY_PUBLIC_KEY_PREF+ENCRYPTED_SUFFIX) &&
preferences.contains(IDENTITY_PRIVATE_KEY_PREF+ENCRYPTED_SUFFIX));
}
public static @NonNull IdentityKey getIdentityKey(@NonNull Context context) {
@ -94,14 +98,51 @@ public class IdentityKeyUtil {
public static String retrieve(Context context, String key) {
SharedPreferences preferences = context.getSharedPreferences(MASTER_SECRET_UTIL_PREFERENCES_NAME, 0);
return preferences.getString(key, null);
String unencryptedSecret = preferences.getString(key, null);
String encryptedSecret = preferences.getString(key+ENCRYPTED_SUFFIX, null);
if (unencryptedSecret != null) return getUnencryptedSecret(key, unencryptedSecret, context);
else if (encryptedSecret != null) return getEncryptedSecret(encryptedSecret);
return null;
}
private static String getUnencryptedSecret(String key, String unencryptedSecret, Context context) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return unencryptedSecret;
} else {
KeyStoreHelper.SealedData encryptedSecret = KeyStoreHelper.seal(unencryptedSecret.getBytes());
// save the encrypted suffix secret "key_encrypted"
save(context,key+ENCRYPTED_SUFFIX,encryptedSecret.serialize());
// delete the regular secret "key"
delete(context,key);
return unencryptedSecret;
}
}
private static String getEncryptedSecret(String encryptedSecret) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
throw new AssertionError("OS downgrade not supported. KeyStore sealed data exists on platform < M!");
} else {
KeyStoreHelper.SealedData sealedData = KeyStoreHelper.SealedData.fromString(encryptedSecret);
return new String(KeyStoreHelper.unseal(sealedData));
}
}
public static void save(Context context, String key, String value) {
SharedPreferences preferences = context.getSharedPreferences(MASTER_SECRET_UTIL_PREFERENCES_NAME, 0);
Editor preferencesEditor = preferences.edit();
preferencesEditor.putString(key, value);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
KeyStoreHelper.SealedData encryptedSecret = KeyStoreHelper.seal(value.getBytes());
preferencesEditor.putString(key+ENCRYPTED_SUFFIX, encryptedSecret.serialize());
} else {
preferencesEditor.putString(key, value);
}
if (!preferencesEditor.commit()) throw new AssertionError("failed to save identity key/value to shared preferences");
}

View File

@ -1,4 +1,4 @@
package org.session.libsession.utilities
package org.thoughtcrime.securesms.crypto
import android.content.Context
import com.goterl.lazysodium.LazySodiumAndroid

View File

@ -1,6 +1,5 @@
package org.thoughtcrime.securesms.database
import android.app.job.JobScheduler
import android.content.Context
import android.net.Uri
import org.session.libsession.database.StorageProtocol
@ -27,6 +26,7 @@ import org.session.libsignal.messages.SignalServiceGroup
import org.session.libsignal.utilities.KeyHelper
import org.session.libsignal.utilities.guava.Optional
import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
import org.thoughtcrime.securesms.jobs.RetrieveProfileAvatarJob
import org.thoughtcrime.securesms.loki.api.OpenGroupManager

View File

@ -4,16 +4,15 @@ import android.content.Intent
import android.os.Bundle
import android.view.View
import network.loki.messenger.R
import org.session.libsession.utilities.TextSecurePreferences
import org.thoughtcrime.securesms.BaseActionBarActivity
import org.session.libsession.utilities.IdentityKeyUtil
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
import org.thoughtcrime.securesms.loki.utilities.push
import org.thoughtcrime.securesms.loki.utilities.setUpActionBarSessionLogo
import org.thoughtcrime.securesms.loki.views.FakeChatView
import org.thoughtcrime.securesms.service.KeyCachingService
import org.thoughtcrime.securesms.util.Util
import org.session.libsession.utilities.TextSecurePreferences
class LandingActivity : BaseActionBarActivity() {
override fun onCreate(savedInstanceState: Bundle?) {

View File

@ -23,16 +23,16 @@ import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.launch
import network.loki.messenger.R
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsignal.utilities.KeyHelper
import org.session.libsignal.crypto.MnemonicCodec
import org.session.libsignal.utilities.hexEncodedPublicKey
import org.session.libsignal.utilities.Hex
import org.session.libsignal.utilities.KeyHelper
import org.session.libsignal.utilities.Log
import org.session.libsignal.utilities.hexEncodedPublicKey
import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.BaseActionBarActivity
import org.thoughtcrime.securesms.crypto.KeyPairUtilities
import org.thoughtcrime.securesms.loki.fragments.ScanQRCodeWrapperFragment
import org.thoughtcrime.securesms.loki.fragments.ScanQRCodeWrapperFragmentDelegate
import org.session.libsession.utilities.KeyPairUtilities
import org.thoughtcrime.securesms.loki.utilities.MnemonicUtilities
import org.thoughtcrime.securesms.loki.utilities.push
import org.thoughtcrime.securesms.loki.utilities.setUpActionBarSessionLogo

View File

@ -14,12 +14,12 @@ import android.widget.Toast
import kotlinx.android.synthetic.main.activity_recovery_phrase_restore.*
import network.loki.messenger.R
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsignal.utilities.KeyHelper
import org.session.libsignal.crypto.MnemonicCodec
import org.session.libsignal.utilities.hexEncodedPublicKey
import org.session.libsignal.utilities.Hex
import org.session.libsignal.utilities.KeyHelper
import org.session.libsignal.utilities.hexEncodedPublicKey
import org.thoughtcrime.securesms.BaseActionBarActivity
import org.session.libsession.utilities.KeyPairUtilities
import org.thoughtcrime.securesms.crypto.KeyPairUtilities
import org.thoughtcrime.securesms.loki.utilities.MnemonicUtilities
import org.thoughtcrime.securesms.loki.utilities.push
import org.thoughtcrime.securesms.loki.utilities.setUpActionBarSessionLogo

View File

@ -18,12 +18,12 @@ import android.widget.Toast
import com.goterl.lazysodium.utils.KeyPair
import kotlinx.android.synthetic.main.activity_register.*
import network.loki.messenger.R
import org.session.libsession.utilities.KeyPairUtilities
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsignal.crypto.ecc.ECKeyPair
import org.session.libsignal.utilities.KeyHelper
import org.session.libsignal.utilities.hexEncodedPublicKey
import org.thoughtcrime.securesms.BaseActionBarActivity
import org.thoughtcrime.securesms.crypto.KeyPairUtilities
import org.thoughtcrime.securesms.loki.utilities.push
import org.thoughtcrime.securesms.loki.utilities.setUpActionBarSessionLogo
import java.util.*

View File

@ -11,13 +11,13 @@ import android.widget.LinearLayout
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_seed.*
import network.loki.messenger.R
import org.thoughtcrime.securesms.BaseActionBarActivity
import org.session.libsession.utilities.IdentityKeyUtil
import org.thoughtcrime.securesms.loki.utilities.MnemonicUtilities
import org.thoughtcrime.securesms.loki.utilities.getColorWithID
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsignal.crypto.MnemonicCodec
import org.session.libsignal.utilities.hexEncodedPrivateKey
import org.thoughtcrime.securesms.BaseActionBarActivity
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
import org.thoughtcrime.securesms.loki.utilities.MnemonicUtilities
import org.thoughtcrime.securesms.loki.utilities.getColorWithID
class SeedActivity : BaseActionBarActivity() {

View File

@ -2,22 +2,25 @@ package org.thoughtcrime.securesms.loki.database
import android.content.ContentValues
import android.content.Context
import org.session.libsession.utilities.IdentityKeyUtil
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsignal.crypto.ecc.DjbECPrivateKey
import org.session.libsignal.crypto.ecc.DjbECPublicKey
import org.session.libsignal.crypto.ecc.ECKeyPair
import org.session.libsignal.utilities.Snode
import org.session.libsignal.database.LokiAPIDatabaseProtocol
import org.session.libsignal.utilities.PublicKeyValidation
import org.session.libsignal.utilities.removing05PrefixIfNeeded
import org.session.libsignal.utilities.toHexString
import org.session.libsignal.utilities.Hex
import org.session.libsignal.utilities.Log
import org.session.libsignal.utilities.*
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
import org.thoughtcrime.securesms.database.Database
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
import org.thoughtcrime.securesms.loki.utilities.*
import java.util.*
import kotlin.Array
import kotlin.Boolean
import kotlin.Int
import kotlin.Long
import kotlin.Pair
import kotlin.String
import kotlin.arrayOf
import kotlin.to
class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), LokiAPIDatabaseProtocol {

View File

@ -4,14 +4,14 @@ import android.app.Dialog
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import androidx.fragment.app.DialogFragment
import androidx.appcompat.app.AlertDialog
import android.view.LayoutInflater
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.DialogFragment
import kotlinx.android.synthetic.main.dialog_clear_all_data.view.*
import network.loki.messenger.R
import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.crypto.KeyPairUtilities
import org.thoughtcrime.securesms.loki.protocol.MultiDeviceProtocol
import org.session.libsession.utilities.KeyPairUtilities
class ClearAllDataDialog : DialogFragment() {

View File

@ -13,10 +13,10 @@ import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.DialogFragment
import kotlinx.android.synthetic.main.dialog_seed.view.*
import network.loki.messenger.R
import org.session.libsession.utilities.IdentityKeyUtil
import org.thoughtcrime.securesms.loki.utilities.MnemonicUtilities
import org.session.libsignal.crypto.MnemonicCodec
import org.session.libsignal.utilities.hexEncodedPrivateKey
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
import org.thoughtcrime.securesms.loki.utilities.MnemonicUtilities
class SeedDialog : DialogFragment() {

View File

@ -21,7 +21,7 @@ import org.thoughtcrime.securesms.backup.BackupPassphrase
import org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference
import org.thoughtcrime.securesms.backup.FullBackupExporter
import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider
import org.session.libsession.utilities.IdentityKeyUtil
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.loki.database.BackupFileRecord
import org.thoughtcrime.securesms.service.LocalBackupListener

View File

@ -1,24 +1,27 @@
package org.session.libsession.messaging
import android.content.Context
import com.goterl.lazysodium.utils.KeyPair
import org.session.libsession.database.MessageDataProvider
import org.session.libsession.database.StorageProtocol
class MessagingModuleConfiguration(
val context: Context,
val storage: StorageProtocol,
val messageDataProvider: MessageDataProvider
val messageDataProvider: MessageDataProvider,
val keyPairProvider: ()-> KeyPair?
) {
companion object {
lateinit var shared: MessagingModuleConfiguration
fun configure(context: Context,
storage: StorageProtocol,
messageDataProvider: MessageDataProvider
storage: StorageProtocol,
messageDataProvider: MessageDataProvider,
keyPairProvider: () -> KeyPair?
) {
if (Companion::shared.isInitialized) { return }
shared = MessagingModuleConfiguration(context, storage, messageDataProvider)
shared = MessagingModuleConfiguration(context, storage, messageDataProvider, keyPairProvider)
}
}
}

View File

@ -6,7 +6,6 @@ import com.goterl.lazysodium.interfaces.Box
import com.goterl.lazysodium.interfaces.Sign
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.sending_receiving.MessageSender.Error
import org.session.libsession.utilities.KeyPairUtilities
import org.session.libsignal.utilities.Hex
import org.session.libsignal.utilities.Log
import org.session.libsignal.utilities.removing05PrefixIfNeeded
@ -25,7 +24,7 @@ object MessageEncrypter {
*/
internal fun encrypt(plaintext: ByteArray, recipientHexEncodedX25519PublicKey: String): ByteArray{
val context = MessagingModuleConfiguration.shared.context
val userED25519KeyPair = KeyPairUtilities.getUserED25519KeyPair(context) ?: throw Error.NoUserED25519KeyPair
val userED25519KeyPair = MessagingModuleConfiguration.shared.keyPairProvider() ?: throw Error.NoUserED25519KeyPair
val recipientX25519PublicKey = Hex.fromStringCondensed(recipientHexEncodedX25519PublicKey.removing05PrefixIfNeeded())
val verificationData = plaintext + userED25519KeyPair.publicKey.asBytes + recipientX25519PublicKey