简体   繁体   English

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

[英]Encoding byte array to Hex string

I have come across a legacy piece of code encoding byte array to hex string which is in production and have never caused an issue.我遇到了一段将字节数组编码为十六进制字符串的遗留代码,该代码正在生产中并且从未引起问题。

This piece of code is used as:这段代码用作:

  • We encrypt a user password.我们加密用户密码。 The encryptor returns a byte[] .加密器返回一个byte[]
  • We convert the byte[] to Hex String using this encoder code and then use that String representation in our properties file and so on.我们使用此编码器代码将byte[]转换为十六进制字符串,然后在我们的属性文件中使用该String表示,依此类推。

However, yesterday we have hit a password, whose encrypted byte[] version is getting encoded incorrectly.但是,昨天我们遇到了一个密码,其加密的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;
    }
}

The legacy code outputs the encoded value as: 0ad21588c0a2c2fc68dc859197fc78cd while the correct expected value should be: a0d21588c0a2c2fc68dc859197fc78cd .旧代码将编码值输出为: 0ad21588c0a2c2fc68dc859197fc78cd而正确的预期值应为: a0d21588c0a2c2fc68dc859197fc78cd

I am trying to understand what's wrong with the encoder and need some help understanding.我试图了解编码器出了什么问题,需要一些帮助理解。

BigInteger(byte[]) constructor is there to handle two's complement representation of a number where the most significant bit also denotes the sign. BigInteger(byte[])构造函数用于处理数字的二进制补码表示,其中最高有效位也表示符号。 The Hex common-codec simply translates each byte into a hex representation, there is no special meaning to the most significant bit. Hex通用编解码器只是简单地将每个字节转换为十六进制表示,最高有效位没有特殊含义。

Your legacy code in the if (inputByteArray[0] < 0) branch attempts to modify the first byte in the byte[] input probably to work around the representation of negative numbers in the two-complement's form eg -1 being represented as ff . if (inputByteArray[0] < 0)分支中的旧代码尝试修改byte[]输入中的第一个字节,可能是为了解决负数在二补码形式中的表示,例如-1表示为ff Unfortunately this is implemented incorrectly in your legacy code:不幸的是,这在您的旧代码中实现不正确:

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

will print将打印

00000000a1
a000000001

showing that the legacy code values are completely wrong.表明遗留代码值是完全错误的。

There is not much to salvage here IMO, instead use Hex.encodeHexString() instead or check other options discussed in this question . IMO 这里没有什么可挽救的,而是使用Hex.encodeHexString()代替或检查此问题中讨论的其他选项

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM