Как применить SHA-1 к большому шестнадцатеричному числу байт за байтом?

Я пытаюсь создать программу, которая позволит мне преобразовать MEID (шестнадцатеричное число длиной 14) в псевдоESN (шестнадцатеричное число длиной 8). Способ получения pESN от MEID теоретически довольно прост. Например, при наличии MEID 0xA0000000002329 для создания pESN необходимо применить SHA-1 к MEID. SHA-1 на A0000000002329 дает 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());
}

Проблема в том, что при использовании этого метода SHA-1 на A0000000002329 дает 6ad447f040941bf43c0693d2b391c6c79fa58320 вместо e3be267a2cd5c861f3c7ea4224df829a3551f1ab. Что я здесь делаю не так??

Кто-то подсказал мне, что

Хитрость заключается в том, чтобы применить SHA-1 к числу, представляющему MEID, а не к строке, представляющей MEID. Вам нужно будет обрабатывать его побайтно, поэтому вы должны дать ему два шестнадцатеричных числа за раз (поскольку два шестнадцатеричных числа составляют байт) и убедиться, что они интерпретируются как числа, а не символы ASCII.

Если эти инструкции верны, то как мне применить SHA-1 к моему шестнадцатеричному числу байт за байтом??


person user1578192    schedule 07.08.2012    source источник
comment
два шестнадцатеричных числа составляют байт?   -  person aviad    schedule 07.08.2012
comment
@aviad, конечно. 0xff == 255 (или 16x16-1, или 2^8-1, или 8 бит), что является байтом   -  person Yanick Rochon    schedule 07.08.2012
comment
@Yanick Rochon, я бы скорее сказал: для представления двухзначного шестнадцатеричного числа требуется 1 байт ...   -  person aviad    schedule 07.08.2012
comment
@aviad, ... или две шестнадцатеричные цифры представляют собой байт, это одно и то же.   -  person Yanick Rochon    schedule 07.08.2012


Ответы (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
person Yanick Rochon    schedule 07.08.2012

У вас есть небольшая проблема, которая является следствием использования BigInteger для получения массива байтов. Поскольку длина MEID составляет всего 7 байтов, при прокачке его через BigInteger вы получите массив байтов длиной 8, поскольку BigInteger выводит дополнительный байт, содержащий знак. Этот дополнительный байт, конечно, приводит к тому, что хеш SHA-1 вашего ввода будет совершенно другим. Вам нужно раздеть его.

Итак, вот как будет выглядеть код HEX MEID в ESN:

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
person Strelok    schedule 07.08.2012