【问题标题】:OpenSSL::HMAC.hexdigest PHP equivalent won't print the same result as ruby oneOpenSSL::HMAC.hexdigest PHP 等效项不会打印与 ruby​​ one 相同的结果
【发布时间】:2020-01-17 17:19:44
【问题描述】:

这是我需要转换为 PHP 的 ruby​​ 代码:

print OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha1"), 'hello', Base64.encode64('bonjour'))

输出:

62ac34e5d28563d6a50272d660805d1f8c791e41

这是我的 PHP 代码:

echo hash_hmac('sha1', base64_encode('bonjour'), 'hello');

输出:

89ebf8bd3d92bf3283aa4c5f24072820258367e4

我找不到62ac34... 的方法。

我也试过了:

echo hash_hmac('sha1', 'bonjour', 'hello'); // 1
echo hash_hmac('sha1', 'hello', 'bonjour'); // 2
echo hash_hmac('sha1', base64_encode('hello'), 'bonjour'); // 3
echo hash_hmac('sha1', 'hello', base64_encode('bonjour')); // 4
echo base64_encode(hash_hmac('sha1', 'hello', 'bonjour', TRUE)); //5

这也是错误的。输出:

bed443484cc49c41c053a11dd15e44d4f79c524f // 1
16923f8d6e9afd345cf947fc963cad73aa12b76c // 2
8e5989976296c76f0462fe33c6bc2dec48bdcb5a // 3
ca237e79f77e6d9739db45fc5d162da3a4036639 // 4
FpI/jW6a/TRc+Uf8ljytc6oSt2w= // 5

我完全绝望了。

编辑

@Casper 的回答并没有完全符合我的期望。对于像bonjour 这样的简单字符串,没有问题。但是当我放一些更复杂的字符串,一个json字符串或者更长的字符串(>60)时,问题就出现了。

首先关注Base64 Ruby module

encode64(bin)

返回 bin 的 Base64 编码版本。此方法符合 RFC 2045。每 60 个编码字符添加换行符。

因此,为了在 PHP 中拥有相同的 base64 编码数据,我需要在每 60 个编码字符以及字符串末尾插入\n。为此,PHP 提供了chunk_split() 函数。

因此,这些命令输出相同的字符串:

chunk_split(base64_encode($json), 60, '\n'); // PHP
Base64.encode64(json) # Ruby

但这并不能解决我的问题

PHP 和 Ruby 的结果仍然不同:

PHP:

$json = '{"data":["bonjour"],"id":true,"price":false,"oper":null}';
$base64 = chunk_split(base64_encode($json), 60, '\n');
$hash = hash_hmac('sha1', $base64, 'bonjour');
// Ouput from var_dump()
eyJkYXRhIjpbImJvbmpvdXIiXSwiaWQiOnRydWUsInByaWNlIjpmYWxzZSwi\nb3BlciI6bnVsbH0=\n // $base64
fd044c309bea13396ed8df47b5c606d950222ceb // $hash

现在在 Ruby 中:

json_body = '{"data":["bonjour"],"id":true,"price":false,"oper":null}'
encoded_body = Base64.encode64(json_body)
hash = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha1"), 'bonjour', encoded_body)
# Ouput from puts var.inspect
eyJkYXRhIjpbImJvbmpvdXIiXSwiaWQiOnRydWUsInByaWNlIjpmYWxzZSwi\nb3BlciI6bnVsbH0=\n # base64
e168f9efe96e9424e22de765c72018c5a3f3437f # hash

注意$base64 PHP 和base64 Ruby 变量是相同的。

我做错了什么?我不知道 Ruby,puts.inspect 是调试我的代码的最佳方式吗?

【问题讨论】:

  • 查看我的更新答案。要调试 Ruby 变量,请使用pp(漂亮的打印)。它通常会为您提供最多的信息。

标签: php ruby openssl base64 hmac


【解决方案1】:

似乎 Ruby 正在为 base64 编码的字符串添加换行符,而 PHP 没有。

鲁比:

Base64.encode64('bonjour')
=> "Ym9uam91cg==\n"

PHP:

base64_encode('bonjour')
=> "Ym9uam91cg=="

所以现在我们知道如何在 PHP 中修复它了:

hash_hmac('sha1', base64_encode('bonjour') . "\n", 'hello');
=> "62ac34e5d28563d6a50272d660805d1f8c791e41"

或者在 Ruby 中修复它:

OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha1"), 
                        'hello', Base64.encode64('bonjour').chomp)
=> "89ebf8bd3d92bf3283aa4c5f24072820258367e4"

第 2 部分

在 PHP 和 Ruby 中,'\n'"\n" 不同。第一个产生两个字符(\ 后跟n),第二个产生一个换行符。

因此,要修复您的代码,您需要在字符串中使用换行符,而不是斜线+n:

$base64 = chunk_split(base64_encode($json), 60, "\n");
                                                ^^^^

您还可以使用 gsub 从 Ruby base64 编码字符串中去除换行符,这意味着您无需在 PHP 代码中使用任何技巧:

encoded_body = Base64.encode64(json_body).gsub("\n", '')

【讨论】:

  • 嗯,我做了这个测试,我没有看到\n。我应该使用var_dump 而不是echo。非常感谢。
  • 没问题。换行很容易错过。我敢打赌,你不是第一个遇到同样问题的人。
  • 我更新了我的评论。但我还是要严谨一点!
  • 请看我刚刚做的更新,它让我抓狂!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-29
  • 1970-01-01
  • 1970-01-01
  • 2012-06-09
  • 2015-10-22
  • 1970-01-01
相关资源
最近更新 更多