Длина байтов изменяется после преобразования в строку

#java #string #byte

#java #строка #байт

Вопрос:

Я хочу преобразовать байты в строку для целей шифрования, а затем я хочу получить те же байты для расшифровки. Но проблема в том, что после генерации 16 байт IV я преобразую его в строку, и когда я пытаюсь получить тот же байт из строки, длина байтов изменяется. Ниже приведен пример программы для воспроизведения проблемы.

 package com.prahs.clinical6.mobile.edge.util;

import java.security.SecureRandom;
import java.util.Random;

import javax.crypto.spec.IvParameterSpec;

public class Test {

  public static void main(String[] args) {
    Random rand = new SecureRandom();
    byte[] bytes = new byte[16];
    rand.nextBytes(bytes);
    IvParameterSpec ivSpec = new IvParameterSpec(bytes);
    System.out.println("length of bytes before converting to String: "   ivSpec.getIV().length);
    String ibString = new String(ivSpec.getIV());
    System.out.println("length of bytes after converting to String: "   ibString.getBytes().length);
  }
}
 

Пожалуйста, кто-нибудь может подтвердить, почему это такое поведение и что мне нужно изменить, чтобы получить ту же длину байта, т.е.: 16 в данном случае.

Комментарии:

1. Почему вы преобразуете эти случайные байты в a String ?

2. Не переходите к string, из-за кодировки сохранение байтов — лучший способ заставить ваш алгоритм работать. Не ищите хитрый способ решить ВАШЕ странное решение: избегайте вашего странного решения.

3. В этом нет никакого смысла. String предназначен для хранения текста в Юникоде. Случайные байты, которые вы получаете от a SecureRandom , не являются текстом. Вам нужно будет более конкретно рассказать о том, что вы пытаетесь сделать, чтобы получить дополнительную помощь.

4. Поскольку случайно сгенерированный IV будет содержать много байтов, которые не могут быть закодированы как string (например, #00), вы НЕ должны преобразовывать его в строку таким образом. Если вы хотите объединить данные, сделайте это на основе byte[] . Если вам нужно их транспортировать (например, по почте), пожалуйста, закодируйте массив байтов в Base64, а затем декодируйте его обратно в массив байтов для последующего использования.

5. Я имею в виду: возможно, вам нужно решить эту проблему (строковую), НО лучшим способом было бы избежать этого вообще. Вы можете видеть, что в качестве комментария вы можете получить

Ответ №1:

Пожалуйста, не преобразуйте случайно сгенерированный массив байтов в строку, поскольку существует множество значений, которые не могут быть закодированы в строку — просто подумайте о x00.

Обычным способом «преобразования» такого массива байтов в строку является кодировка массива байтов Base64. Это удлинит строку примерно на 1/3, но вы можете без потерь перекодировать строку в массив байтов.

Пожалуйста, обратите внимание, что вы не должны использовать Random but SecureRandom в качестве источника этих данных.

вывод:

 length of bytes before converting to String: 16
ivBase64:  wQtdbbbFdvrorpFb6LRTw==
length of bytes after converting to String: 16
ivSpec equals to ivRedecoded: true
 

код:

 import javax.crypto.spec.IvParameterSpec;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Base64;

public class Main {
    public static void main(String[] args) {
        //Random rand = new SecureRandom();
        SecureRandom rand = new SecureRandom();
        byte[] bytes = new byte[16];
        rand.nextBytes(bytes);
        IvParameterSpec ivSpec = new IvParameterSpec(bytes);
        System.out.println("length of bytes before converting to String: "   ivSpec.getIV().length);
        //String ibString = new String(ivSpec.getIV());
        String ivBase64 = Base64.getEncoder().encodeToString(ivSpec.getIV());
        System.out.println("ivBase64: "   ivBase64);
        byte[] ivRedecoded = Base64.getDecoder().decode(ivBase64);
        //System.out.println("length of bytes after converting to String: "   ibString.getBytes().length);
        System.out.println("length of bytes after converting to String: "   ivRedecoded.length);
        System.out.println("ivSpec equals to ivRedecoded: "   Arrays.equals(ivSpec.getIV(), ivRedecoded));
    }
}