Ich generiere einen Schlüssel und muss ihn in DB speichern, also konvertiere ich ihn in einen String, aber um den Schlüssel aus dem String zurückzuholen. Welche Möglichkeiten gibt es, um dies zu erreichen?
Mein Code lautet
SecretKey key = KeyGenerator.getInstance("AES").generateKey();
String stringKey=key.toString();
System.out.println(stringKey);
Wie kann ich den Schlüssel vom String zurückholen?
Sie können SecretKey
in ein Byte-Array (byte[]
) konvertieren und dann Base64 in ein String
codieren. Um wieder in ein SecretKey
zu konvertieren, decodiert Base64 den String und verwendet ihn in einem SecretKeySpec
, um das ursprüngliche SecretKey
neu zu erstellen.
SecretKey zu String:
// create new key
SecretKey secretKey = KeyGenerator.getInstance("AES").generateKey();
// get base64 encoded version of the key
String encodedKey = Base64.getEncoder().encodeToString(secretKey.getEncoded());
String zu SecretKey:
// decode the base64 encoded string
byte[] decodedKey = Base64.getDecoder().decode(encodedKey);
// rebuild key using SecretKeySpec
SecretKey originalKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES");
NOTE I: Sie können den Base64-Codierungs-/Decodierungsteil überspringen und den byte[]
einfach in SQLite speichern. Das Ausführen der Base64-Codierung Decodierung ist jedoch keine kostspielige Operation, und Sie können Zeichenfolgen in fast jeder Datenbank ohne Probleme speichern.
NOTE II: Frühere Java-Versionen enthalten kein Base64 in einem der Pakete Java.lang
oder Java.util
. Es ist jedoch möglich, Codecs aus/- Apache Commons Codec , Bouncy Castle oder Guava zu verwenden.
SecretKey zu String:
// CREATE NEW KEY
// GET ENCODED VERSION OF KEY (THIS CAN BE STORED IN A DB)
SecretKey secretKey;
String stringKey;
try {secretKey = KeyGenerator.getInstance("AES").generateKey();}
catch (NoSuchAlgorithmException e) {/* LOG YOUR EXCEPTION */}
if (secretKey != null) {stringKey = Base64.encodeToString(secretKey.getEncoded(), Base64.DEFAULT)}
String zu SecretKey:
// DECODE YOUR BASE64 STRING
// REBUILD KEY USING SecretKeySpec
byte[] encodedKey = Base64.decode(stringKey, Base64.DEFAULT);
SecretKey originalKey = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
Um zu zeigen, wie viel Spaß es macht, einige Funktionen zu erstellen, die Fail Fast sind, habe ich die folgenden 3 Funktionen geschrieben.
Man erstellt einen AES-Schlüssel, man codiert ihn und man dekodiert ihn zurück. Diese drei Methoden können mit Java 8 verwendet werden (ohne Abhängigkeit interner Klassen oder außerhalb von Abhängigkeiten):
public static SecretKey generateAESKey(int keysize)
throws InvalidParameterException {
try {
if (Cipher.getMaxAllowedKeyLength("AES") < keysize) {
// this may be an issue if unlimited crypto is not installed
throw new InvalidParameterException("Key size of " + keysize
+ " not supported in this runtime");
}
final KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(keysize);
return keyGen.generateKey();
} catch (final NoSuchAlgorithmException e) {
// AES functionality is a requirement for any Java SE runtime
throw new IllegalStateException(
"AES should always be present in a Java SE runtime", e);
}
}
public static SecretKey decodeBase64ToAESKey(final String encodedKey)
throws IllegalArgumentException {
try {
// throws IllegalArgumentException - if src is not in valid Base64
// scheme
final byte[] keyData = Base64.getDecoder().decode(encodedKey);
final int keysize = keyData.length * Byte.SIZE;
// this should be checked by a SecretKeyFactory, but that doesn't exist for AES
switch (keysize) {
case 128:
case 192:
case 256:
break;
default:
throw new IllegalArgumentException("Invalid key size for AES: " + keysize);
}
if (Cipher.getMaxAllowedKeyLength("AES") < keysize) {
// this may be an issue if unlimited crypto is not installed
throw new IllegalArgumentException("Key size of " + keysize
+ " not supported in this runtime");
}
// throws IllegalArgumentException - if key is empty
final SecretKeySpec aesKey = new SecretKeySpec(keyData, "AES");
return aesKey;
} catch (final NoSuchAlgorithmException e) {
// AES functionality is a requirement for any Java SE runtime
throw new IllegalStateException(
"AES should always be present in a Java SE runtime", e);
}
}
public static String encodeAESKeyToBase64(final SecretKey aesKey)
throws IllegalArgumentException {
if (!aesKey.getAlgorithm().equalsIgnoreCase("AES")) {
throw new IllegalArgumentException("Not an AES key");
}
final byte[] keyData = aesKey.getEncoded();
final String encodedKey = Base64.getEncoder().encodeToString(keyData);
return encodedKey;
}
Sie möchten .toString()
nicht verwenden.
Beachten Sie, dass SecretKey von Java.security.Key erbt, das wiederum von Serializable erbt. Der Schlüssel hier (kein Wortspiel beabsichtigt) ist also, den Schlüssel in einen ByteArrayOutputStream zu serialisieren, das Byte [] -Array abzurufen und in der Datenbank zu speichern. Der umgekehrte Vorgang wäre, das Byte [] -Array aus der Datenbank zu holen, einen ByteArrayInputStream des Byte [] - Arrays zu erstellen und den SecretKey davon zu deserialisieren ...
... oder noch einfacher, verwenden Sie einfach die .getEncoded()
-Methode, die von Java.security.Key (einer übergeordneten Schnittstelle von SecretKey) geerbt wurde. Diese Methode gibt das codierte Byte [] -Array von Key/SecretKey zurück, das Sie speichern oder aus der Datenbank abrufen können.
Dies alles setzt voraus, dass Ihre SecretKey-Implementierung die Kodierung unterstützt. Andernfalls gibt getEncoded()
null zurück.
Sie sollten sich die Key/SecretKey-Javadocs ansehen (direkt zu Beginn einer Google-Seite verfügbar):
http://download.Oracle.com/javase/6/docs/api/Java/security/Key.html
Oder dies von CodeRanch (auch mit der gleichen Google-Suche gefunden):
http://www.coderanch.com/t/429127/Java/java/Convertion-between-SecretKey-String-or
Konvertieren von SecretKeySpec in String und umgekehrt: Sie können die getEncoded()
-Methode in SecretKeySpec
verwenden, die byteArray
enthält. Daraus können Sie encodeToString()
verwenden, um den string
-Wert von SecretKeySpec
im Base64
-Objekt zu erhalten.
Bei der Konvertierung von SecretKeySpec
in String
: verwenden Sie decode()
in Base64
byteArray
. Daraufhin können Sie eine Instanz für SecretKeySpec
mit den Parametern als byteArray
erstellen, um Ihre SecretKeySpec
zu reproduzieren.
String mAesKey_string;
SecretKeySpec mAesKey= new SecretKeySpec(secretKey.getEncoded(), "AES");
//SecretKeySpec to String
byte[] byteaes=mAesKey.getEncoded();
mAesKey_string=Base64.encodeToString(byteaes,Base64.NO_WRAP);
//String to SecretKeySpec
byte[] aesByte = Base64.decode(mAesKey_string, Base64.NO_WRAP);
mAesKey= new SecretKeySpec(aesByte, "AES");
Eigentlich hat das, was Luis vorgeschlagen hat, für mich nicht funktioniert. Ich musste einen anderen Weg finden. Das hat mir geholfen. Könnte dir auch helfen. Links:
* .getEncoded (): https://docs.Oracle.com/javase/7/docs/api/Java/security/Key.html
Informationen zum Encoder: https://docs.Oracle.com/javase/8/docs/api/Java/util/Base64.Encoder.html
Informationen zum Decoder: https://docs.Oracle.com/javase/8/docs/api/Java/util/Base64.Decoder.html
Codeausschnitte: Für die Kodierung:
String temp = new String(Base64.getEncoder().encode(key.getEncoded()));
Zum Dekodieren:
byte[] encodedKey = Base64.getDecoder().decode(temp);
SecretKey originalKey = new SecretKeySpec(encodedKey, 0, encodedKey.length, "DES");