Erlang и JavaScript MD5 Digest Match - PullRequest
5 голосов
/ 25 июля 2011

Тестирование реализации MD5 в Javascript здесь: http://www.webtoolkit.info/javascript-md5.html дает следующий вывод:

MD5("muzaaya") = "00e081abefbbbf72b2d5258196a9b6d0"

Переход к моей оболочке erlang и вычисление MD5 того жезначение, которое я получаю это:

Eshell V5.8.4  (abort with ^G)
1> erlang:md5("muzaaya").
<<0,224,129,171,239,187,191,114,178,213,37,129,150,169,
  182,208>>
2>

Как я могу сравнить два?Если результат MD5 из приложения JavaScript передается на мой бэкэнд Erlang, я бы хотел сравнить два дайджеста.Как я могу сопоставить дайджест Javascript MD5 с дайджестом Эрланга?

Ответы [ 5 ]

16 голосов
/ 25 июля 2011

Хеш MD5 по сути является 128-битным числом.

Вы получаете значение MD5 в Erlang в виде двоичного файла из 16 байтов (16 * 8 = 128 бит). Каждый байт в этом двоичном файле должен быть преобразован в шестнадцатеричное представление, чтобы быть сопоставимым с выводом JavaScript MD5 (который представляет собой шестнадцатеричную строку с двумя символами на байт):

2> lists:flatten([io_lib:format("~2.16.0b", [B]) || <<B>> <= MD5]).
"00e081abefbbbf72b2d5258196a9b6d0"

Сначала мы берем каждый байт из двоичного файла и используем модуль io_lib, чтобы отформатировать его в шестнадцатеричную строку. Затем мы используем функцию flatten для отображения ее в виде читаемой строки (хотя в этом нет необходимости, если вы собираетесь записать значение в файл или сокет, поскольку они могут обрабатывать глубокие списки ввода-вывода, вложенные списки символов или двоичные файлы).

Используемая строка формата, ~2.16.0b означает форматирование целого числа (b), используя основание 16 и заполнение до ширины 2 с символом заполнения 0 (см. io:format/3 для полного руководства).

Если вы хотите двоичный файл, вы можете использовать следующее двоичное понимание:

3> << << (list_to_binary(io_lib:format("~2.16.0b", [C])))/binary >>
     || <<C>> <= MD5 >>.
<<"00e081abefbbbf72b2d5258196a9b6d0">>

(вместо io_lib:format/2 также есть http_util:integer_to_hexlist/1, хотя я не знаю, быстрее ли он)

4 голосов
/ 07 сентября 2011

Еще одна и более быстрая версия:

hstr(B) when is_binary(B) ->
  << <<(hex(A)), (hex(B))>> || <<A:4,B:4>> <= B >>.

-compile({inline, [hex/1]}).

hex(0)  -> $0;
hex(1)  -> $1;
hex(2)  -> $2;
hex(3)  -> $3;
hex(4)  -> $4;
hex(5)  -> $5;
hex(6)  -> $6;
hex(7)  -> $7;
hex(8)  -> $8;
hex(9)  -> $9;
hex(10) -> $a;
hex(11) -> $b;
hex(12) -> $c;
hex(13) -> $d;
hex(14) -> $e;
hex(15) -> $f.

, но самой быстрой версией будет

md5_hex(L) ->
  << A1:4, A2:4,  A3:4,  A4:4,  A5:4,  A6:4,  A7:4,  A8:4,
    A9:4,  A10:4, A11:4, A12:4, A13:4, A14:4, A15:4, A16:4,
    A17:4, A18:4, A19:4, A20:4, A21:4, A22:4, A23:4, A24:4,
    A25:4, A26:4, A27:4, A28:4, A29:4, A30:4, A31:4, A32:4
    >> = erlang:md5(L),
  << (hex(A1)), (hex(A2)),  (hex(A3)),  (hex(A4)),
    (hex(A5)),  (hex(A6)),  (hex(A7)),  (hex(A8)),
    (hex(A9)),  (hex(A10)), (hex(A11)), (hex(A12)),
    (hex(A13)), (hex(A14)), (hex(A15)), (hex(A16)),
    (hex(A17)), (hex(A18)), (hex(A19)), (hex(A20)),
    (hex(A21)), (hex(A22)), (hex(A23)), (hex(A24)),
    (hex(A25)), (hex(A26)), (hex(A27)), (hex(A28)),
    (hex(A29)), (hex(A30)), (hex(A31)), (hex(A32)) >>.

, но вам не нужно делать эту оптимизацию.

РЕДАКТИРОВАТЬ: Эта версия hex/1 еще быстрее:

hex(X) ->
  element(X+1, {$0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $a, $b, $c, $d, $e, $f}).

EDIT2: Еще один подход:

md5_hex(L) ->
    <<X:128>> = erlang:md5(L),
    B = integer_to_binary(X,16),
    list_to_binary([lists:duplicate(32-byte_size(B),$0)|B]).
3 голосов
/ 25 июля 2011

Вот версия для понимания цепочки битов, возможно, самая быстрая и наиболее эффективная для памяти:

hstr(B) when is_binary(B) ->
    T = {$0,$1,$2,$3,$4,$5,$6,$7,$8,$9,$a,$b,$c,$d,$e,$f},
    << <<(element(X bsr 4 + 1, T)), (element(X band 16#0F + 1, T))>>
    || <<X:8>> <= B >>.

3> M: hstr (erlang: md5 ("muzaaya")).

4> << "00e081abefbbbf72b2d5258196a9b6d0" >>

3 голосов
/ 25 июля 2011

Если вам нужен однострочник, это может быть что-то вроде этого:

1> B = erlang:md5("muzaaya").
<<0,224,129,171,239,187,191,114,178,213,37,129,150,169,
  182,208>>
2> lists:flatten([io_lib:format("~2.16.0b", [C]) || <<C>> <= B]).
"00e081abefbbbf72b2d5258196a9b6d0"
2 голосов
/ 25 июля 2011

Если вы хотите сделать это на стороне JavaScript, вы можете использовать это

function md5HexToArray ( hexStr ) {  
  var i, arr = [], arraylength = hexStr.length/2;

  for( i = 0; i < arraylength ; i++ ) {
     arr[i] = parseInt( hexStr.substr(i*2,2), 16) ;
  }

  return arr;
};

Но комментарий @ Wrikken выглядит так, как будто он тоже должен работать.

...