【发布时间】:2015-03-23 14:21:35
【问题描述】:
我正在努力替换一个旧系统,该系统(除其他外)接收任意文件的 SHA1 哈希,并使用带有简单 PHP Web 服务的私钥对其进行签名。
它应该看起来像这样:
$providedInput = '13A0227580C5DE137C2EBB2907A3F2D7F00CA71D';
// pseudo "= sha1(somefile.txt); file not available server side!
$expectedOutput = 'DBC9CC4CB0BECEE313BB100DD1AD39AEC045714D72767211FD574E3E3546EB55E77D2EBFE33BA2974BB74CE051608BFF45A73A52612C5FC418DD3A76CAC0AE0C8FB3FC6CE4F7A516013A9743A36424DDACFE889B3D45E86E6853FD9A55B5B4F0F0D8A574A0B244C0946A99B81CCBD1A7AF7C11072745B11C06AD680BE8AC4CB4';
// pseudo: "= openssl_sign(file_get_contents(somefile.txt), signature, privateKeID);
为了简单起见,我使用 PHP 内置的 openssl 扩展。我遇到的问题是 openssl_sign 似乎根据openssl_sign 上的这个德国手册条目再次在内部对输入数据进行 SHA1 哈希处理。由于某种原因,英文条目缺少该信息。
这会产生预期的输出...
$privateKeyID = openssl_get_privatekey(file_get_contents($privateKey));
openssl_sign(file_get_contents("x.txt"), $signature, $privateKeyID);
var_dump(bin2hex($signature));
...但是由于我无法访问服务器端的实际输入文件,所以它不是很有帮助。
在没有 3rd 方库的情况下,有没有办法绕过额外的散列?我已经尝试简单地加密收到的哈希,但从How to compute RSA-SHA1(sha1WithRSAEncryption) value 我了解到加密和签名会产生不同的输出。
更新以使事情更加清晰:
我收到一个 SHA1 哈希作为输入,服务必须将其转换为有效签名(使用私钥),可以使用 openssl_verify 简单地进行验证。客户端遥不可及,因此无法更改其实现。
来自How to compute RSA-SHA1(sha1WithRSAEncryption) value:
如果您重现此 EM 并使用 RSA_private_encrypt,那么您将获得正确的 PKCS#1 v1.5 签名编码,与使用通用 EVP_PKEY_sign 获得的 RSA_sign 相同甚至更好。
我想我可以根据this specification 自己简单地实现 DER 编码,但结果 (EM) 似乎太长而无法用我的密钥加密
// 1. Apply the hash function to the message M to produce a hash value H
$H = hex2bin($input); // web service receives sha1 hash of an arbitrary file as input
$emLen = 128; // 1024 rsa key
// 2. Encode the algorithm ID for the hash function and the hash value into
// an ASN.1 value of type DigestInfo
$algorithmIdentifier = pack('H*', '3021300906052b0e03021a05000414');
$digest = $H;
$digestInfo = $algorithmIdentifier.$digest;
$tLen = strlen($digestInfo);
// 3. error checks omitted ...
// 4. Generate an octet string PS consisting of emLen - tLen - 3 octets
// with hexadecimal value 0xff. The length of PS will be at least 8
// octets.
$ps = str_repeat(chr(0xFF), $emLen - $tLen - 3);
//5. Concatenate PS, the DER encoding T, and other padding to form the
// encoded message EM as
$em = "\0\1$ps\0$digestInfo";
if(!openssl_private_encrypt($em, $signature, $privateKeyID)) {
echo openssl_error_string();
}
else {
echo bin2hex($signature);
}
输出:
错误:0406C06E:rsa 例程:RSA_padding_add_PKCS1_type_1:数据对于密钥大小来说太大
有什么提示吗?
【问题讨论】: