1

我需要在 PHP 中生成一个与T-SQL中HASHBYTES函数的输出相匹配的哈希。

以下是最初用于在 T-SQL 中生成哈希的代码:

 declare @input varchar(15) =  [this is the incoming value entered by the user]
 declare @salt binary(32) =  CRYPT_GEN_RANDOM(32)
 declare @saltchars nvarchar(32) = cast(@salt as nvarchar(32) )
 declare @inputchars nvarchar(50) = cast(@input as nvarchar(50) )
 declare @sha binary(32) = HASHBYTES('SHA2_256', @passwordchars + @saltchars)

对于输入“pete1234matt”,我们得到以下输出:

 salt =  0x75D6215CA44339B645E86BE790FF562D3EE4BC51034FDC6A9697F767BB961B5B
 sha  =  0x979EEAC93B5F6624269634202D9F3B5B8008113B03A83D104784184E0F9361F8

现在这是我编写的 PHP 代码,我采用提供的和输入,然后将它们编码为 UTF-16LE,就像我期望转换为 nvarchar 所做的那样。那是对的吗?

$password = 'pete1234matt'; 
$salt = 0x75D6215CA44339B645E86BE790FF562D3EE4BC51034FDC6A9697F767BB961B5B;
$saltchars = mb_convert_encoding($salt, 'UTF-16LE');
$passwordchars = mb_convert_encoding($password, 'UTF-16LE');
$sha = hash('sha256', $passwordchars . $saltchars);
//$sha ==   17b87bd0491f32f1e474ad9293e2fe5db56ed0a5c9939435f0984fdc04806dc5
//Expected: 979EEAC93B5F6624269634202D9F3B5B8008113B03A83D104784184E0F9361F8

我倾向于盐存在编码问题,但不能完全弄清楚我哪里出错了。任何对字符编码和 T-SQl 有更多了解的人都可以在这里帮帮我!

4

1 回答 1

1
  1. 您使用的十六进制表示法仅用于 PHP 中的数字。您想将其作为字符串放入并调用hex2bin().
  2. 我不知道您为什么要将盐转换为 UTF16,但不要这样做。
$password = 'pete1234matt'; 
$salt = hex2bin('75D6215CA44339B645E86BE790FF562D3EE4BC51034FDC6A9697F767BB961B5B');
$saltchars = $salt;
$passwordchars = mb_convert_encoding($password, 'UTF-16LE');
$sha = hash('sha256', $passwordchars . $saltchars);
//Expected: 979EEAC93B5F6624269634202D9F3B5B8008113B03A83D104784184E0F9361F8

var_dump($sha);

输出:

string(64) "979eeac93b5f6624269634202d9f3b5b8008113b03a83d104784184e0f9361f8"

不要养成在没有明确指定源编码的情况下调用任何字符集转换函数的习惯。PHP 字符串本质上只是没有编码概念的字节数组。PHP 具有控制假定默认字符集的配置设置,但使用正确解码的十六进制调用mb_convert_encoding($salt, 'UTF-16LE');将根据 PHP 默认值(可能是 UTF8 或 ISO-8859-1)解释字符串,并将其转换为 mojibake。实际上,该字符串已经是 UTF16LE。

例如:

$test_8   = 'hello ';
$test_16  = mb_convert_encoding($test_8, 'UTF-16LE', 'UTF-8');
$mojibake = mb_convert_encoding($test_16, 'UTF-16LE');

var_dump(
    bin2hex($test_8),
    bin2hex($test_16),
    bin2hex($mojibake)
);

输出:

string(20) "68656c6c6f20f09f8d86"
string(32) "680065006c006c006f0020003cd846df"
string(64) "68000000650000006c0000006c0000006f000000200000003c003f0046003f00"
于 2021-04-29T22:11:39.373 回答