Андроид обратным порядком байтов 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 ответа:
Проблема в том, что эта строка 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[]
и сравните их.