如何将一个大字符串转换为十六进制,然后再转换为字节数组?

3
我每天都和手机打交道,并处理MEID号码。因此,我想到可以自己编写一个程序,而不是在网上搜索MEID(长度为14个十六进制数字的编号)到伪ESN(长度为8个十六进制数字的编号)计算器。从理论上讲,从MEID获取pESN的方法非常简单。例如,给定MEID 0xA0000000002329,要生成pESN,需要将SHA-1应用于MEID。对A0000000002329进行SHA-1运算得到e3be267a2cd5c861f3c7ea4224df829a3551f1ab。取该结果的最后6个十六进制数字,然后将其附加到0x80——结果为0x8051F1AB。
现在是我至今拥有的代码:
public void sha1() throws NoSuchAlgorithmException {

    String hexMEID = "A0000000002329";

    MessageDigest mDigest = MessageDigest.getInstance("SHA1");      

    byte[] result = mDigest.digest(hexMEID.getBytes());
    StringBuilder sb = new StringBuilder();

    for (int i = 0; i < result.length; i++) {
        sb.append(Integer.toString((result[i] & 0xff) + 0x100, 16).substring(1));
    }

    System.out.println(sb.toString());
}  

使用这种方法,对A0000000002329应用SHA-1算法会得到a89b611b421f57705bd013297ce3fc835f706ab0,而不是e3be267a2cd5c861f3c7ea4224df829a3551f1ab。我在这里做错了什么?
有人给了我一个提示:“诀窍是将SHA-1应用于表示MEID的数字,而不是表示MEID的字符串。你需要逐字节地处理它,所以你必须每次给出两个十六进制数(因为两个十六进制数组成一个字节),并确保它们被解释为数字而不是ASCII字符”。如果这是正确的,那么我该如何将我的字符串转换为十六进制,然后转换为字节,以便SHA1可以给我正确的结果?
3个回答

3

如果没有库,你可以按照这里的示例:

在Java中,如何将十六进制字符串转换为byte[]?

 byte[] b = new BigInteger(s,16).toByteArray();

我确定有许多库可以提供这个功能,其中一个是POJava:

<dependency>
    <groupId>org.pojava</groupId>
    <artifactId>pojava</artifactId>
    <version>2.8.1</version>
</dependency>


 byte[] hexMEIDBytes=EncodingTool.hexDecode(hexMEID);

[编辑] ==============

以下是根据您的后续问题提供的更完整示例:

    byte[] hexMEIDBytes = EncodingTool.hexDecode(hexMEID);
    byte[] hash = HashingTool.hash(hexMEIDBytes, HashingAlgorithm.SHA);
    String pESN="0x80" + EncodingTool.hexEncode(hash).substring(34).toUpperCase();
    // a hexMEID value of "A0000000002329" results in a pESN value of "0x8051F1AB"

谢谢,这似乎解决了将实际十六进制数转换为字节的问题。现在我需要找到一种逐字节将其输入到sha-1中的方法。 - user1578192

2

将字符串转换为十六进制:

public String StrToHex(String arg) {

    return String.format("%040x", new BigInteger(arg.getBytes(//Your Charset//)));
}

十六进制转字节:

下面的代码对于“0”无法工作。

public byte[] hexStrToByteArray(String s) {
    int leng = s.length();
    byte[] data = new byte[leng / 2];
    for (int i = 0; i < leng; i += 2) {
        data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                             + Character.digit(s.charAt(i+1), 16));
    }
    return data;
}

1
您可以使用以下两种方法。
    public static synchronized String bytesToHex(byte [] buf){
        StringBuffer strbuf = new StringBuffer(buf.length * 2);
        int i;
        for (i = 0; i < buf.length; i++) {
            if (((int) buf[i] & 0xff) < 0x10){
                strbuf.append("0");
            }
            strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
        }
        return strbuf.toString();
    }

    public synchronized static byte[] hexToBytes(String hexString) {
         byte[] b = new BigInteger(hexString,16).toByteArray();     
         return b;
    }

1
这将抑制前导零字节。因此,字符串“007b”将仅产生new byte [] {0x7b},而不是new byte [] {00,0x7b} - President James K. Polk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接