Schlüssel, Anmeldeinformationen und Speicher auf Android

() translation by (you can also view the original English article)
Im vorherigen Artikel zur Datensicherheit von Android-Benutzern haben wir uns mit der Verschlüsselung von Daten über einen vom Benutzer angegebenen Passcode befasst. In diesem Lernprogramm wird der Schwerpunkt auf die Speicherung von Anmeldeinformationen und Schlüsseln gelegt. Ich beginne mit der Einführung von Kontoanmeldeinformationen und ende mit einem Beispiel für den Schutz von Daten mithilfe des KeyStore.
- SicherheitSicheres Speichern von Daten unter AndroidCollin Stuart
- AndroidWie Sie eine Android App sichern könnenAshraff Hathibelagal
Wenn Sie mit einem Drittanbieter arbeiten, ist häufig eine Authentifizierung erforderlich. Dies kann so einfach sein wie ein /login
-Endpunkt, der einen Benutzernamen und ein Kennwort akzeptiert.
Zunächst scheint es eine einfache Lösung zu sein, eine Benutzeroberfläche zu erstellen, die den Benutzer auffordert, sich anzumelden, und dann seine Anmeldeinformationen zu erfassen und zu speichern. Dies ist jedoch nicht die beste Vorgehensweise, da unsere App die Anmeldeinformationen für ein Konto eines Drittanbieters nicht kennen muss. Stattdessen können wir den Account Manager verwenden, der die Verarbeitung dieser vertraulichen Informationen für uns delegiert.
Buchhalter
Der Account Manager ist ein zentraler Helfer für Anmeldeinformationen von Benutzerkonten, sodass Ihre App nicht direkt mit Kennwörtern umgehen muss. Es stellt häufig ein Token anstelle des tatsächlichen Benutzernamens und Kennworts bereit, mit dem authentifizierte Anforderungen an einen Dienst gestellt werden können. Ein Beispiel ist das Anfordern eines OAuth2-Tokens.
Manchmal sind alle erforderlichen Informationen bereits auf dem Gerät gespeichert, und manchmal muss der Account Manager einen Server anrufen, um ein aktualisiertes Token zu erhalten. Möglicherweise haben Sie den Abschnitt Accounts in den Einstellungen Ihres Geräts für verschiedene Apps gesehen. Wir können diese Liste der verfügbaren Accounts erhalten:
1 |
AccountManager accountManager = AccountManager.get(this); |
2 |
Account[] accounts = accountManager.getAccounts(); |
Der Code erfordert die Berechtigung android.permission.GET_ACCOUNTS
. Wenn Sie nach einem bestimmten Account suchen, finden Sie es:
1 |
AccountManager accountManager = AccountManager.get(this); |
2 |
Account[] accounts = accountManager.getAccountsByType("com.google"); |
Sobald Sie den Account haben, können Sie ein Token für das Account abrufen, indem Sie die Methode getAuthToken(Account, String, Bundle, Activity, AccountManagerCallback, Handler)
aufrufen. Das Token kann dann verwendet werden, um authentifizierte API-Anforderungen an einen Dienst zu senden. Dies kann eine RESTful-API sein, bei der Sie während einer HTTPS-Anforderung einen Token-Parameter übergeben, ohne jemals die Details des privaten Kontos des Benutzers kennen zu müssen.
Da für jeden Dienst die privaten Anmeldeinformationen auf unterschiedliche Weise authentifiziert und gespeichert werden, stellt der Account Manager Authentifizierungsmodule zur Verfügung, die von einem Drittanbieter-Service implementiert werden können. Während Android Implementierungen für viele beliebte Dienste bietet, können Sie Ihren eigenen Authentifikator schreiben, um die Kontoauthentifizierung und den Speicher für Anmeldeinformationen Ihrer App zu verwalten. Auf diese Weise können Sie sicherstellen, dass die Anmeldeinformationen verschlüsselt sind. Beachten Sie, dass dies auch bedeutet, dass Anmeldeinformationen im Account Manager, die von anderen Diensten verwendet werden, im Klartext gespeichert werden können, sodass sie für jeden sichtbar sind, der sein Gerät gerootet hat.
Anstelle einfacher Anmeldeinformationen müssen Sie manchmal einen Schlüssel oder ein Zertifikat für eine Person oder Entität verarbeiten, z. B. wenn Ihnen ein Dritter eine Zertifikatdatei sendet, die Sie aufbewahren müssen. Das häufigste Szenario ist, wenn sich eine App beim Server einer privaten Organisation authentifizieren muss.
Im nächsten Tutorial werden wir uns mit der Verwendung von Zertifikaten für die Authentifizierung und sichere Kommunikation befassen, aber ich möchte in der Zwischenzeit noch erläutern, wie diese Elemente gespeichert werden. Die Schlüsselbund-API wurde ursprünglich für diesen speziellen Zweck entwickelt: Installieren eines privaten Schlüssels oder Zertifikatpaars aus einer PKCS#12-Datei.
Der Schlüsselbund
Die in Android 4.0 (API Level 14) eingeführte Schlüsselbund-API befasst sich mit der Schlüsselverwaltung. Insbesondere funktioniert es mit PrivateKey
- und X509Certificate
-Objekten und bietet einen sichereren Container als die Verwendung des Datenspeichers Ihrer App. Dies liegt daran, dass Berechtigungen für private Schlüssel nur Ihrer eigenen App den Zugriff auf die Schlüssel ermöglichen und nur nach Benutzerautorisierung. Dies bedeutet, dass auf dem Gerät ein Sperrbildschirm eingerichtet werden muss, bevor Sie den Speicher für Anmeldeinformationen verwenden können. Falls verfügbar, sind die Objekte im Schlüsselbund möglicherweise an sichere Hardware gebunden.
Der Code zum Installieren eines Zertifikats lautet wie folgt:
1 |
Intent intent = KeyChain.createInstallIntent(); |
2 |
byte[] p12Bytes = //... read from file, such as example.pfx or example.p12... |
3 |
intent.putExtra(KeyChain.EXTRA_PKCS12, p12Bytes); |
4 |
startActivity(intent); |
Der Benutzer wird aufgefordert, ein Kennwort für den Zugriff auf den privaten Schlüssel und eine Option zum Benennen des Zertifikats einzugeben. Um den Schlüssel abzurufen, enthält der folgende Code eine Benutzeroberfläche, über die der Benutzer aus der Liste der installierten Schlüssel auswählen kann.
1 |
KeyChain.choosePrivateKeyAlias(this, this, new String[]{"RSA"}, null, null, -1, null); |
Sobald die Auswahl getroffen wurde, wird im alias(final String alias)
ein String-Aliasname zurückgegeben, über den Sie direkt auf den privaten Schlüssel oder die Zertifikatkette zugreifen können.
1 |
public class KeychainTest extends Activity implements ..., KeyChainAliasCallback |
2 |
{
|
3 |
//...
|
4 |
|
5 |
@Override
|
6 |
public void alias(final String alias) |
7 |
{
|
8 |
Log.e("MyApp", "Alias is " + alias); |
9 |
|
10 |
try
|
11 |
{
|
12 |
PrivateKey privateKey = KeyChain.getPrivateKey(this, alias); |
13 |
X509Certificate[] certificateChain = KeyChain.getCertificateChain(this, alias); |
14 |
}
|
15 |
catch ... |
16 |
}
|
17 |
|
18 |
//...
|
19 |
}
|
Mit diesem Wissen wollen wir nun sehen, wie wir den Speicher für Anmeldeinformationen verwenden können, um Ihre eigenen vertraulichen Daten zu speichern.
Der KeyStore
Im vorherigen Tutorial haben wir uns mit dem Schutz von Daten über einen vom Benutzer angegebenen Passcode befasst. Diese Art der Einrichtung ist gut, aber die App-Anforderungen vermeiden oft, dass sich Benutzer jedes Mal anmelden und sich einen zusätzlichen Passcode merken.
Hier kann die KeyStore-API verwendet werden. Seit API 1 wird der KeyStore vom System zum Speichern von WLAN- und VPN-Anmeldeinformationen verwendet. Ab 4.3 (API 18) können Sie mit Ihren eigenen app-spezifischen asymmetrischen Schlüsseln arbeiten und in Android M (API 23) einen symmetrischen AES-Schlüssel speichern. Während die API das direkte Speichern vertraulicher Zeichenfolgen nicht zulässt, können diese Schlüssel gespeichert und dann zum Verschlüsseln von Zeichenfolgen verwendet werden.
Der Vorteil des Speicherns eines Schlüssels im KeyStore besteht darin, dass Schlüssel bearbeitet werden können, ohne den geheimen Inhalt dieses Schlüssels preiszugeben. Schlüsseldaten gelangen nicht in den App-Bereich. Denken Sie daran, dass Schlüssel durch Berechtigungen geschützt sind, sodass nur Ihre App darauf zugreifen kann. Wenn das Gerät in der Lage ist, sind sie möglicherweise zusätzlich sicherheitsunterstützt. Dadurch wird ein Container erstellt, der das Extrahieren von Schlüsseln von einem Gerät erschwert.
Generieren Sie einen neuen Zufallsschlüssel
In diesem Beispiel können wir anstelle eines AES-Schlüssels aus einem vom Benutzer angegebenen Passcode automatisch einen zufälligen Schlüssel generieren, der im KeyStore geschützt wird. Wir können dies tun, indem wir eine KeyGenerator
-Instanz erstellen, die auf den Anbieter "AndroidKeyStore"
eingestellt ist.
1 |
//Generate a key and store it in the KeyStore
|
2 |
final KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore"); |
3 |
final KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder("MyKeyAlias", |
4 |
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) |
5 |
.setBlockModes(KeyProperties.BLOCK_MODE_GCM) |
6 |
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) |
7 |
//.setUserAuthenticationRequired(true) //requires lock screen, invalidated if lock screen is disabled
|
8 |
//.setUserAuthenticationValidityDurationSeconds(120) //only available x seconds from password authentication. -1 requires finger print - every time
|
9 |
.setRandomizedEncryptionRequired(true) //different ciphertext for same plaintext on each call |
10 |
.build(); |
11 |
keyGenerator.init(keyGenParameterSpec); |
12 |
keyGenerator.generateKey(); |
Wichtige Teile, die hier betrachtet werden müssen, sind die Spezifikationen .setUserAuthenticationRequired(true)
und .setUserAuthenticationValidityDurationSeconds(120)
. Dazu muss ein Sperrbildschirm eingerichtet und der Schlüssel gesperrt werden, bis sich der Benutzer authentifiziert hat.
In der Dokumentation zu .setUserAuthenticationValidityDurationSeconds()
sehen Sie, dass der Schlüssel nur eine bestimmte Anzahl von Sekunden nach der Kennwortauthentifizierung verfügbar ist und dass die Übergabe von -1
jedes Mal eine Authentifizierung per Fingerabdruck erfordert, wenn Sie auf den Schlüssel zugreifen möchten. Durch Aktivieren der Authentifizierungsanforderung wird der Schlüssel auch widerrufen, wenn der Benutzer den Sperrbildschirm entfernt oder ändert.
Da das Speichern eines ungeschützten Schlüssels neben den verschlüsselten Daten dem Platzieren eines Hausschlüssels unter der Fußmatte gleicht, versuchen diese Optionen, den Schlüssel in Ruhe zu schützen, falls ein Gerät kompromittiert wird. Ein Beispiel könnte ein Offline-Datendump des Geräts sein. Ohne dass das Kennwort für das Gerät bekannt ist, werden diese Daten unbrauchbar.
Die Option .setRandomizedEncryptionRequired(true)
aktiviert die Anforderung, dass genügend Randomisierung vorhanden ist (jedes Mal eine neue zufällige IV), sodass die verschlüsselte Ausgabe immer noch unterschiedlich ist, wenn dieselben Daten ein zweites Mal verschlüsselt werden. Dies verhindert, dass ein Angreifer aufgrund der Eingabe derselben Daten Hinweise auf den Chiffretext erhält.
Eine weitere zu beachtende Option ist setUserAuthenticationValidWhileOnBody(boolean remainsValid)
, mit dem der Schlüssel gesperrt wird, sobald das Gerät erkannt hat, dass er sich nicht mehr in der Person befindet.
Daten verschlüsseln
Nachdem der Schlüssel im KeyStore gespeichert ist, können wir eine Methode erstellen, die Daten mit dem Cipher
-Objekt unter Verwendung des SecretKey
verschlüsselt. Es wird eine HashMap
zurückgegeben, die die verschlüsselten Daten und eine zufällige IV enthält, die zum Entschlüsseln der Daten benötigt wird. Die verschlüsselten Daten können dann zusammen mit der IV in einer Datei oder in den freigegebenen Einstellungen gespeichert werden.
1 |
private HashMap<String, byte[]> encrypt(final byte[] decryptedBytes) |
2 |
{
|
3 |
final HashMap<String, byte[]> map = new HashMap<String, byte[]>(); |
4 |
try
|
5 |
{
|
6 |
//Get the key
|
7 |
final KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); |
8 |
keyStore.load(null); |
9 |
final KeyStore.SecretKeyEntry secretKeyEntry = (KeyStore.SecretKeyEntry)keyStore.getEntry("MyKeyAlias", null); |
10 |
final SecretKey secretKey = secretKeyEntry.getSecretKey(); |
11 |
|
12 |
//Encrypt data
|
13 |
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); |
14 |
cipher.init(Cipher.ENCRYPT_MODE, secretKey); |
15 |
final byte[] ivBytes = cipher.getIV(); |
16 |
final byte[] encryptedBytes = cipher.doFinal(decryptedBytes); |
17 |
map.put("iv", ivBytes); |
18 |
map.put("encrypted", encryptedBytes); |
19 |
}
|
20 |
catch (Throwable e) |
21 |
{
|
22 |
e.printStackTrace(); |
23 |
}
|
24 |
|
25 |
return map; |
26 |
}
|
Entschlüsseln in ein Byte-Array
Bei der Entschlüsselung wird das Gegenteil angewendet. Das Cipher
-Objekt wird mit der Konstante DECRYPT_MODE
initialisiert und ein entschlüsseltes byte[]
-Array zurückgegeben.
1 |
private byte[] decrypt(final HashMap<String, byte[]> map) |
2 |
{
|
3 |
byte[] decryptedBytes = null; |
4 |
try
|
5 |
{
|
6 |
//Get the key
|
7 |
final KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); |
8 |
keyStore.load(null); |
9 |
final KeyStore.SecretKeyEntry secretKeyEntry = (KeyStore.SecretKeyEntry)keyStore.getEntry("MyKeyAlias", null); |
10 |
final SecretKey secretKey = secretKeyEntry.getSecretKey(); |
11 |
|
12 |
//Extract info from map
|
13 |
final byte[] encryptedBytes = map.get("encrypted"); |
14 |
final byte[] ivBytes = map.get("iv"); |
15 |
|
16 |
//Decrypt data
|
17 |
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); |
18 |
final GCMParameterSpec spec = new GCMParameterSpec(128, ivBytes); |
19 |
cipher.init(Cipher.DECRYPT_MODE, secretKey, spec); |
20 |
decryptedBytes = cipher.doFinal(encryptedBytes); |
21 |
}
|
22 |
catch (Throwable e) |
23 |
{
|
24 |
e.printStackTrace(); |
25 |
}
|
26 |
|
27 |
return decryptedBytes; |
28 |
}
|
Beispiel testen
Wir können jetzt unser Beispiel testen!
1 |
@TargetApi(Build.VERSION_CODES.M) |
2 |
private void testEncryption() |
3 |
{
|
4 |
try
|
5 |
{
|
6 |
//Generate a key and store it in the KeyStore
|
7 |
final KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore"); |
8 |
final KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder("MyKeyAlias", |
9 |
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) |
10 |
.setBlockModes(KeyProperties.BLOCK_MODE_GCM) |
11 |
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) |
12 |
//.setUserAuthenticationRequired(true) //requires lock screen, invalidated if lock screen is disabled
|
13 |
//.setUserAuthenticationValidityDurationSeconds(120) //only available x seconds from password authentication. -1 requires finger print - every time
|
14 |
.setRandomizedEncryptionRequired(true) //different ciphertext for same plaintext on each call |
15 |
.build(); |
16 |
keyGenerator.init(keyGenParameterSpec); |
17 |
keyGenerator.generateKey(); |
18 |
|
19 |
//Test
|
20 |
final HashMap<String, byte[]> map = encrypt("My very sensitive string!".getBytes("UTF-8")); |
21 |
final byte[] decryptedBytes = decrypt(map); |
22 |
final String decryptedString = new String(decryptedBytes, "UTF-8"); |
23 |
Log.e("MyApp", "The decrypted string is " + decryptedString); |
24 |
}
|
25 |
catch (Throwable e) |
26 |
{
|
27 |
e.printStackTrace(); |
28 |
}
|
29 |
}
|
Verwenden von asymmetrischen RSA-Schlüsseln für ältere Geräte
Das ist eine gute Lösung zum Speichern von Daten für Versionen M und höher. Wenn Ihre App frühere Versionen unterstützt? Während symmetrische AES-Schlüssel unter M nicht unterstützt werden, sind es asymmetrische RSA-Schlüssel. Wir können RSA-Schlüssel und Verschlüsselung verwenden, um dasselbe zu erreichen.
Der Hauptunterschied besteht darin, dass ein asymmetrisches Schlüsselpaar zwei Schlüssel enthält, einen privaten und einen öffentlichen Schlüssel, wobei der öffentliche Schlüssel die Daten verschlüsselt und der private Schlüssel sie entschlüsselt. Eine KeyPairGeneratorSpec
wird an den KeyPairGenerator
übergeben, der mit KEY_ALGORITHM_RSA
und dem "AndroidKeyStore"
-Anbieter initialisiert wird.
1 |
private void testPreMEncryption() |
2 |
{
|
3 |
try
|
4 |
{
|
5 |
//Generate a keypair and store it in the KeyStore
|
6 |
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); |
7 |
keyStore.load(null); |
8 |
|
9 |
Calendar start = Calendar.getInstance(); |
10 |
Calendar end = Calendar.getInstance(); |
11 |
end.add(Calendar.YEAR, 10); |
12 |
KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(this) |
13 |
.setAlias("MyKeyAlias") |
14 |
.setSubject(new X500Principal("CN=MyKeyName, O=Android Authority")) |
15 |
.setSerialNumber(new BigInteger(1024, new Random())) |
16 |
.setStartDate(start.getTime()) |
17 |
.setEndDate(end.getTime()) |
18 |
.setEncryptionRequired() //on API level 18, encrypted at rest, requires lock screen to be set up, changing lock screen removes key |
19 |
.build(); |
20 |
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore"); |
21 |
keyPairGenerator.initialize(spec); |
22 |
keyPairGenerator.generateKeyPair(); |
23 |
|
24 |
//Encryption test
|
25 |
final byte[] encryptedBytes = rsaEncrypt("My secret string!".getBytes("UTF-8")); |
26 |
final byte[] decryptedBytes = rsaDecrypt(encryptedBytes); |
27 |
final String decryptedString = new String(decryptedBytes, "UTF-8"); |
28 |
Log.e("MyApp", "Decrypted string is " + decryptedString); |
29 |
}
|
30 |
catch (Throwable e) |
31 |
{
|
32 |
e.printStackTrace(); |
33 |
}
|
34 |
}
|
Zum Verschlüsseln erhalten wir den RSAPublicKey
vom Schlüsselpaar und verwenden ihn mit dem Cipher
-Objekt.
1 |
public byte[] rsaEncrypt(final byte[] decryptedBytes) |
2 |
{
|
3 |
byte[] encryptedBytes = null; |
4 |
try
|
5 |
{
|
6 |
final KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); |
7 |
keyStore.load(null); |
8 |
final KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry("MyKeyAlias", null); |
9 |
final RSAPublicKey publicKey = (RSAPublicKey)privateKeyEntry.getCertificate().getPublicKey(); |
10 |
|
11 |
final Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL"); |
12 |
cipher.init(Cipher.ENCRYPT_MODE, publicKey); |
13 |
|
14 |
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); |
15 |
final CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream, cipher); |
16 |
cipherOutputStream.write(decryptedBytes); |
17 |
cipherOutputStream.close(); |
18 |
|
19 |
encryptedBytes = outputStream.toByteArray(); |
20 |
|
21 |
}
|
22 |
catch (Throwable e) |
23 |
{
|
24 |
e.printStackTrace(); |
25 |
}
|
26 |
return encryptedBytes; |
27 |
}
|
Die Entschlüsselung erfolgt mit dem RSAPrivateKey
-Objekt.
1 |
public byte[] rsaDecrypt(final byte[] encryptedBytes) |
2 |
{
|
3 |
byte[] decryptedBytes = null; |
4 |
try
|
5 |
{
|
6 |
final KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); |
7 |
keyStore.load(null); |
8 |
final KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry("MyKeyAlias", null); |
9 |
final RSAPrivateKey privateKey = (RSAPrivateKey)privateKeyEntry.getPrivateKey(); |
10 |
|
11 |
final Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL"); |
12 |
cipher.init(Cipher.DECRYPT_MODE, privateKey); |
13 |
|
14 |
final CipherInputStream cipherInputStream = new CipherInputStream(new ByteArrayInputStream(encryptedBytes), cipher); |
15 |
final ArrayList<Byte> arrayList = new ArrayList<>(); |
16 |
int nextByte; |
17 |
while ( (nextByte = cipherInputStream.read()) != -1 ) |
18 |
{
|
19 |
arrayList.add((byte)nextByte); |
20 |
}
|
21 |
|
22 |
decryptedBytes = new byte[arrayList.size()]; |
23 |
for(int i = 0; i < decryptedBytes.length; i++) |
24 |
{
|
25 |
decryptedBytes[i] = arrayList.get(i); |
26 |
}
|
27 |
}
|
28 |
catch (Throwable e) |
29 |
{
|
30 |
e.printStackTrace(); |
31 |
}
|
32 |
|
33 |
return decryptedBytes; |
34 |
}
|
Eine Sache bei RSA ist, dass die Verschlüsselung langsamer ist als in AES. Das geht für kleine Informationsmengen in Ordnung, z. B. wenn Sie gemeinsame Einstellungszeichenfolgen sichern. Wenn Sie jedoch ein Leistungsproblem beim Verschlüsseln großer Datenmengen feststellen, können Sie dieses Beispiel stattdessen zum Verschlüsseln und Speichern nur eines AES-Schlüssels verwenden. Verwenden Sie dann die schnellere AES-Verschlüsselung, die im vorherigen Lernprogramm für den Rest Ihrer Daten beschrieben wurde. Sie können einen neuen AES-Schlüssel generieren und ihn in ein byte[]
-Array konvertieren, das mit diesem Beispiel kompatibel ist.
1 |
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); |
2 |
keyGenerator.init(256); //AES-256 |
3 |
SecretKey secretKey = keyGenerator.generateKey(); |
4 |
byte[] keyBytes = secretKey.getEncoded(); |
Gehen Sie folgendermaßen vor, um den Schlüssel von den Bytes zurückzugewinnen:
1 |
SecretKey key = new SecretKeySpec(keyBytes, 0, keyBytes.length, "AES"); |
Das war viel Code! Um alle Beispiele einfach zu halten, habe ich auf eine gründliche Ausnahmebehandlung verzichtet. Denken Sie jedoch daran, dass es für Ihren Produktionscode nicht empfohlen wird, einfach alle Throwable
-Fälle in einer catch-Anweisung abzufangen.
Abschluss
Damit ist das Lernprogramm zum Arbeiten mit Anmeldeinformationen und Schlüsseln abgeschlossen. Ein Großteil der Verwirrung um Schlüssel und Speicher hängt mit der Entwicklung des Android-Betriebssystems zusammen. Sie können auswählen, welche Lösung von Ihrer App unterstützten API-Ebene verwendet werden soll.
Nachdem wir die Best Practices für das Sichern von Daten in Ruhe behandelt haben, konzentriert sich das nächste Lernprogramm auf das Sichern von Daten während des Transports.