字节与其16进制字符表示转换的bug
1、原始的字节一旦用16进制字符表示,还原回字节的时候不能直接hexStr.getBytes()
String tHex = SmUtil.sm3(...); // 返回的是 64 个十六进制字符,如 "3a5f…” BigInteger t = new BigInteger(tHex.getBytes()); // 这是 64 个 ASCII 码字节,不是 32 个哈希字节
hex字符串,就是对字节数据用16进制字符这个规则进行编码,然后转化为字符串。64个16进制字符算起来也是32字节。
tHex这里是32字节 hash byte的16进制字符串表示。
那么tHex.getBytes()是还原为字节数组。但问题出在这里,是每个字符去还原为1个字节,变成了64字节。
byte[] tBytes = HexUtil.decodeHex(tHex); 这里是真正的还原,就是每2个字符作为一个字节,是32字节。
2、new BigInteger(byte[] src) 把字节数组当作有符号大端整数解析。如果 src[0] 的最高位是 1,BigInteger 会把它理解为负数,toByteArray() 还原时会在前面补一个 0x00 字节,导致长度多1个字节。
即,首先new BigInteger(1, src) 保证按照正数来处理,最高位又是1, t = new BigInteger(1, src) ,那么t.toByteArray()会在最前加0x00,来明确说这个是正数,避免最高位是1表示负数的歧义, 如果最高位是0那就不用补位了;如果是t = new BigInteger(src)且src最高位是1,那么t.toByteArray()不会在前面补充,最高位是0当然也不用补位。
浙公网安备 33010602011771号