0

我正在用 Java 开发一个游戏,该游戏将被打包为一个小程序,并且我正在研究网络方面。我设计了一个会话流,可以满足请求频率和安全需求,而不需要使用 SSL。数据传输过程松散地基于 facebook 签署其签名令牌与 OAuth 过程一起使用的方式。这是简化的上下文:

  • 我的 php/java 实现使用 hash_hmac/javax.crypto.Mac 基于共享的、秘密的、唯一的令牌和不同的 JSON 有效负载生成一个模糊的签名来签署有效负载
  • 两个输出必须完全匹配,因为它们是更大的编码/解码压缩方案的一部分
  • 此签名将通过 URL 与有效负载一起传递,并用于验证有效负载的有效性和完整性

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

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

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Ó‚</p>

爪哇:

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Ó,</p>

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

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

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

4

1 回答 1

3

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

htmlentities()在 PHP 中使用,它正在将字符转换ÿ&yulm;,而您的 Java 剪辑正在尝试转储 UTF-8 数据。

为什么您实际上希望在 HMAC 之后得到有效的 UTF-8 数据?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�&gt;^�#$���/#2{�oZӂ

这完全是意料之中的。$hmac_b实际上是二进制被解释为 UTF-8,因此它将充满无效的 UTF-8 序列。不要指望它是字符。您会更好地将其视为 ISO-8859-1 输出,它不是多字节的:

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

(该输出的末尾还有一个控制字符\x82

关键是,您将梨包装中的苹果与橙子进行比较。

于 2012-10-23T12:58:50.990 回答