with library getinstance example encrypt decrypt crypto code cipher cbc java string encryption bytearray

library - java cryptography example code



Problemas al convertir la matriz de bytes en cadena y volver a la matriz de bytes (4)

Hay muchas preguntas con respecto a este tema, la misma solución, pero esto no funciona para mí. Tengo una prueba simple con una encriptación. El cifrado / descifrado en sí mismo funciona (siempre que maneje esta prueba con la matriz de bytes en sí y no como cadenas). El problema es que no quiero manejarlo como una matriz de bytes sino como una cadena, pero cuando codigo la matriz de bytes a la cadena y viceversa, la matriz de bytes resultante difiere de la matriz de bytes original, por lo que el descifrado ya no funciona. Probé los siguientes parámetros en los métodos de cadena correspondientes: UTF-8, UTF8, UTF-16, UTF8. Ninguno de ellos funciona. El conjunto de bytes resultante difiere del original. ¿Alguna idea de por qué esto es así?

Encriptador:

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; } }

Esta es la prueba donde lo intento:

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); } }


Ahora, encontré otra solución también ...

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); } }


La solución aceptada no funcionará si su String tiene algunos caracteres no típicos como š, ž, ć, Ō, ō, Ū , etc.

El siguiente código funcionó bien para mí.

byte[] myBytes = Something.getMyBytes(); String encodedString = Base64.encodeToString(bytes, Base64.NO_WRAP); byte[] decodedBytes = Base64.decode(encodedString, Base64.NO_WRAP);


No es una buena idea almacenar datos encriptados en Strings porque son para texto legible por humanos, no para datos binarios arbitrarios. Para datos binarios, es mejor usar byte[] .

Sin embargo, si debe hacerlo, debe usar una codificación que tenga una correspondencia de 1 a 1 entre bytes y caracteres, es decir, donde cada secuencia de bytes se pueda asignar a una secuencia única de caracteres, y viceversa. Una de estas codificaciones es ISO-8859-1 , es decir:

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);

Otras codificaciones comunes que no pierden datos son hexadecimal y base64 , pero lamentablemente se necesita una biblioteca de ayuda para ellos. La API estándar no define clases para ellos.

Con UTF-16 el programa fallaría por dos razones:

  1. String.getBytes ("UTF-16") agrega un carácter de marcador de orden de bytes a la salida para identificar el orden de los bytes. Debe usar UTF-16LE o UTF-16BE para que esto no suceda.
  2. No todas las secuencias de bytes se pueden asignar a caracteres en UTF-16. Primero, el texto codificado en UTF-16 debe tener un número par de bytes. En segundo lugar, UTF-16 tiene un mecanismo para codificar caracteres Unicode más allá de U + FFFF. Esto significa que, por ejemplo, hay secuencias de 4 bytes que se asignan a un solo carácter Unicode. Para que esto sea posible, los primeros 2 bytes de los 4 no codifican ningún carácter en UTF-16.

Su problema es que no puede construir una cadena UTF-16 (o cualquier otra codificación) desde una matriz de bytes arbitraria (vea UTF-16 en Wikipedia ). Depende de usted, sin embargo, serializar y deserializar la matriz de bytes cifrados sin pérdida, para, por ejemplo, persistir y utilizarla más adelante. Aquí está el código de cliente modificado que debería darle una idea de lo que está sucediendo realmente con las matrices de bytes:

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); }

Este es el resultado:

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

decryptedText es correcto, cuando se restaura desde el encryptedByteArray original. Tenga en cuenta que el valor encoded no es lo mismo que encryptedByteArray , debido a la pérdida de datos durante la conversión byte[] -> String("UTF-16")->byte[] .