Problems converting an array of bytes to a string and back to a byte array

There are many questions in this topic, this is the same solution, but it does not work for me. I have a simple test with encryption. Encryption / decryption itself works (as long as I process this test with an array of bytes, and not as strings). The problem is that you do not want to treat it as an array of bytes, but as a String, but when I encode an array of bytes into a string and vice versa, the resulting byte array is different from the original byte array, so decryption does not work anymore. I tried the following parameters in the corresponding string methods: UTF-8, UTF8, UTF-16, UTF8. None of them work. The resulting byte matrix is ​​different from the original. Any ideas why this is so?

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

This is the test where I try it:

 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); } } 
+29
java string bytearray encryption
Feb 01 2018-12-12T00:
source share
4 answers

It is not recommended to store encrypted data in Strings, because they are intended for human-readable text, and not for arbitrary binary data. For binary data, it is best to use byte[] .

However, if you must do this, you must use an encoding that has a 1-to-1 mapping between bytes and characters, that is, where each sequence of bytes can be mapped to a unique sequence of characters and vice versa. One such encoding is ISO-8859-1 , that is:

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

Other common encodings that do not lose data are hexadecimal and base64 , but unfortunately you need a helper library. The standard API does not define classes for them.

With UTF-16, the program will fail for two reasons:

  • String.getBytes ("UTF-16") appends the marker byte character to the output to determine the byte order. You must use UTF-16LE or UTF-16BE to prevent this from happening.
  • Not all byte sequences can be mapped to characters in UTF-16. Firstly, text encoded in UTF-16 must have an even number of bytes. Secondly, UTF-16 has a Unicode character encoding mechanism outside of U + FFFF. This means that, for example, there are sequences of 4 bytes that are displayed for only one Unicode character. To make this possible, the first 2 bytes of 4 do not encode any character in UTF-16.
+71
Feb 01 '12 at 15:53
source share

The decision made will not work if your String has some non-standard characters, such as š, ž, ć, Ō, ō, Ū , etc.

The following code worked well for me.

 byte[] myBytes = Something.getMyBytes(); String encodedString = Base64.encodeToString(bytes, Base64.NO_WRAP); byte[] decodedBytes = Base64.decode(encodedString, Base64.NO_WRAP); 
+13
Oct. 15 '15 at 15:40
source share

Now I have found another solution ...

  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); } } 
+5
Feb 01 '12 at 16:00
source share

Your problem is that you cannot construct a UTF-16 string (or any other encoding) from an arbitrary byte array (see UTF-16 on Wikipedia ). However, you decide to serialize and deserialize the encrypted byte array without any loss, to, say, save it and use it later. Here's the modified client code, which should give you an idea of ​​what is actually happening with byte arrays:

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

This is the conclusion:

 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 correct if it is restored from the original encryptedByteArray . Note that the encoded value does not match the encryptedByteArray due to data loss during the conversion byte[] -> String("UTF-16")->byte[] .

0
Feb 01 '12 at 15:50
source share



All Articles