Last updated on 2019年9月12日
使用RSA做加解密有过几次经历,每次掉的坑都不太一样。这里把遇到的问题表述一下,以备下次查阅。
- PHP56+
- openssl扩展
一、私钥加密公钥解密
RSA非对称加密:私钥加密请使用公钥解密,公钥加密请使用私钥解密。
二、加密模式和填充方法
首先要和对方核实加密模式和填充方法,PHP中RSA 私钥加密默认使用OPENSSL_PKCS1_PADDING填充,可设置为 OPENSSL_NO_PADDING ,其他加解密具体填充模式可参考PHP官方文档。
三、加密数据长度要求
以私钥加密为例,加密强度1024的私钥,每次可加密数据长度为 1024位/8=128字节,当使用OPENSSL_PKCS1_PADDING(这个要占用11个字节)填充时,可加密128-11=117字节。如果超出,那么这些openssl加解密函数会返回false。所以当超出时,请分段加密!
注:当然对方也可能是64字节进行分段加密,需要和对方核实并保持一致。
四、注意加解密前进行编码和解码
一般来说加密后的数据是二进制数据,为了便于传输和可见性,通常会将加密后的数据进行base64编码。同样地,解密前需将密文进行base64解码。
注:需和对方核实,此处有可能使用2进制、16进制编码、解码,如bin2hex、hex2bin
五、示例
这里以RSA私钥加密为例,写一个demo,公钥解密、公钥加密以及私钥解密同理,请更换相应openssl_*簇加解密函数即可。
$ourSecret = 'this is ok.'; // 待加密文本
$pem = 'your_pem_format.file'; // 注意这里是pem格式的文件内容
$pi_key = openssl_pkey_get_private($pem);
if (!$pi_key) die('$pem Format Error.');
// ras 加密时最大长度117字符串,因此加密时要循环切割&加密拼接(这里假设超出了117字符)
// 对方Java源码可能使用64位切割
$rsaContent = '';
foreach (str_split($ourSecret, 117) as $chunk) {
$rsaEn = openssl_private_encrypt($chunk, $encrypted, $pi_key); // 私钥加密
if (!$rsaEn) dump('RSA Encrypt Error.');
$rsaContent .= $encrypted;
}
if (!$rsaContent) die('RSA Encrypt Fail.');
$rsaContent = base64_encode($rsaContent); // 进行base64编码
echo 'RSA加密结果:',$rsaContent;
参考链接:
https://secure.php.net/manual/zh/function.openssl-private-encrypt.php
https://www.felix021.com/blog/read.php?2169
https://www.cnblogs.com/firstForEver/p/5803940.html