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

Java 将字节数组编码为十六进制字符串,java,arrays,encoding,hex,Java,Arrays,Encoding,Hex,我遇到了一段将字节数组编码为十六进制字符串的遗留代码,该代码正在生产中,从未引起任何问题 这段代码用作: 我们加密用户密码。加密程序返回一个字节[] 我们使用此编码器代码将字节[]转换为十六进制字符串,然后在属性文件中使用该字符串表示形式,依此类推 然而,昨天我们发现了一个密码,其加密的byte[]版本编码不正确 import java.math.BigInteger; import java.util.HashMap; import org.apache.commons.codec.De

我遇到了一段将字节数组编码为十六进制字符串的遗留代码,该代码正在生产中,从未引起任何问题

这段代码用作:

  • 我们加密用户密码。加密程序返回一个
    字节[]
  • 我们使用此编码器代码将
    字节[]
    转换为十六进制字符串,然后在属性文件中使用该
    字符串
    表示形式,依此类推
然而,昨天我们发现了一个密码,其加密的
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;
    }
}
import java.math.biginger;
导入java.util.HashMap;
导入org.apache.commons.codec.DecoderException;
导入org.apache.commons.codec.binary.Hex;
公共类ByteArrayToHexEncoder{
公共静态void main(字符串[]args)引发Decode异常{
字符串hexString=“a0d21588c0a2c2fc68dc859197fc78cd”;//正确的十六进制表示法
//等效字节数组:这是加密程序返回的字节数组
字节[]byteArray=Hex.decodeHex(hexString.ToCharray());
//传统编码器
System.out.println(“遗留代码编码为:”+encodeHexBytesWithPadding(byteArray));
//通用编解码器
System.out.println(“Commons编解码器编码为:”+新字符串(Hex.encodeHex(byteArray));
}
私有静态最终字符串填充0=
"0000000000000000000000000000000000000000000000000000000000000";
私有静态最终HashMap映射_OF_HEX=新HashMap();
静止的{
映射十六进制put(0,'0');
映射十六进制put(1,'1');
映射十六进制put(2,'2');
映射十六进制put(3,'3');
映射十六进制put(4,'4');
映射十六进制put(5,'5');
映射十六进制put(6,'6');
映射十六进制put(7,'7');
映射十六进制put(8,'8');
映射十六进制put(9,'9');
映射十六进制put(10,'a');
映射十六进制put(11,'b');
映射十六进制put(12,'c');
十六进制put(13,'d')的映射;
映射十六进制put(14,'e');
映射十六进制put(15,'f');
}
公共静态字符串encodeHexBytesWithPadding(字节[]inputByteArray){
字符串encodedValue=encodeHexBytes(inputByteArray);
int expectedSize=inputByteArray.length*2;
if(encodedValue.length()>4)&0x0F;
encodedValue=新的大整数(inputByteArray).toString(16);
inputByteArray[0]=旧值;
encodedValue=十六进制get(半字节)+encodedValue的映射;
}否则{
encodedValue=新的大整数(inputByteArray).toString(16);
}
返回编码值;
}
}
传统代码将编码值输出为:
0ad21588c0a2c2fc68dc859197fc78cd
,而正确的预期值应为:
a0d21588c0a2c2fc68dc859197fc78cd

我正在试图理解编码器的错误,需要一些帮助来理解。

biginger(byte[])
构造函数用于处理最高有效位也表示符号的位置。通用编解码器将每个字节转换成十六进制表示,最高有效位没有特殊意义

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()
或检查。

请您再解释一下。。如果修改第一个字节以忽略2补码形式的符号是错误的?