Кодировка строки SHA-512: результат С# и JAVA отличается

Я пытаюсь сравнить две разные строки, закодированные sha512. Но результат разный. Я имею в виду, что это может быть проблема с кодировкой. Я надеюсь, что вы можете мне помочь.

Это мой код Java:

    MessageDigest digest = java.security.MessageDigest.getInstance("SHA-512"); 
    digest.update(MyString.getBytes()); 
    byte messageDigest[] = digest.digest();

    // Create Hex String
    StringBuffer hexString = new StringBuffer();
    for (int i = 0; i < messageDigest.length; i++) {
        String h = Integer.toHexString(0xFF & messageDigest[i]);
        while (h.length() < 2)
            h = "0" + h;
        hexString.append(h);
    }
    return hexString.toString();

и это мой код С#:

        UnicodeEncoding UE = new UnicodeEncoding();
        byte[] hashValue;
        byte[] message = UE.GetBytes(MyString);

        SHA512Managed hashString = new SHA512Managed();
        string hex = "";

        hashValue = hashString.ComputeHash(message);
        foreach (byte x in hashValue)
        {
            hex += String.Format("{0:x2}", x);

        }
        return hex;

В чем проблема ? Большое спасибо, ребята

ОБНОВЛЕНИЕ

Если я не укажу тип кодировки, я думаю, что это Unicode. Результат такой (ничего не уточняя):

Java SHA: a99951079450e0bf3cf790872336b3269da580b62143af9cfa27aef42c44ea09faa83e1fbddfd1135e364ae62eb373c53ee4e89c69b54a7d4d268cc2274493a8

C# SHA: 70e6eb559cbb062b0c865c345b5f6dbd7ae9c2d39169571b6908d7df04642544c0c4e6e896e6c750f9f135ad05280ed92b9ba349de12526a28e7642721a446aa

Вместо этого, если я укажу UTF-16 в Java:

Java UTF-16: SHA f7a587d55916763551e9fcaafd24d0995066371c41499fcb04614325cd9d829d1246c89af44b98034b88436c8acbd82cd13ebb366d4ab81b4942b720f02b0d9b

Всегда разное!!!


person kinghomer    schedule 24.02.2012    source источник
comment
Что происходит, когда вы указываете кодировку в MyString.getBytes()? (Плохое имя переменной, кстати.)   -  person Hauke Ingmar Schmidt    schedule 24.02.2012
comment
Вы сравнивали байты MyString перед вычислением хэша?   -  person L.B    schedule 24.02.2012
comment
Было бы неплохо предоставить нам полные образцы кода, а также ваш ввод/вывод.   -  person wkl    schedule 24.02.2012
comment
Ваши типы кодирования отличаются.   -  person Security Hound    schedule 24.02.2012
comment
Я надеюсь, что это не используется для хеширования паролей...   -  person CodesInChaos    schedule 24.02.2012
comment
Я хочу объединить пользователя и передать строку и хешировать их вместе. Я знаю, что у меня другой тип кодировки, но я не знаю, какой тип кодировки правильный!   -  person kinghomer    schedule 24.02.2012


Ответы (3)


Используемый вами UnicodeEncoding в C# соответствует little-endian кодировка UTF-16, в то время как "UTF-16" в Java соответствует big-endian кодировке UTF-16. Еще одно отличие состоит в том, что C# не выводит маркер порядка байтов (называемый в API "преамбулой"), если вы его не запрашиваете, в то время как "UTF-16" в Java генерирует его всегда. Чтобы сделать две программы совместимыми, вы можете заставить Java также использовать UTF-16 с прямым порядком байтов:

digest.update(MyString.getBytes("UTF-16LE"));

Или вы можете переключиться на другую известную кодировку, например UTF-8.

person Joni    schedule 24.02.2012

Здесь,

digest.update(MyString.getBytes()); 

вы должны явно указать желаемую кодировку символов в методе String#getBytes(). В противном случае по умолчанию будет использоваться кодировка платформы по умолчанию, полученная с помощью Charset#defaultCharset().

Исправьте это соответствующим образом:

digest.update(MyString.getBytes("UTF-16LE")); 

По крайней мере, это должна быть та же кодировка, что и UnicodeEncoding для внутреннего использования.


Не связанный с конкретной проблемой, Java также имеет расширенный цикл for и String#format().

person BalusC    schedule 24.02.2012
comment
UnicodeEncoding, по-видимому, использует UTF-16LE. Я обновил ответ. - person BalusC; 25.02.2012

Причина, вероятно, в том, что вы не указали кодировку для использования при преобразовании строки в байты, java использует кодировку платформы по умолчанию, а UnicodeEncoding, похоже, использует utf-16.

Изменить:

В документации по UnicodeEncoding говорится

Этот конструктор создает экземпляр, который использует порядок байтов с прямым порядком байтов, предоставляет метку порядка байтов Unicode и не генерирует исключение при обнаружении недопустимой кодировки.

Однако Javas "utf-16", по-видимому, по умолчанию использует порядок байтов big endian. С кодировками символов лучше быть очень конкретным, есть конструктор UnicodeEncoding, принимающий два логических значения с указанием порядка байтов, а в java есть еще "utf-16le" и "utf-16be". Вы можете попробовать следующее в С#

new UnicodeEncoding(true, false) // big endian, no byte order mark

и в джаве

myyString.getBytes("utf-16be")

Или, что еще лучше, используйте "utf-8" / Encoding.UTF8 в обоих случаях, поскольку на него не влияет другой порядок байтов.

person Jörn Horstmann    schedule 24.02.2012
comment
Неа. Однако происходит другой результат - person kinghomer; 24.02.2012