it-swarm.com.de

Was ist der beste Weg, um Benutzereinstellungen in einer Android-Anwendung zu speichern

Ich erstelle eine Anwendung, die über Benutzername/Kennwort eine Verbindung zum Server herstellt, und möchte die Option "Kennwort speichern" aktivieren, damit der Benutzer das Kennwort nicht jedes Mal eingeben muss, wenn die Anwendung gestartet wird.

Ich habe versucht, dies mit den gemeinsamen Einstellungen zu tun, bin mir aber nicht sicher, ob dies die beste Lösung ist.

Ich würde mich über jeden Vorschlag freuen, wie Benutzerwerte/Einstellungen in der Android-Anwendung gespeichert werden können.

291
Niko Gamulin

Im Allgemeinen ist SharedPreferences die beste Wahl, um Präferenzen zu speichern. Im Allgemeinen empfehle ich diesen Ansatz zum Speichern von Anwendungs- und Benutzereinstellungen.

Das einzige Problem, das Sie hier beachten, ist das, was Sie sparen. Passwörter sind immer eine knifflige Angelegenheit, und es wäre besonders wichtig, sie als Klartext zu speichern. Die Android-Architektur ist so ausgelegt, dass die SharedPreferences Ihrer Anwendung in einer Sandbox ausgeführt werden, um zu verhindern, dass andere Anwendungen auf die Werte zugreifen können. Es gibt also eine gewisse Sicherheit, aber der physische Zugriff auf ein Telefon kann möglicherweise den Zugriff auf die Werte ermöglichen.

Wenn möglich, würde ich in Betracht ziehen, den Server so zu ändern, dass ein ausgehandeltes Token für die Bereitstellung des Zugriffs verwendet wird, z. B. OAuth . Alternativ müssen Sie möglicherweise einen kryptografischen Speicher erstellen, der jedoch nicht trivial ist. Vergewissern Sie sich zumindest, dass Sie das Kennwort verschlüsseln, bevor Sie es auf die Festplatte schreiben.

226
Reto Meier

Ich stimme Reto und FiXedd zu. Objektiv gesehen macht es nicht viel Sinn, viel Zeit und Mühe in die Verschlüsselung von Passwörtern in SharedPreferences zu investieren, da ein Angreifer, der Zugriff auf Ihre Voreinstellungsdatei hat, mit großer Wahrscheinlichkeit auch Zugriff auf die Binärdatei Ihrer Anwendung hat und somit die Schlüssel zum Entschlüsseln der Passwort.

Allerdings scheint es eine Publicity-Initiative zu geben, die mobile Anwendungen identifiziert, die ihre Passwörter im Klartext in SharedPreferences speichern und diese Anwendungen ungünstig beleuchten. Siehe http://blogs.wsj.com/digits/2011/06/08/some-top-apps-put-data-at-risk/ und http://viaforensics.com/appwatchdog für einige Beispiele. 

Wir brauchen zwar mehr Aufmerksamkeit für die Sicherheit im Allgemeinen, aber ich würde behaupten, dass diese Art von Aufmerksamkeit zu diesem speziellen Thema unsere Sicherheit insgesamt nicht wesentlich erhöht. Die Wahrnehmung ist jedoch so, wie sie ist. Hier finden Sie eine Lösung zum Verschlüsseln der Daten, die Sie in SharedPreferences ablegen.

Wickeln Sie einfach Ihr eigenes SharedPreferences-Objekt in dieses ein, und alle Daten, die Sie lesen/schreiben, werden automatisch verschlüsselt und entschlüsselt. z.B.

final SharedPreferences prefs = new ObscuredSharedPreferences( 
    this, this.getSharedPreferences(MY_PREFS_FILE_NAME, Context.MODE_PRIVATE) );

// eg.    
prefs.edit().putString("foo","bar").commit();
prefs.getString("foo", null);

Hier ist der Code für die Klasse:

/**
 * Warning, this gives a false sense of security.  If an attacker has enough access to
 * acquire your password store, then he almost certainly has enough access to acquire your
 * source binary and figure out your encryption key.  However, it will prevent casual
 * investigators from acquiring passwords, and thereby may prevent undesired negative
 * publicity.
 */
