如何逐字节地将SHA-1应用于大十六进制数?

时间:2012-08-07 03:24:44

标签: java sha

我正在尝试创建一个程序,使我能够将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[] b = new BigInteger(hexMEID,16).toByteArray();    

    byte[] result = mDigest.digest(b);
    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给出6ad447f040941bf43c0693d2b391c6c79fa58320而不是e3be267a2cd5c861f3c7ea4224df829a3551f1ab。我在这做错了什么?

有人给了我一个暗示

  

诀窍是将SHA-1应用于代表MEID的数字,而不是   表示MEID的字符串。 您需要处理它   逐字节,所以你必须一次给它两个十六进制数字(因为两个   十六进制数字构成一个字节)并确保它们被解释为数字   而不是ASCII字符

如果这些指令为真,那么如何逐字节地将SHA-1应用于我的十六进制数?

2 个答案:

答案 0 :(得分:4)

你有一个小问题,这是使用BigInteger获取你的字节数组的结果。由于MEID只有7个字节长,当你通过BigInteger泵送它时,你将得到一个长度为8的字节数组,因为BigInteger输出保存符号的exta字节。当然,这个额外的字节会导致输入的SHA-1哈希完全不同。你需要剥掉它。

所以这是ESN代码的HEX MEID的样子:

String hexMEID = "A0000000002329";
MessageDigest mDigest = MessageDigest.getInstance( "SHA1" );

byte[] input = new byte[ 7 ]; // MEIDs are only 7 bytes

// Now copy the bytes from BigInteger skipping the extra byte added by it
System.arraycopy( new BigInteger( hexMEID, 16 ).toByteArray(), 1, input, 0, 7 );

// Get the SHA-1 bytes
byte[] result = mDigest.digest( input );

// Build the SHA-1 String
StringBuilder sb = new StringBuilder();
for ( int i = 0; i < result.length; i++ )
{
    String hex = Integer.toHexString( 0xFF & result[ i ] );
    if ( hex.length() == 1 )
    {
        sb.append( '0' );
    }
    sb.append( hex );
}

String sha1 = sb.toString();
// Grab the last 6 characters of the SHA-1 hash
String lastSix = sha1.substring( sha1.length() - 6 );
// And prepend '80', now you have the ESN
System.out.println( "80" + lastSix );
// Will print 8051f1ab which is exactly what you want

答案 1 :(得分:2)

Strelok发现了BigInteger在返回的数组中添加额外字节的问题。这个更简单的版本也给出了预期的结果:

String hexMEID = "A0000000002329";

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

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

// skip the first byte set by BigInteger and retain only 7 bytes (length of MEID)
byte[] result = mDigest.digest(Arrays.copyOfRange(b, 1, 8));

StringBuilder sb = new StringBuilder("80");

// need only the last 3 bytes
for (int i=17; i<20; i++) {
    sb.append(Integer.toHexString((result[i] & 0xff) | 0x100).substring(1));
}

String pESN = sb.toString();
System.out.println(pESN);
// -> 8051f1ab