PHP 的 hash_hmac 使用什么字符串编码?
What string encoding is used by PHP's hash_hmac?
PHP 有一个方法 hash_hmac 使用给定的密钥和算法计算给定字符串的 HMAC 签名。但 HMAC 在技术上对二进制数据进行操作,PHP 将其所有参数作为字符串。它如何将这些字符串转换为二进制数据?
它只是 UTF-8(用于字符串文字)。
您可以在字符串中放入任何您想要的编码,hash_hmac()
不使用任何特定的编码,只是您的字符串具有的任何编码。
这里 an example from Wikipedia 使用 UTF-8 编码和 运行 二进制的 HMAC 算法:
HMAC_MD5("key", "The quick brown fox jumps over the lazy dog")
= 80070713463e7749b90c2dc24911e275
这里是等效的 PHP 代码的结果,它得到相同的响应:
php > echo hash_hmac('md5', "The quick brown fox jumps over the lazy dog", "key");
80070713463e7749b90c2dc24911e275
简短回答:字符串编码只是 元数据 附在一堆二进制数据上。 PHP 字符串只是一团,你 必须跟踪其余部分。
长答案:
PHP 采用 Honey Badger 方法进行本机字符串编码,换句话说,“PHP 不关心”。你给它一个字节序列,它存储它们。它没有编码的概念,直到你想使用一个关心它的函数。即使 then 你也需要 明确地 声明输入和输出编码,否则 PHP 将使用其配置的默认值,这通常不是什么任何人都想要。
function nice_hex($in) {
return implode(' ', str_split(bin2hex($in), 2));
}
$utf8 = "You owe me €5.";
$utf16le = mb_convert_encoding($utf8, 'utf-16le', 'utf-8');
$utf16be = mb_convert_encoding($utf8, 'utf-16be', 'utf-8');
$iso88591 = mb_convert_encoding($utf8, 'iso-8859-1', 'utf-8');
$cp1252 = mb_convert_encoding($utf8, 'cp1252', 'utf-8');
var_dump(
$utf8,
nice_hex($utf8),
hash_hmac('md5', $utf8, 'foo'),
$utf16le,
nice_hex($utf16le),
hash_hmac('md5', $utf16le, 'foo'),
$utf16be,
nice_hex($utf16be),
hash_hmac('md5', $utf16be, 'foo'),
$iso88591,
nice_hex($iso88591),
hash_hmac('md5', $iso88591, 'foo'),
$cp1252,
nice_hex($cp1252),
hash_hmac('md5', $cp1252, 'foo')
);
输出:
string(16) "You owe me €5."
string(47) "59 6f 75 20 6f 77 65 20 6d 65 20 e2 82 ac 35 2e"
string(32) "7724135d91c43906f8730a26dcd76ffb"
string(28) "You owe me � 5."
string(83) "59 00 6f 00 75 00 20 00 6f 00 77 00 65 00 20 00 6d 00 65 00 20 00 ac 20 35 00 2e 00"
string(32) "f4a2347b4a1336dae1db21554c54b9e2"
string(28) "You owe me �5."
string(83) "00 59 00 6f 00 75 00 20 00 6f 00 77 00 65 00 20 00 6d 00 65 00 20 20 ac 00 35 00 2e"
string(32) "b0c1a98d8b853e6568bae513d764a029"
string(14) "You owe me ?5."
string(41) "59 6f 75 20 6f 77 65 20 6d 65 20 3f 35 2e"
string(32) "301a0fb55e23285904413323d10cc774"
string(14) "You owe me �5."
string(41) "59 6f 75 20 6f 77 65 20 6d 65 20 80 35 2e"
string(32) "fa1ee73d39e1a70fe2cde7a8c5bbf0ba"
之所以看起来如此,是因为:
- Whosebug 使用 UTF-8。
- 我的编辑器使用 UTF-8。
- 我的控制台使用 UTF-8。
- 事实上 PHP 不关心字符串编码,这让我很容易产生像上面这样的任意编码的垃圾输出。
补充推荐阅读:UTF-8 all the way through
有趣的事实: PHP6 从未结束的原因之一是因为他们想包括本机多字节字符串编码,但没有人就什么达成一致味道应该是。最终他们只是放弃了整个事情并把它留给了我们,就像在 PHP5.
中一样
PHP 有一个方法 hash_hmac 使用给定的密钥和算法计算给定字符串的 HMAC 签名。但 HMAC 在技术上对二进制数据进行操作,PHP 将其所有参数作为字符串。它如何将这些字符串转换为二进制数据?
它只是 UTF-8(用于字符串文字)。
您可以在字符串中放入任何您想要的编码,hash_hmac()
不使用任何特定的编码,只是您的字符串具有的任何编码。
这里 an example from Wikipedia 使用 UTF-8 编码和 运行 二进制的 HMAC 算法:
HMAC_MD5("key", "The quick brown fox jumps over the lazy dog")
= 80070713463e7749b90c2dc24911e275
这里是等效的 PHP 代码的结果,它得到相同的响应:
php > echo hash_hmac('md5', "The quick brown fox jumps over the lazy dog", "key");
80070713463e7749b90c2dc24911e275
简短回答:字符串编码只是 元数据 附在一堆二进制数据上。 PHP 字符串只是一团,你 必须跟踪其余部分。
长答案:
PHP 采用 Honey Badger 方法进行本机字符串编码,换句话说,“PHP 不关心”。你给它一个字节序列,它存储它们。它没有编码的概念,直到你想使用一个关心它的函数。即使 then 你也需要 明确地 声明输入和输出编码,否则 PHP 将使用其配置的默认值,这通常不是什么任何人都想要。
function nice_hex($in) {
return implode(' ', str_split(bin2hex($in), 2));
}
$utf8 = "You owe me €5.";
$utf16le = mb_convert_encoding($utf8, 'utf-16le', 'utf-8');
$utf16be = mb_convert_encoding($utf8, 'utf-16be', 'utf-8');
$iso88591 = mb_convert_encoding($utf8, 'iso-8859-1', 'utf-8');
$cp1252 = mb_convert_encoding($utf8, 'cp1252', 'utf-8');
var_dump(
$utf8,
nice_hex($utf8),
hash_hmac('md5', $utf8, 'foo'),
$utf16le,
nice_hex($utf16le),
hash_hmac('md5', $utf16le, 'foo'),
$utf16be,
nice_hex($utf16be),
hash_hmac('md5', $utf16be, 'foo'),
$iso88591,
nice_hex($iso88591),
hash_hmac('md5', $iso88591, 'foo'),
$cp1252,
nice_hex($cp1252),
hash_hmac('md5', $cp1252, 'foo')
);
输出:
string(16) "You owe me €5."
string(47) "59 6f 75 20 6f 77 65 20 6d 65 20 e2 82 ac 35 2e"
string(32) "7724135d91c43906f8730a26dcd76ffb"
string(28) "You owe me � 5."
string(83) "59 00 6f 00 75 00 20 00 6f 00 77 00 65 00 20 00 6d 00 65 00 20 00 ac 20 35 00 2e 00"
string(32) "f4a2347b4a1336dae1db21554c54b9e2"
string(28) "You owe me �5."
string(83) "00 59 00 6f 00 75 00 20 00 6f 00 77 00 65 00 20 00 6d 00 65 00 20 20 ac 00 35 00 2e"
string(32) "b0c1a98d8b853e6568bae513d764a029"
string(14) "You owe me ?5."
string(41) "59 6f 75 20 6f 77 65 20 6d 65 20 3f 35 2e"
string(32) "301a0fb55e23285904413323d10cc774"
string(14) "You owe me �5."
string(41) "59 6f 75 20 6f 77 65 20 6d 65 20 80 35 2e"
string(32) "fa1ee73d39e1a70fe2cde7a8c5bbf0ba"
之所以看起来如此,是因为:
- Whosebug 使用 UTF-8。
- 我的编辑器使用 UTF-8。
- 我的控制台使用 UTF-8。
- 事实上 PHP 不关心字符串编码,这让我很容易产生像上面这样的任意编码的垃圾输出。
补充推荐阅读:UTF-8 all the way through
有趣的事实: PHP6 从未结束的原因之一是因为他们想包括本机多字节字符串编码,但没有人就什么达成一致味道应该是。最终他们只是放弃了整个事情并把它留给了我们,就像在 PHP5.
中一样