public class ObscuredSharedPreferences implements SharedPreferences {
    protected static final String UTF8 = "utf-8";
    private static final char[] SEKRIT = ... ; // INSERT A RANDOM PASSWORD HERE.
                                               // Don't use anything you wouldn't want to
                                               // get out there if someone decompiled
                                               // your app.


    protected SharedPreferences delegate;
    protected Context context;

    public ObscuredSharedPreferences(Context context, SharedPreferences delegate) {
        this.delegate = delegate;
        this.context = context;
    }

    public class Editor implements SharedPreferences.Editor {
        protected SharedPreferences.Editor delegate;

        public Editor() {
            this.delegate = ObscuredSharedPreferences.this.delegate.edit();                    
        }

        @Override
        public Editor putBoolean(String key, boolean value) {
            delegate.putString(key, encrypt(Boolean.toString(value)));
            return this;
        }

        @Override
        public Editor putFloat(String key, float value) {
            delegate.putString(key, encrypt(Float.toString(value)));
            return this;
        }

        @Override
        public Editor putInt(String key, int value) {
            delegate.putString(key, encrypt(Integer.toString(value)));
            return this;
        }

        @Override
        public Editor putLong(String key, long value) {
            delegate.putString(key, encrypt(Long.toString(value)));
            return this;
        }

        @Override
        public Editor putString(String key, String value) {
            delegate.putString(key, encrypt(value));
            return this;
        }

        @Override
        public void apply() {
            delegate.apply();
        }

        @Override
        public Editor clear() {
            delegate.clear();
            return this;
        }

        @Override
        public boolean commit() {
            return delegate.commit();
        }

        @Override
        public Editor remove(String s) {
            delegate.remove(s);
            return this;
        }
    }

    public Editor edit() {
        return new Editor();
    }


    @Override
    public Map<String, ?> getAll() {
        throw new UnsupportedOperationException(); // left as an exercise to the reader
    }

    @Override
    public boolean getBoolean(String key, boolean defValue) {
        final String v = delegate.getString(key, null);
        return v!=null ? Boolean.parseBoolean(decrypt(v)) : defValue;
    }

    @Override
    public float getFloat(String key, float defValue) {
        final String v = delegate.getString(key, null);
        return v!=null ? Float.parseFloat(decrypt(v)) : defValue;
    }

    @Override
    public int getInt(String key, int defValue) {
        final String v = delegate.getString(key, null);
        return v!=null ? Integer.parseInt(decrypt(v)) : defValue;
    }

    @Override
    public long getLong(String key, long defValue) {
        final String v = delegate.getString(key, null);
        return v!=null ? Long.parseLong(decrypt(v)) : defValue;
    }

    @Override
    public String getString(String key, String defValue) {
        final String v = delegate.getString(key, null);
        return v != null ? decrypt(v) : defValue;
    }

    @Override
    public boolean contains(String s) {
        return delegate.contains(s);
    }

    @Override
    public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener onSharedPreferenceChangeListener) {
        delegate.registerOnSharedPreferenceChangeListener(onSharedPreferenceChangeListener);
    }

    @Override
    public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener onSharedPreferenceChangeListener) {
        delegate.unregisterOnSharedPreferenceChangeListener(onSharedPreferenceChangeListener);
    }




    protected String encrypt( String value ) {

        try {
            final byte[] bytes = value!=null ? value.getBytes(UTF8) : new byte[0];
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
            SecretKey key = keyFactory.generateSecret(new PBEKeySpec(SEKRIT));
            Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
            pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(Settings.Secure.getString(context.getContentResolver(),Settings.Secure.Android_ID).getBytes(UTF8), 20));
            return new String(Base64.encode(pbeCipher.doFinal(bytes), Base64.NO_WRAP),UTF8);

        } catch( Exception e ) {
            throw new RuntimeException(e);
        }

    }

    protected String decrypt(String value){
        try {
            final byte[] bytes = value!=null ? Base64.decode(value,Base64.DEFAULT) : new byte[0];
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
            SecretKey key = keyFactory.generateSecret(new PBEKeySpec(SEKRIT));
            Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
            pbeCipher.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec(Settings.Secure.getString(context.getContentResolver(),Settings.Secure.Android_ID).getBytes(UTF8), 20));
            return new String(pbeCipher.doFinal(bytes),UTF8);

        } catch( Exception e) {
            throw new RuntimeException(e);
        }
    }

}
204
emmby

