RSA和SHA-256加密,用于使用PHP签名 [英] RSA and SHA-256 encryption for signing using PHP

查看:570
本文介绍了RSA和SHA-256加密,用于使用PHP签名的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在从Web Service API接收请求中的XML.它包含一个签名,该签名由请求者的私钥签名,我必须通过请求者的公钥进行验证.然后,我必须发送一个带有我的私钥签名的签名的响应.

I'm receiving XML in request from a Web Service API. It contains a signature, signed by the requester's private key, and I have to verify it by the requester public key. Then I have to send a response with a signature, signed by my private key.

此过程应在PHP中使用RSA和SHA-256完成.

This process should be done with RSA and SHA-256 in PHP.

我目前有以下代码:

$data_to_encrypt = "MsgBody..../MsgBody"; // xml 

$msgbody = simplexml_load_string($data_to_encrypt);
$result = $msgbody->xpath('//MsgBody'); 

openssl_private_encrypt(json_encode($result), $encrypted, $private_key, OPENSSL_PKCS1_PADDING);

$signature = $encrypted;
$verify = openssl_verify($encrypt, $signature ,$publick_key, OPENSSL_ALGO_SHA256); 

$ verify = 0的结果.为什么验证不正确?

The result of $verify= 0. Why is it a bad verify?

推荐答案

openssl_private_encrypt openssl_public_decrypt .两种方法都允许使用PKCS#1 v1.5填充( RSASSA-PKCS1进行低级签名/验证-v1_5 ),其中不隐式地不对数据进行哈希处理,也不会在哈希表之前使用所使用摘要的ID.也就是说,为了使结果符合PKCS#1 v1.5填充,必须明确完成这两项.

The counterpart to openssl_private_encrypt is openssl_public_decrypt. Both methods allow low level signing/verification with PKCS#1 v1.5 padding (RSASSA-PKCS1-v1_5), where the data is implicitly not hashed, nor is the ID of the digest used prepended to the hash. I.e., for the result to be compliant with PKCS#1 v1.5 padding, both must be done explicitly.

相比之下, openssl_verify 在RSA和PKCS#1 v1.5填充的情况下,因此签名自动符合PKCS#1 v1.5填充.

In contrast, hashing and adding the digest ID is implicitly taken into account in openssl_sign and openssl_verify in the context of RSA and PKCS#1 v1.5 padding, so the signature is automatically compliant with PKCS#1 v1.5 padding.

通常,后者是签名/验证的更有效方法.但是, openssl_private_encrypt 也有用途,即当不是要签名的数据本身,而只有已经散列的数据可用于签名时.

Generally, the latter is the more efficient way for signing/verifying. However, openssl_private_encrypt also has a use, namely when not the data to be signed itself, but only the already hashed data is available for signing.

代码中的问题是 openssl_private_encrypt openssl_verify 的组合.当然,您可以将两者结合使用,但是随后您必须实现散列并为 openssl_private_encrypt 添加摘要ID,该ID在代码中缺失.另外(如注释中所述),可以应用 openssl_sign ,在此效率更高.
另一个不一致之处是,必须对同一数据进行签名和验证.在代码中,使用 json_encode($ result)进行签名,并使用 $ encrypt (从中派生出 json_encode($ result))进行验证

The issue in the code is the combination of openssl_private_encrypt and openssl_verify. Of course you can combine both, but then you have to implement hashing and adding the digest ID for openssl_private_encrypt, which is missing in the code. Alternatively (as already noted in the comments) openssl_sign can be applied, which is more efficient here.
Another inconsistency is that signing and verifying must be done on the same data. In the code, json_encode($result) is used for signing and $encrypt (from which json_encode($result) was derived) for verifying.

以下PHP代码演示了 openssl_private_encrypt openssl_verify 的组合(请参见 Test 1 ):

The following PHP code demonstrates the combination of openssl_private_encrypt and openssl_verify (see Test 1):

function getRSAKeys(){
    $keyPairResource = openssl_pkey_new(array("private_key_bits" => 2048, "private_key_type" => OPENSSL_KEYTYPE_RSA)); 
    openssl_pkey_export($keyPairResource, $privateKey);
    return [$privateKey, openssl_pkey_get_details($keyPairResource)["key"]];
}

// Create test key
$newKeyPair = getRSAKeys();
$privateKey = $newKeyPair[0];
$publicKey = $newKeyPair[1];

// Test 1: openssl_private_encrypt and openssl_verify
$dataToSign = 'Test 1: The data to sign'; // Could correspond to e.g. json_encode($result) in the code
$dataToSignHashed = hash('sha256', $dataToSign, true);
$dataToSignHashedWithID = hex2bin("3031300d060960864801650304020105000420") . $dataToSignHashed; // ID from https://tools.ietf.org/html/rfc8017#page-47
openssl_private_encrypt($dataToSignHashedWithID, $signature, $privateKey, OPENSSL_PKCS1_PADDING);
$verified = openssl_verify($dataToSign, $signature, $publicKey, OPENSSL_ALGO_SHA256);
print($verified) . PHP_EOL;

// Test 2: openssl_sign and openssl_verify
$dataToSign = 'Test 2: The data to sign'; // Could correspond to e.g. json_encode($result) in the code
openssl_sign($dataToSign, $signature, $privateKey, OPENSSL_ALGO_SHA256);
$verified = openssl_verify($dataToSign, $signature, $publicKey, OPENSSL_ALGO_SHA256);
print($verified) . PHP_EOL;

// Test 3: openssl_private_encrypt and openssl_public_decrypt (without hashing and adding the digest id)
$dataToSign = 'Test 3: The data to sign'; // Could correspond to e.g. json_encode($result) in the code
openssl_private_encrypt($dataToSign, $signature, $privateKey, OPENSSL_PKCS1_PADDING);
openssl_public_decrypt($signature, $decrypted, $publicKey, OPENSSL_PKCS1_PADDING);
print($dataToSign === $decrypted) . PHP_EOL;

最后一个例子应该理解为纯技术,并且应证明使用 openssl_private_encrypt 进行加密而不进行散列和不添加ID可以使用 openssl_public_decrypt 进行解密.实际上,签名时会应用散列,请参见 kelalaka 的评论,例如此处.这两种方法都不打算直接对消息 进行签名/验证,而是如上所述,允许用户对已散列的消息 进行签名/验证.

The last example is to be understood purely technical and should demonstrate that encryption with openssl_private_encrypt without hashing and without adding the ID can be decrypted with openssl_public_decrypt. In practice, hashing is applied when signing, see comment by kelalaka and e.g. here. Both methods are not intended to sign/verify the message directly, but, as already mentioned above, to allow the user to sign/verify an already hashed message.

这篇关于RSA和SHA-256加密,用于使用PHP签名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