因为安全方面的原因,浏览器里的Web crypto API开始使用SHA2的hash算法了,但php里调用openssl函数进行公钥加密信息时,还是使用SHA1,而且无法使用参数进行设定。还好可以使用第三方库Phpseclib
,纯php实现,1.x版本在PHP4上也可以使用,效率也不低。在PHP官方文档里,openssl_public_encrypt函数下有一个评论:
https://www.php.net/manual/en/function.openssl-public-encrypt.php
We can't guarantee that RSA will still be trusted for security in 2016, but this is the current best practice for RSA. The rest of the world is moving on to ECDH and EdDSA (e.g. Ed25519).
That said, make sure you are using OPENSSL_PKCS1_OAEP_PADDING or else you're vulnerable to a chosen-ciphertext attack (Google: "Daniel Bleichenbacher 1998 RSA padding oracle" and you'll find plenty of material on it.)
The only fix is to use OAEP (preferably with MGF1-SHA256, but this function doesn't let you specify that detail and defaults to MGF1+SHA1).
Phpseclib offers RSAES-OAEP + MGF1-SHA256 for encryption and RSASS-PSS + MGF1-SHA256 for signatures.
http://phpseclib.sourceforge.net/rsa/examples.html#encrypt,enc1
If you don't want to hassle with these details yourself, check out https://github.com/paragonie/EasyRSA
按phpsceclib上给出的例子,可以简单实现SHA256加密,与浏览器上的RSA加密兼容。其中loadKey里的参数,可以省略“-----BEGIN PUBLIC KEY----- ”的头尾标记。
<?php
include('Crypt/RSA.php');
$rsa = new Crypt_RSA();
$rsa->loadKey('...'); // public key
$rsa->setHash('sha256');
$rsa->setMGFHash('sha256');
$plaintext = '...';
//$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_OAEP);
$ciphertext = $rsa->encrypt($plaintext);
$rsa->loadKey('...'); // private key
echo $rsa->decrypt($ciphertext);
?>