Die einfachste Methode zum Speichern einer einzelnen Präferenz in einer Android-Aktivität besteht darin, Folgendes zu tun:

Editor e = this.getPreferences(Context.MODE_PRIVATE).edit();
e.putString("password", mPassword);
e.commit();

Wenn Sie sich Sorgen um die Sicherheit machen, können Sie das Kennwort vor dem Speichern immer verschlüsseln.

28
Jeremy Logan

Mit dem von Richard bereitgestellten Snippet können Sie das Kennwort verschlüsseln, bevor Sie es speichern. Die Preferences-API bietet jedoch keine einfache Möglichkeit, den Wert abzufangen und zu verschlüsseln. Sie können das Speichern über einen OnPreferenceChange-Listener sperren. Sie können ihn theoretisch über einen PreferenceChangeListener ändern. Dies führt jedoch zu einer Endlosschleife.

Ich hatte zuvor vorgeschlagen, eine "versteckte" Präferenz hinzuzufügen, um dies zu erreichen. Es ist definitiv nicht der beste Weg. Ich werde zwei weitere Optionen vorstellen, die ich für praktikabler halte. 

Am einfachsten ist es in einem PreferenceChangeListener. Sie können den eingegebenen Wert abrufen, verschlüsseln und dann in einer alternativen Voreinstellungsdatei speichern:

  public boolean onPreferenceChange(Preference preference, Object newValue) {
      // get our "secure" shared preferences file.
      SharedPreferences secure = context.getSharedPreferences(
         "SECURE",
         Context.MODE_PRIVATE
      );
      String encryptedText = null;
      // encrypt and set the preference.
      try {
         encryptedText = SimpleCrypto.encrypt(Preferences.SEED,(String)newValue);

         Editor editor = secure.getEditor();
         editor.putString("encryptedPassword",encryptedText);
         editor.commit();
      }
      catch (Exception e) {
         e.printStackTrace();
      }
      // always return false.
      return false; 
   }

Die zweite Art und Weise, die ich jetzt vorziehen möchte, besteht darin, Ihre eigenen benutzerdefinierten Einstellungen zu erstellen, indem Sie EditTextPreference erweitern, @ die Methoden setText() und getText() überschreiben, sodass setText() das Kennwort verschlüsselt und getText() null zurückgibt.

9
Mark

Ich weiß, das ist ein bisschen Nekromantie, aber Sie sollten den Android AccountManager verwenden. Es wurde speziell für dieses Szenario entwickelt. Dies ist zwar etwas umständlich, aber die lokalen Anmeldeinformationen werden ungültig, wenn sich die SIM-Karte ändert. Wenn also jemand Ihr Telefon überfällt und eine neue SIM-Karte in den SIM-Speicher wirft, werden Ihre Anmeldeinformationen nicht beeinträchtigt.

Dies gibt dem Benutzer auch eine schnelle und einfache Möglichkeit, auf die gespeicherten Anmeldeinformationen für jedes Konto, das er auf dem Gerät hat, von einem Ort aus zuzugreifen (und möglicherweise zu löschen).

SampleSyncAdapter ist ein Beispiel, das gespeicherte Kontoanmeldeinformationen verwendet.

5
Jon O

Okay; Es ist eine Weile her, seit die Antwort irgendwie gemischt ist, aber hier sind ein paar allgemeine Antworten. Ich habe das wie verrückt recherchiert und es war schwer eine gute Antwort zu finden

  1. Die Methode MODE_PRIVATE wird allgemein als sicher angesehen, wenn Sie davon ausgehen, dass der Benutzer das Gerät nicht als Root-Benutzer angemeldet hat. Ihre Daten werden in Klartext in einem Teil des Dateisystems gespeichert, auf den nur das Originalprogramm zugreifen kann. Dies macht es einfach, das Passwort mit einer anderen App auf einem gerooteten Gerät zu packen. Möchten Sie auch gerootete Geräte unterstützen?

  2. AES ist immer noch die beste Verschlüsselung, die Sie tun können. Denken Sie daran, dies nachzuschlagen, wenn Sie eine neue Implementierung starten, wenn seit dieser Zeit eine Weile vergangen ist. Das größte Problem dabei ist "Was tun mit dem Verschlüsselungsschlüssel?"

