PHP和Java hmac哈希输出匹配十六进制,在原始二进制文件中不匹配。发生了什么? [英] PHP and Java hmac hash output matches in hex, doesn't match in raw binary. What's happening?

查看:179
本文介绍了PHP和Java hmac哈希输出匹配十六进制,在原始二进制文件中不匹配。发生了什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个Java游戏,它将打包为applet,我正在研究网络方面。我设计了一个会话流程,可以满足请求频率和安全需求,而无需使用SSL。数据传输过程基于facebook在其OAuth流程中使用signed_token的方式。这是简化的上下文:

I'm developing a game in Java that will be packaged as an applet, and I'm working on the networking aspect. I've designed a session flow that will work for the frequency of requests and the security needs, without requiring the use of SSL. The data transmission process is loosely based off of the way facebook signs their signed_token used with their OAuth process. Here's the simplified context:


  • 我的php / java实现使用hash_hmac / javax.crypto.Mac来生成用于签署有效负载的模糊签名,基于共享,秘密,唯一令牌和各种JSON有效载荷

  • 两个输出必须完全匹配,因为它们是更大的编码/解码压缩方案的一部分

  • 此签名将通过带有效负载的URL传递,并用于验证有效负载的有效性和完整性

正如您可以推断的那样,如果它们不匹配,那么由于发送的数据无效,我丢弃了数据包和错误。我的问题是,虽然结果的十六进制编码完全匹配,但原始二进制文件似乎不匹配。下面是我设置的提取的php和Java测试用例:

As you can infer, if they don't match, then I have dropped packets of data and errors due to invalid data sent. My issue is that, while the hex encoding of the result matches perfectly, the raw binary doesn't seem to ever match. Below are the extracted php and Java test cases I set up:

注意:由于php和java如何为php关联数组生成JSON结构的差异/ java hashmaps,我使用秘密的值代替字符串有效负载,以便两个字段在平台之间保持一致。

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

ff21a9e468ac49863e5e992324ac8bc92f239a08100b0f329b087be16f5ad382

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

ÿ!©äh¬I†>^™#$¬‹É/#š2›{áoZÓ‚

Java:

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

ff21a9e468ac49863e5e992324ac8bc92f239a08100b0f329b087be16f5ad382

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

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

当复制到php并告诉echo时,第二个字符串如下所示:

When copied to php and told to echo, that second string looks like this:


:�!��h�I�> ^�#$���/#���2{�oZÓ,

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

请注意,虽然十六进制相同,但二进制文件不同,但在从同一来源显示时包含相同的结尾(oZÓ,)。实际上,它按顺序包含所有更常见的字符(!hI> ^#$ /#2 {oZÓ,)。我玩了把控制台输出复制到php然后显示为二进制字符串,常规字符串,utf8_encode'd二进制/常规字符串,以及utf8_encode'ing $ hmac_b。似乎没有什么能使原始版本匹配。

Note that while the hex is identical, the binary is different, but contains the same ending ( oZÓ‚ ) when displayed from the same source. Actually, it contains all of the more common characters (!hI>^#$/#2{oZÓ,) in order. I played around with copying the console output to php then displaying as a binary string, regular string, utf8_encode'd binary/regular string, and also utf8_encode'ing $hmac_b. Nothing seems to make the raw versions match up.

我在php的hmac上运行了mb_detect_encoding,它告诉我UTF-8。我还将javax.crypto.Mac中的所有内容设置为UTF-8,并显示为UTF-8,但没有骰子。 我知道Java的UTF-8与php的UTF-8没什么不同,因为它违背了标准字符集的概念。这里发生了什么?

I've run mb_detect_encoding on php's hmac, and it told me UTF-8. I've also set everything in javax.crypto.Mac to UTF-8, and displayed as UTF-8, but no dice. I know Java's UTF-8 isn't different than php's UTF-8, because that defies the concept of having standard character sets. What's going on here?

注意:虽然我现在更喜欢并且能够使用十六进制版本进行URL编码,但我仍然想知道这个字符集的废话是什么,以及可能如何解决它。

推荐答案

我不是Java专家,但看起来你做了两件不同的事......

I'm no Java expert, but it looks like you're doing two different things...

你在PHP中使用 htmlentities(),它正在转换像ÿ& yulm; ,而你的Java剪辑试图转出UTF-8数据。

You are using htmlentities() in PHP, which is converting characters like ÿ to &yulm;, whereas your Java snipped is trying to dump out UTF-8 data.

为什么在HMAC之后你真的期待有效的UTF-8数据? UTF-8用于表示Unicode字符,而不是随机哈希值。

Why are you actually expecting valid UTF-8 data after a HMAC? UTF-8 is for representing Unicode characters, not random hashes.

在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识别终端中):

I get the following (in a UTF-8 aware terminal):

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

这完全是预期的。 $ hmac_b 实际上二进制被解释为UTF-8,因此它将充满无效的UTF-8序列。不要指望它是人物。您将以ISO-8859-1输出更好地查看它,这不是多字节:

This is entirely expected. $hmac_b is effectively binary being interpreted as UTF-8, so it will be full of invalid UTF-8 sequences. Don't expect it to be characters. You will be better looking at it in as ISO-8859-1 output, which isn't multibyte:

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

(输出结尾还有一个控制字符 \ x82

(There's also a control character on the end of that output \x82)

重点是,您要将苹果与梨包装中的橙子进行比较。

The point is, you're comparing apples with oranges in pear packaging.

这篇关于PHP和Java hmac哈希输出匹配十六进制,在原始二进制文件中不匹配。发生了什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