将字节数组编码为十六进制字符串

我遇到了一个遗留代码段,将字节数组编码为十六进制字符串,这种代码正在生产中,并且从未引起问题。

这段代码用作:

  • 我们对用户密码进行加密。加密器返回一个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

我正试图了解编码器出了什么问题,需要一些帮助来理解。

z332150607 回答:将字节数组编码为十六进制字符串

BigInteger(byte[])构造函数可以处理two's complement representation of a number,其中最高有效位还表示符号。 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

显示旧代码值完全错误。

这里的IMO没什么可挽救的,可以改用Hex.encodeHexString()或检查other options discussed in this question

本文链接:https://www.f2er.com/3140843.html

大家都在问