Jetzt sind wir bei "Was tun mit dem Schlüssel?" Portion. Das ist der schwierige Teil. Den Schlüssel zu bekommen stellt sich als nicht so schlimm heraus. Sie können eine Schlüsselableitungsfunktion verwenden, um ein Kennwort zu erhalten und es zu einem ziemlich sicheren Schlüssel zu machen. Sie stoßen auf Fragen wie "Wie viele Pässe machen Sie mit PKFDF2?", Aber das ist ein anderes Thema

  1. Idealerweise speichern Sie die AES-Taste vom Gerät. Sie müssen einen guten Weg finden, um den Schlüssel sicher, zuverlässig und sicher vom Server abzurufen

  2. Sie haben eine Anmeldesequenz (sogar die ursprüngliche Anmeldesequenz für den Fernzugriff). Sie können Ihren Schlüsselgenerator zwei Mal mit demselben Passwort ausführen. Wie dies funktioniert, ist, dass Sie den Schlüssel zweimal mit einem neuen Salt und einem neuen sicheren Initialisierungsvektor ableiten. Sie speichern eines dieser generierten Kennwörter auf dem Gerät und verwenden das zweite Kennwort als AES-Schlüssel.

Wenn Sie sich anmelden, leiten Sie den Schlüssel für das lokale Login erneut ab und vergleichen ihn mit dem gespeicherten Schlüssel. Sobald dies erledigt ist, verwenden Sie den Ableitungsschlüssel Nr. 2 für AES.

  1. Mit dem "generell sicheren" Ansatz verschlüsseln Sie die Daten mit AES und speichern den Schlüssel in MODE_PRIVATE. Dies wird von einem kürzlich veröffentlichten Android-Blogbeitrag empfohlen. Nicht unglaublich sicher, aber für manche Leute viel besser als einfacher Text

Sie können viele Variationen davon machen. Anstelle einer vollständigen Anmeldesequenz können Sie beispielsweise eine schnelle PIN (abgeleitet) durchführen. Die schnelle PIN ist möglicherweise nicht so sicher wie eine vollständige Anmeldesequenz, jedoch um ein Vielfaches sicherer als normaler Text

5
Joe Plante

Ich werde meinen Hut in den Ring werfen, nur um über das Sichern von Passwörtern auf Android zu sprechen. Unter Android sollte das binäre Gerät als gefährdet betrachtet werden - dies gilt auch für Endanwendungen, die direkt vom Benutzer gesteuert werden. Konzeptionell könnte ein Hacker den erforderlichen Zugriff auf die Binärdatei verwenden, um sie zu dekompilieren und Ihre verschlüsselten Kennwörter usw. zu entfernen.

Daher gibt es zwei Vorschläge, die ich Ihnen gerne mitteilen möchte, wenn Sicherheit für Sie ein wichtiges Anliegen ist:

1) Speichern Sie nicht das eigentliche Passwort. Speichern Sie ein gewährtes Zugriffstoken und authentifizieren Sie die Sitzungsserverseite mit dem Zugriffstoken und der Signatur des Telefons. Dies hat den Vorteil, dass das Token eine begrenzte Dauer haben kann, Sie das ursprüngliche Kennwort nicht beeinträchtigen und über eine gute Signatur verfügen, die Sie später für den Datenverkehr verwenden können (z. B. um Eindringungsversuche zu prüfen und das Kennwort zu deaktivieren Token macht es nutzlos).

2) Verwenden Sie die 2-Faktor-Authentifizierung. Dies kann ärgerlicher und aufdringlicher sein, aber für einige Compliance-Situationen ist dies unvermeidbar.

5
dcgregorya

Sie können auch diese kleine Bibliothek mit der von Ihnen erwähnten Funktionalität auschecken.

https://github.com/kovmarci86/Android-secure-preferences

Es ist ähnlich wie bei einigen anderen Ansätzen. Hoffnung hilft :)

