Андроид обратным порядком байтов MD5 в


Я портирую приложение Windows на Android, и у меня возникает проблема с endianness. Приложение берет ряд текстовых полей от пользователя и генерирует пароль на основе MD5. Проблема в том, что когда я создаю массив байтов для передачи в метод MD5 digest, байты в приложении для Android имеют формат big endian. Таким образом, выходные данные MD5 не совпадают между двумя платформами.

Я пробовал использовать ByteBuffer для преобразования в little endian, а затем скопировать это значение обратно в байт массив с использованием ByteBuffer.получить(). К сожалению, это не работает, так как не поддерживает установку порядка.. Это, кажется, известный "попался", когда имеешь дело с ByteBuffers. Если я сравниваю ByteBuffer.getLong () значение и эквивалент в версии windows значения совпадают, но я не знаю, как получить массив обратно из ByteBuffer в правильном порядке.

Edit: я прикрепил обе функции java и C# ниже.

Ниже приведена версия java, которая не пытается исправить порядок / конечность:

public static final long md5(final String input) {
    try {
        // Create MD5
        MessageDigest md5 = MessageDigest.getInstance("MD5");

        // Read in string as an array of bytes.
        byte[] originalBytes = input.getBytes("US-ASCII");
        byte[] encodedBytes = md5.digest(originalBytes);

        long output = 0;
        long multiplier = 1;

        // Create 64 bit integer from the MD5 hash of the input
        for (int i = 0; i < encodedBytes.length; i++) {
            output = output + encodedBytes[i] * multiplier;
            multiplier = multiplier * 255;
        }
        return output;

    } 
    catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
     catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
    return 0;
}

А вот версия C#

private Int64 MD5(string input)
{
  MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();

  byte[] originalBytes = ASCIIEncoding.ASCII.GetBytes(input);
  byte[] encodedBytes = md5.ComputeHash(originalBytes);
  Int64 output = 0;
  Int64 Multiplyer = 1;
  for (int i = 0; i < encodedBytes.Length; i++)
  {
    output = output + encodedBytes[i] * Multiplyer;
    Multiplyer = Multiplyer * 255;
  }
  return output;
}
2 3

2 ответа:

Проблема в том, что эта строка Java:

            output = output + encodedBytes[i] * multiplier;

Тонко отличается от этой строки кода C#:

    output = output + encodedBytes[i] * Multiplyer;
В частности, неявное преобразование encodedBytes[i] из byte в long (Java) или Int64 (C#) немного отличается.

Видите ли, в Java byte - это знаковое значение между -128 и 127, тогда как в C# это беззнаковое значение между 0 и 255. Так, например, если encodedBytes[i] является B2 (1011 0010), тогда Java интерпретирует это как -78, в то время как C# интерпретирует это как 178.

Чтобы эмулировать интерпретацию C# в Java, вы можете написать что-то вроде этого:

            output = output + ((encodedBytes[i] + 256) % 256) * multiplier;

(К счастью, Java имеет ту же обработку для переполнения целых чисел, что и "непроверенный" режим C#, который, по-видимому, вы используете; , что было бы намного сложнее эмулировать, если бы вам пришлось.)

СтандартMD5 вызывает 128-битные значения, а не 64-битные. Итак, во-первых, подпись private Int64 MD5(string input) не имеет смысла. Вы не должны преобразовывать их в целые числа и пытаться сравнить их. Просто передайте ссылки byte[] и сравните их.