Кодирование байтового массива в шестнадцатеричную строку - PullRequest
0 голосов
/ 08 ноября 2019

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

Этот фрагмент кода используется как:

  • Зашифровываем пароль пользователя. Шифратор возвращает byte[].
  • . Мы конвертируем byte[] в шестнадцатеричную строку, используя этот код кодера, а затем используем это представление String в нашем файле свойств и т. Д.

Однако вчера мы ввели пароль, чья зашифрованная версия byte[] кодируется неправильно.

import java.math.BigInteger;
import java.util.HashMap;

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;

public class ByteArrayToHexEncoder {

    public static void main(String[] args) throws DecoderException {
        String hexString = "a0d21588c0a2c2fc68dc859197fc78cd"; // correct hex representation
        // equivalent byte array: this is the byte array returned by the encryptor
        byte[] byteArray = Hex.decodeHex(hexString.toCharArray());

        // legacy encoder
        System.out.println("Legacy code encodes as: " + encodeHexBytesWithPadding(byteArray));

        // commons-codec encoder
        System.out.println("Commons codec encode as: " + new String(Hex.encodeHex(byteArray)));
    }

    private static final String PADDING_ZEROS =
            "0000000000000000000000000000000000000000000000000000000000000";

    private static final HashMap<Integer, Character> MAP_OF_HEX = new HashMap<>();
    static {
        MAP_OF_HEX.put(0, '0');
        MAP_OF_HEX.put(1, '1');
        MAP_OF_HEX.put(2, '2');
        MAP_OF_HEX.put(3, '3');
        MAP_OF_HEX.put(4, '4');
        MAP_OF_HEX.put(5, '5');
        MAP_OF_HEX.put(6, '6');
        MAP_OF_HEX.put(7, '7');
        MAP_OF_HEX.put(8, '8');
        MAP_OF_HEX.put(9, '9');
        MAP_OF_HEX.put(10, 'a');
        MAP_OF_HEX.put(11, 'b');
        MAP_OF_HEX.put(12, 'c');
        MAP_OF_HEX.put(13, 'd');
        MAP_OF_HEX.put(14, 'e');
        MAP_OF_HEX.put(15, 'f');
    }

    public static String encodeHexBytesWithPadding(byte[] inputByteArray) {
        String encodedValue = encodeHexBytes(inputByteArray);
        int expectedSize = inputByteArray.length * 2;
        if (encodedValue.length() < expectedSize) {
            int zerosToPad = expectedSize - encodedValue.length();
            encodedValue = PADDING_ZEROS.substring(0, zerosToPad) + encodedValue;
        }
        return encodedValue;
    }

    public static String encodeHexBytes(byte[] inputByteArray) {
        String encodedValue;
        if (inputByteArray[0] < 0) {
            // Something is wrong here! Don't know what!
            byte oldValue = inputByteArray[0];
            inputByteArray[0] = (byte) (oldValue & 0x0F);
            int nibble = (oldValue >> 4) & 0x0F;
            encodedValue = new BigInteger(inputByteArray).toString(16);
            inputByteArray[0] = oldValue;
            encodedValue = MAP_OF_HEX.get(nibble) + encodedValue;
        } else {
            encodedValue = new BigInteger(inputByteArray).toString(16);
        }
        return encodedValue;
    }
}

Унаследованный код выводит закодированное значение как: 0ad21588c0a2c2fc68dc859197fc78cd, тогда как правильное ожидаемое значение должно быть: a0d21588c0a2c2fc68dc859197fc78cd.

Я пытаюсь понять, что не так с кодировщиком, и мне нужна помощь в понимании.

1 Ответ

0 голосов
/ 08 ноября 2019

BigInteger(byte[]) конструктор для обработки представления дополнения до двух числа , где старший значащий бит также обозначает знак. Общий кодек Hex просто переводит каждый байт в шестнадцатеричное представление, и нет особого значения для самого значимого бита.

Ваш устаревший код в ветви if (inputByteArray[0] < 0) пытается изменить первый байт вbyte[] ввод, вероятно, для обхода представления отрицательных чисел в форме двух дополнений, например, -1 представляется как ff. К сожалению, это неправильно реализовано в вашем устаревшем коде:

String input = "a000000001";
byte[] bytes = Hex.decodeHex(input.toCharArray());
System.out.println(encodeHexBytesWithPadding(bytes));
System.out.println(Hex.encodeHexString(bytes));

напечатает

00000000a1
a000000001

, показывая, что значения устаревшего кода совершенно неверны.

Здесь не так много для спасения ИМО, вместо этого используйте Hex.encodeHexString() или отметьте другие варианты, обсуждаемые в этом вопросе .

...