2
Marcell

Dies ist eine ergänzende Antwort für diejenigen, die hier ankommen, basierend auf dem Fragetitel (wie ich) und muss sich nicht mit den Sicherheitsproblemen im Zusammenhang mit dem Speichern von Passwörtern befassen.

So verwenden Sie die gemeinsamen Einstellungen

Benutzereinstellungen werden in der Regel lokal in Android mit SharedPreferences mit einem Schlüssel-Wert-Paar gespeichert. Sie verwenden die String-Taste, um den zugehörigen Wert zu speichern oder nachzuschlagen.

Schreiben Sie in die gemeinsamen Einstellungen

String key = "myInt";
int valueToSave = 10;

SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putInt(key, valueToSave).commit();

Verwenden Sie apply() anstelle von commit(), um nicht sofort, sondern im Hintergrund zu speichern.

Lesen Sie aus den gemeinsamen Einstellungen

String key = "myInt";
int defaultValue = 0;

SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
int savedValue = sharedPref.getInt(key, defaultValue);

Der Standardwert wird verwendet, wenn der Schlüssel nicht gefunden wird.

Anmerkungen

  • Anstatt einen lokalen Schlüssel String an mehreren Stellen zu verwenden, wie ich es oben tat, ist es besser, eine Konstante an einem einzigen Ort zu verwenden. Sie könnten so etwas wie oben in Ihren Einstellungen verwenden:

    final static String PREF_MY_INT_KEY = "myInt";
    
  • Ich habe in meinem Beispiel eine int verwendet, aber Sie können auch putString(), putBoolean(), getString(), getBoolean() usw. verwenden.

  • Siehe Dokumentation für weitere Details.
  • Es gibt mehrere Möglichkeiten, SharedPreferences abzurufen. Siehe diese Antwort , worauf Sie achten müssen.
2
Suragch

Diese Antwort basiert auf einem Vorschlag von Mark. Eine benutzerdefinierte Version der EditTextPreference-Klasse wird erstellt, die zwischen dem in der Ansicht angezeigten Nur-Text und einer verschlüsselten Version des im Voreinstellungsspeicher gespeicherten Kennworts hin und her konvertiert. 

Wie von den meisten Befragten, die in diesem Thread geantwortet haben, darauf hingewiesen wurde, handelt es sich hierbei nicht um eine sehr sichere Technik, obwohl der Sicherheitsgrad zum Teil von dem verwendeten Verschlüsselungs-/Entschlüsselungscode abhängt. Aber es ist ziemlich einfach und bequem und wird das lässigste Schnuppern vereiteln. 

Hier ist der Code für die benutzerdefinierte EditTextPreference-Klasse:

package com.Merlinia.OutBack_Client;

import Android.content.Context;
import Android.preference.EditTextPreference;
import Android.util.AttributeSet;
import Android.util.Base64;

import com.Merlinia.MEncryption_Main.MEncryptionUserPassword;


/**
 * This class extends the EditTextPreference view, providing encryption and decryption services for
 * OutBack user passwords. The passwords in the preferences store are first encrypted using the
 * MEncryption classes and then converted to string using Base64 since the preferences store can not
 * store byte arrays.
 *
 * This is largely copied from this article, except for the encryption/decryption parts:
 * https://groups.google.com/forum/#!topic/Android-developers/pMYNEVXMa6M
 */
public class EditPasswordPreference  extends EditTextPreference {

    // Constructor - needed despite what compiler says, otherwise app crashes
    public EditPasswordPreference(Context context) {
        super(context);
    }


    // Constructor - needed despite what compiler says, otherwise app crashes
    public EditPasswordPreference(Context context, AttributeSet attributeSet) {
        super(context, attributeSet);
    }


    // Constructor - needed despite what compiler says, otherwise app crashes
    public EditPasswordPreference(Context context, AttributeSet attributeSet, int defaultStyle) {
        super(context, attributeSet, defaultStyle);
    }


