Es gibt viele Fragen zu diesem Thema, dieselbe Lösung, aber das funktioniert nicht für mich. Ich habe einen einfachen Test mit einer Verschlüsselung. Die Verschlüsselung/Entschlüsselung selbst funktioniert (solange ich diesen Test mit dem Byte-Array selbst und nicht als Strings erledige). Das Problem ist, dass es nicht als Byte-Array, sondern als String behandelt werden soll. Wenn ich das Byte-Array jedoch in Zeichenfolge und zurück codiere, unterscheidet sich das resultierende Byte-Array vom ursprünglichen Byte-Array, sodass die Entschlüsselung nicht mehr funktioniert. Ich habe die folgenden Parameter in den entsprechenden String-Methoden ausprobiert: UTF-8, UTF8, UTF-16, UTF8. Keiner von ihnen arbeitet. Das resultierende Byte-Array unterscheidet sich vom Original. Irgendwelche Ideen, warum das so ist?
Encrypter:
public class NewEncrypter
{
private String algorithm = "DESede";
private Key key = null;
private Cipher cipher = null;
public NewEncrypter() throws NoSuchAlgorithmException, NoSuchPaddingException
{
key = KeyGenerator.getInstance(algorithm).generateKey();
cipher = Cipher.getInstance(algorithm);
}
public byte[] encrypt(String input) throws Exception
{
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] inputBytes = input.getBytes("UTF-16");
return cipher.doFinal(inputBytes);
}
public String decrypt(byte[] encryptionBytes) throws Exception
{
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] recoveredBytes = cipher.doFinal(encryptionBytes);
String recovered = new String(recoveredBytes, "UTF-16");
return recovered;
}
}
Dies ist der Test, bei dem ich es versuche:
public class NewEncrypterTest
{
@Test
public void canEncryptAndDecrypt() throws Exception
{
String toEncrypt = "FOOBAR";
NewEncrypter encrypter = new NewEncrypter();
byte[] encryptedByteArray = encrypter.encrypt(toEncrypt);
System.out.println("encryptedByteArray:" + encryptedByteArray);
String decoded = new String(encryptedByteArray, "UTF-16");
System.out.println("decoded:" + decoded);
byte[] encoded = decoded.getBytes("UTF-16");
System.out.println("encoded:" + encoded);
String decryptedText = encrypter.decrypt(encoded); //Exception here
System.out.println("decryptedText:" + decryptedText);
assertEquals(toEncrypt, decryptedText);
}
}
Es ist keine gute Idee, verschlüsselte Daten in Strings zu speichern, da sie für den Menschen lesbaren Text und nicht für beliebige binäre Daten sind. Für binäre Daten verwenden Sie am besten byte[]
.
Wenn Sie müssen tun, sollten Sie jedoch eine Kodierung verwenden, die eine 1-zu-1-Zuordnung zwischen Byte und Zeichen aufweist, d. H. Jede Bytefolge kann einer eindeutigen Zeichenfolge zugeordnet werden , und zurück. Eine solche Kodierung ist ISO-8859-1 , das heißt:
String decoded = new String(encryptedByteArray, "ISO-8859-1");
System.out.println("decoded:" + decoded);
byte[] encoded = decoded.getBytes("ISO-8859-1");
System.out.println("encoded:" + Java.util.Arrays.toString(encoded));
String decryptedText = encrypter.decrypt(encoded);
Andere häufige Kodierungen, bei denen keine Daten verloren gehen, sind hexadezimal und base64 . Leider benötigen Sie dazu eine Hilfsbibliothek. Die Standard-API definiert keine Klassen für sie.
Bei UTF-16 würde das Programm aus zwei Gründen fehlschlagen:
Die akzeptierte Lösung funktioniert nicht, wenn Ihre String
nicht typische Zeichen wie š, ž, ć, Ō, ō, Ū
usw. enthält.
Der folgende Code hat für mich gut funktioniert.
byte[] myBytes = Something.getMyBytes();
String encodedString = Base64.encodeToString(bytes, Base64.NO_WRAP);
byte[] decodedBytes = Base64.decode(encodedString, Base64.NO_WRAP);
Nun habe ich auch eine andere Lösung gefunden ...
public class NewEncrypterTest
{
@Test
public void canEncryptAndDecrypt() throws Exception
{
String toEncrypt = "FOOBAR";
NewEncrypter encrypter = new NewEncrypter();
byte[] encryptedByteArray = encrypter.encrypt(toEncrypt);
String encoded = String.valueOf(Hex.encodeHex(encryptedByteArray));
byte[] byteArrayToDecrypt = Hex.decodeHex(encoded.toCharArray());
String decryptedText = encrypter.decrypt(byteArrayToDecrypt);
System.out.println("decryptedText:" + decryptedText);
assertEquals(toEncrypt, decryptedText);
}
}
Ihr Problem ist, dass Sie keinen UTF-16-String (oder eine andere Codierung) aus einem beliebigen Byte-Array erstellen können (siehe UTF-16 in Wikipedia ). Es liegt jedoch an Ihnen, das verschlüsselte Byte-Array verlustfrei zu serialisieren und zu deserialisieren, um es beispielsweise zu persistieren und später zu nutzen. Hier ist der modifizierte Client-Code, der Ihnen einen Einblick geben soll, was mit den Byte-Arrays tatsächlich passiert:
public static void main(String[] args) throws Exception {
String toEncrypt = "FOOBAR";
NewEncrypter encrypter = new NewEncrypter();
byte[] encryptedByteArray = encrypter.encrypt(toEncrypt);
System.out.println("encryptedByteArray:" + Arrays.toString(encryptedByteArray));
String decoded = new String(encryptedByteArray, "UTF-16");
System.out.println("decoded:" + decoded);
byte[] encoded = decoded.getBytes("UTF-16");
System.out.println("encoded:" + Arrays.toString(encoded));
String decryptedText = encrypter.decrypt(encryptedByteArray); // NOT the "encoded" value!
System.out.println("decryptedText:" + decryptedText);
}
Dies ist die Ausgabe:
encryptedByteArray:[90, -40, -39, -56, -90, 51, 96, 95, -65, -54, -61, 51, 6, 15, -114, 88]
decoded:<some garbage>
encoded:[-2, -1, 90, -40, -1, -3, 96, 95, -65, -54, -61, 51, 6, 15, -114, 88]
decryptedText:FOOBAR
Die decryptedText
ist korrekt, wenn sie von der ursprünglichen encryptedByteArray
wiederhergestellt wird. Bitte beachten Sie, dass der encoded
-Wert aufgrund des Datenverlusts während der byte[] -> String("UTF-16")->byte[]
-Konvertierung nicht mit encryptedByteArray
identisch ist.