Вывод хеширования hmac PHP и Java соответствует шестнадцатеричному, не соответствует в двоичном формате. Что происходит?

Я разрабатываю игру на Java, которая будет упакована в виде апплета, и я работаю над сетевым аспектом. Я разработал поток сеанса, который будет работать для частоты запросов и потребностей безопасности, не требуя использования SSL. Процесс передачи данных свободно основан на том, как facebook подписывает свой подписанный_токен, используемый с их процессом OAuth. Вот упрощенный контекст:

  • мои реализации php / java используют hash_hmac / javax.crypto.Mac для создания скрытой подписи для подписи полезной нагрузки на основе общего, секретного, уникального токена и разнообразной полезной нагрузки JSON
  • оба выхода должны соответствовать точно, потому что они являются частью более крупной схемы сжатия кодирования / декодирования
  • эта подпись будет передаваться через URL с полезной нагрузкой и используется для проверки полезной нагрузки для достоверности и целостности

Как вы можете сделать вывод, если они не совпадают, тогда я сбросил пакеты данных и ошибок из-за недействительных данных. Моя проблема в том, что, в то время как шестнадцатеричное кодирование результата идеально соответствует, необработанный двоичный код, похоже, никогда не соответствует . Ниже приведены извлеченные тестовые примеры php и Java, которые я установил:

Примечание. Из-за различий в том, как php и java генерируют структуру JSON для ассоциативных массивов php / java, я использую значение секретности вместо полезной нагрузки строки, чтобы оба поля были согласованы между платформами.

Php:

$secret = "922ec205d8e4d0ea06079d60a5336fffd9cf0aea"; $json = $secret; //json_encode($test_array); $hmac_a = hash_hmac('sha256',$json,$secret); $hmac_b = hash_hmac('sha256',$json,$secret,$raw=true); echo(htmlentities($hmac_a)."<br/>\n"); echo(htmlentities($hmac_b)."<br/>\n"); 

Вывод в браузере:

ff21a9e468ac49863e5e992324ac8bc92f239a08100b0f329b087be16f5ad382

ÿ! © äh¬I †> ^ ™ # $ ¬ <Э / # Š2> {áoZÓ,

Ява:

 Mac hmac = Mac.getInstance("HmacSHA256"); SecretKeySpec secret_key = new SecretKeySpec(Charset.forName("UTF-8").encode(this.secret).array(), "HmacSHA256"); hmac.init(secret_key); byte[] digest = hmac.doFinal(this.secret.getBytes("UTF-8")); System.out.println(hexify(digest)); System.out.println(new String(digest,"UTF-8")); 

Консольный выход:

ff21a9e468ac49863e5e992324ac8bc92f239a08100b0f329b087be16f5ad382

! h I > ^ # $ / # 2 { oZӂ

При копировании на php и произнесении эхо, эта вторая строка выглядит так:

: Ï¿½ ��h�I�> ^ � # $ ��� / # ���2 {�oZÓ,

Обратите внимание, что хотя шестнадцатеричный код идентичен, двоичный файл отличается, но содержит тот же конец (oZÓ,), когда отображается из одного источника. Фактически, он содержит все более общие символы (! HI> ^ # $ / # 2 {oZÓ,) по порядку. Я играл с копированием вывода консоли на php, а затем отображал как двоичную строку, регулярную строку, utf8_encode'd двоичную / регулярную строку, а также utf8_encode'ing $ hmac_b. Кажется, ничто не сравнит исходные версии.

Я запустил mb_detect_encoding на hmac php, и он сказал мне UTF-8. Я также установил все в javax.crypto.Mac для UTF-8 и отображался как UTF-8, но не играл в кости. Я знаю, что UTF-8 Java не отличается от UTF-8 php, потому что это противоречит концепции наличия стандартных наборов символов. Что тут происходит?

Примечание. Хотя я теперь предпочитаю и могу использовать шестнадцатеричную версию для кодировки URL, мне все равно хотелось бы знать, что происходит с этим набором символов, и, возможно, как это исправить.

Я не эксперт по Java, но похоже, что вы делаете две разные вещи …

Вы используете htmlentities() в PHP, который преобразует символы, такие как ÿ в &yulm; , в то время как ваша Java отключена, пытается сбросить данные UTF-8.

Почему вы действительно ожидаете действительных данных UTF-8 после HMAC? UTF-8 предназначен для представления символов Unicode, а не случайных хэшей.

Используя это в PHP:

 $secret = "922ec205d8e4d0ea06079d60a5336fffd9cf0aea"; $json = $secret; $hmac_a = hash_hmac('sha256',$json,$secret); $hmac_b = hash_hmac('sha256',$json,$secret,$raw=true); echo $hmac_a . "\n"; echo $hmac_b . "\n"; 

Я получаю следующее (в терминале с поддержкой UTF-8):

 ff21a9e468ac49863e5e992324ac8bc92f239a08100b0f329b087be16f5ad382  !  h I >^ #$   /#2{ oZӂ 

Это вполне ожидаемо. $hmac_b эффективно бинарно интерпретируется как UTF-8, поэтому он будет заполнен недопустимыми последовательностями UTF-8. Не ожидайте, что это будут персонажи. Вы будете лучше смотреть на него как на выход ISO-8859-1, который не является многобайтным:

 ff21a9e468ac49863e5e992324ac8bc92f239a08100b0f329b087be16f5ad382 �!��h�I�>^�#$���/#ï¿2ï¿{�oZÓ 

(В конце этого выхода есть также управляющий символ \x82 )

Дело в том, что вы сравниваете яблоки с апельсинами в грушей упаковке.