    /**
     * Override the method that gets a preference from the preferences storage, for display by the
     * EditText view. This gets the base64 password, converts it to a byte array, and then decrypts
     * it so it can be displayed in plain text.
     * @return  OutBack user password in plain text
     */
    @Override
    public String getText() {
        String decryptedPassword;

        try {
            decryptedPassword = MEncryptionUserPassword.aesDecrypt(
                     Base64.decode(getSharedPreferences().getString(getKey(), ""), Base64.DEFAULT));
        } catch (Exception e) {
            e.printStackTrace();
            decryptedPassword = "";
        }

        return decryptedPassword;
    }


    /**
     * Override the method that gets a text string from the EditText view and stores the value in
     * the preferences storage. This encrypts the password into a byte array and then encodes that
     * in base64 format.
     * @param passwordText  OutBack user password in plain text
     */
    @Override
    public void setText(String passwordText) {
        byte[] encryptedPassword;

        try {
            encryptedPassword = MEncryptionUserPassword.aesEncrypt(passwordText);
        } catch (Exception e) {
            e.printStackTrace();
            encryptedPassword = new byte[0];
        }

        getSharedPreferences().edit().putString(getKey(),
                                          Base64.encodeToString(encryptedPassword, Base64.DEFAULT))
                .commit();
    }


    @Override
    protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
        if (restoreValue)
            getEditText().setText(getText());
        else
            super.onSetInitialValue(restoreValue, defaultValue);
    }
}

Dies zeigt, wie es verwendet werden kann - dies ist die "items" -Datei, die die Anzeige der Einstellungen steuert. Beachten Sie, dass es drei normale EditTextPreference-Ansichten und eine der benutzerdefinierten EditPasswordPreference-Ansichten enthält.

<PreferenceScreen xmlns:Android="http://schemas.Android.com/apk/res/Android">

    <EditTextPreference
        Android:key="@string/useraccountname_key"
        Android:title="@string/useraccountname_title"
        Android:summary="@string/useraccountname_summary"
        Android:defaultValue="@string/useraccountname_default"
        />

    <com.Merlinia.OutBack_Client.EditPasswordPreference
        Android:key="@string/useraccountpassword_key"
        Android:title="@string/useraccountpassword_title"
        Android:summary="@string/useraccountpassword_summary"
        Android:defaultValue="@string/useraccountpassword_default"
        />

    <EditTextPreference
        Android:key="@string/outbackserverip_key"
        Android:title="@string/outbackserverip_title"
        Android:summary="@string/outbackserverip_summary"
        Android:defaultValue="@string/outbackserverip_default"
        />

    <EditTextPreference
        Android:key="@string/outbackserverport_key"
        Android:title="@string/outbackserverport_title"
        Android:summary="@string/outbackserverport_summary"
        Android:defaultValue="@string/outbackserverport_default"
        />

</PreferenceScreen>

Die eigentliche Ver-/Entschlüsselung bleibt dem Leser als Übung überlassen. Ich verwende derzeit Code basierend auf diesem Artikel http://zenu.wordpress.com/2011/09/21/aes-128bit-cross-platform-Java-und-c-encryption-compatibility/ , allerdings mit unterschiedlichen Werten für den Schlüssel und den Initialisierungsvektor.

1
RenniePet

Zunächst einmal denke ich, dass Benutzerdaten nicht auf dem Telefon gespeichert werden sollten, und wenn Daten irgendwo auf dem Telefon gespeichert werden müssen, sollten sie mit den privaten Daten der Apps verschlüsselt werden. Die Sicherheit der Anmeldeinformationen der Benutzer sollte die Priorität der Anwendung sein.

Die sensiblen Daten sollten sicher oder gar nicht gespeichert werden. Im Falle einer verlorenen Geräte- oder Malware-Infektion können unsicher gespeicherte Daten gefährdet werden.

1
Gauraw Yadav

Ich verwende den Android KeyStore, um das Kennwort mit RSA im EZB-Modus zu verschlüsseln und dann in den SharedPreferences zu speichern.

Wenn ich das Passwort zurück haben möchte, lese ich das verschlüsselte aus den SharedPreferences und entschlüssle es mit dem KeyStore.

Mit dieser Methode generieren Sie ein öffentliches/privates Schlüsselpaar, bei dem das private sicher von Android gespeichert und verwaltet wird.

Hier ist ein Link, wie das geht: Android KeyStore Tutorial

0
Braveblacklion