Il y a beaucoup de questions sur ce sujet, la même solution, mais cela ne fonctionne pas pour moi. J'ai un test simple avec un cryptage. Le chiffrement/déchiffrement lui-même fonctionne (tant que je gère ce test avec le tableau d'octets lui-même et non en tant que chaînes). Le problème est que vous ne voulez pas le gérer sous forme de tableau d'octets mais sous forme de chaîne, mais lorsque je code le tableau d'octets en chaîne, le tableau d'octets résultant diffère du tableau d'octets d'origine. J'ai essayé les paramètres suivants dans les méthodes de chaîne correspondantes: UTF-8, UTF8, UTF-16, UTF8. Aucun d'entre eux ne fonctionne. Le tableau d'octets résultant diffère de l'original. Des idées pourquoi c'est ainsi?
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;
}
}
C'est le test où je l'essaie:
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);
}
}
Ce n'est pas une bonne idée de stocker des données cryptées dans des chaînes, car elles sont pour le texte lisible par l'homme, pas pour les données binaires arbitraires. Pour les données binaires, il vaut mieux utiliser byte[]
.
Cependant, si vous le faites devez, vous devez utiliser un codage avec un mappage 1 à 1 entre octets et caractères, c’est-à-dire où chaque séquence d’octets peut être mappée à une séquence unique. de personnages et retour. Un tel encodage est ISO-8859-1, c'est-à-dire:
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);
Les autres encodages courants qui ne perdent pas de données sont hexadécimal _ et base64, mais vous avez malheureusement besoin d'une bibliothèque d'assistance. L'API standard ne définit pas de classes pour elles.
Avec UTF-16, le programme échouerait pour deux raisons:
La solution acceptée ne fonctionnera pas si votre String
a des caractères inhabituels tels que š, ž, ć, Ō, ō, Ū
, etc.
Suivre le code a bien fonctionné pour moi.
byte[] myBytes = Something.getMyBytes();
String encodedString = Base64.encodeToString(bytes, Base64.NO_WRAP);
byte[] decodedBytes = Base64.decode(encodedString, Base64.NO_WRAP);
Maintenant, j'ai trouvé une autre solution aussi ...
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);
}
}
Votre problème est que vous ne pouvez pas construire de chaîne UTF-16 (ou autre) à partir d'un tableau d'octets arbitraire (voir UTF-16 sur Wikipedia ). Cependant, il vous appartient de sérialiser et de désérialiser le tableau d'octets chiffré sans aucune perte, afin, par exemple, de le conserver et de l'utiliser ultérieurement. Voici le code client modifié qui devrait vous donner un aperçu de ce qui se passe réellement avec les tableaux d'octets:
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);
}
C'est la sortie:
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
La decryptedText
est correcte lorsqu'elle est restaurée à partir de la encryptedByteArray
d'origine. Veuillez noter que la valeur encoded
n'est pas identique à encryptedByteArray
, en raison de la perte de données lors de la conversion byte[] -> String("UTF-16")->byte[]
.