【PHP】RSA 长字符串 分段加密(117)解密(128)
Q1:为什么RSA对长字符串需分段进行加、解密?
RSA对明文长度和密文长度有限制,如果要加密的明文太长则会出错。RSA 1024bit 加密明文最大长度117字节,解密要求密文最大长度为128字节,所以在加密和解密的过程中需要分块进行。
Q2:解决办法?
RSA密钥长度1024bit,加密的时候117个字符加密一次,然后把所有的密文拼接成一个密文;解密的时候需要128个字符解密一下,然后拼接成数据。
Q3:RSA不同的密钥长度,在分段加、解密时,分段字节数是不同的
若RSA密钥长度为M bit,分段加密字节数为(M/8-11),分段解密字节数为(M/8)。
如:
1024bit:分段加密字节数为117,分段解密字节数为128。
2048bit:分段加密字节数为245,分段解密字节数为256。
Demo 1:
private $private_key = "-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQDvluFNiF8IrIsddK0OXBAvVBJH11OKvy9er1tRGn9yEJoHCJY3
EU/xz2LasCK8AwgRIqGJbvDBgRa70c3QT9j+wPqNqqJCSoSEKifnDUk1RgUReJT6
iqWaJyfM+WM3aHnKl61RZL4NV5qKe4CHMtaH/JtBCC/JzpuFER1P1IhCtQIDAQAB
AoGAaFYQb68/k4twWbeB1YsKEVJPU7HV08pGWrmKztr3PTk1mnKG2BxV8DwcFJg3
yCCZ1rx6FFuXxOzudYR8WIctO4wdsEbFky/cEGsfc6JJjiktmZaQ7MvobGNwnoFJ
QvRxDd+5uD87JE19iBSgUpLVtXbv+pZxSpD70vitnMdSctECQQD66Z5HsuC8DUPu
OLQHNN4ra5Op179Xlq7LiEFW4GaVgonw24kiLX23c7CK7295Rgxct1fwQKyuU9br
n2uj8toDAkEA9HJ85BWlm2OfUm6VI3Q99rjlpCnhRyz70+sEtf7if1SpctVxNTkX
UOnXlpPTohjAHNhzh9fa1hh/ySH9sRMu5wJAa//8uh3br/YBxFsx2lw+OPBQGe4c
lSXtzPu0LCHg5f/PQhYs28I696jbV6IiGFA3Z/0e4/HiohLCUp9HJMWWYwJACE53
pfyCUyRwfomZccn6bQ7dZtWxfQyvRgU/dLvDkJYc5/UO0sMs4qf/lnNRhrmWlaRZ
UK1qF0pf1ULdbw360wJBAObrYopW2kvIlE09j9SEgNtgVsmfZlf85c4EAZrFJP/T
8nMNKQGo92Gd3HvbjJ+ZBOP1IFt+FDAsXeSLWLAwJrg=
-----END RSA PRIVATE KEY-----";
private $public_key = "-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDvluFNiF8IrIsddK0OXBAvVBJH
11OKvy9er1tRGn9yEJoHCJY3EU/xz2LasCK8AwgRIqGJbvDBgRa70c3QT9j+wPqN
qqJCSoSEKifnDUk1RgUReJT6iqWaJyfM+WM3aHnKl61RZL4NV5qKe4CHMtaH/JtB
CC/JzpuFER1P1IhCtQIDAQAB
-----END PUBLIC KEY-----
";
public function rsa(){
$content = "这是一段文字";
$res = $this->superLongPublicKeyEncrypt($content,$this->public_key,false,true);
var_dump($res);
$content = "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";
$res = $this->superLongPrivateKeyDecrypt($content,$this->private_key,false,true);
var_dump($res);
}
public function superLongPublicKeyEncrypt($content, $rsaPublicKey, $choicePath = true, $withBase64 = false)
{
if ($choicePath) {
$pubKeyId = openssl_pkey_get_public($rsaPublicKey);//绝对路径读取
} else {
$pubKeyId = $rsaPublicKey;//公钥
}
$RSA_ENCRYPT_BLOCK_SIZE = 117;
$result = '';
$data = str_split($content, $RSA_ENCRYPT_BLOCK_SIZE);
foreach ($data as $block) {
openssl_public_encrypt($block, $dataEncrypt, $pubKeyId, OPENSSL_PKCS1_PADDING);
$result .= $dataEncrypt;
}
if ($withBase64) {
return base64_encode($result);
} else {
return $result;
}
}
public static function superLongPrivateKeyDecrypt($content, $rsaPrivateKey, $choicePath = true, $withBase64 = false)
{
if ($choicePath) {
$priKeyId = openssl_pkey_get_private($rsaPrivateKey);//绝对路径
} else {
$priKeyId = $rsaPrivateKey;//私钥
}
if ($withBase64) {
$data = base64_decode($content);
}
$RSA_DECRYPT_BLOCK_SIZE = 128;
$result = '';
$data = str_split($data, $RSA_DECRYPT_BLOCK_SIZE);
foreach ($data as $block) {
openssl_private_decrypt($block, $dataDecrypt, $priKeyId, OPENSSL_PKCS1_PADDING);
$result .= $dataDecrypt;
}
if ($result) {
return $result;
} else {
return false;
}
}
Demo 2:
<?php
/**
* PHP实现RSA分段加密、解密
*
* Class RSA
*/
class RSA
{
public $privateKey = './rsa_private_key.pem'; //私钥地址
public $publicKey = './rsa_public_key.pem'; //公钥地址
public $pri_key = '-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQDvluFNiF8IrIsddK0OXBAvVBJH11OKvy9er1tRGn9yEJoHCJY3
EU/xz2LasCK8AwgRIqGJbvDBgRa70c3QT9j+wPqNqqJCSoSEKifnDUk1RgUReJT6
iqWaJyfM+WM3aHnKl61RZL4NV5qKe4CHMtaH/JtBCC/JzpuFER1P1IhCtQIDAQAB
AoGAaFYQb68/k4twWbeB1YsKEVJPU7HV08pGWrmKztr3PTk1mnKG2BxV8DwcFJg3
yCCZ1rx6FFuXxOzudYR8WIctO4wdsEbFky/cEGsfc6JJjiktmZaQ7MvobGNwnoFJ
QvRxDd+5uD87JE19iBSgUpLVtXbv+pZxSpD70vitnMdSctECQQD66Z5HsuC8DUPu
OLQHNN4ra5Op179Xlq7LiEFW4GaVgonw24kiLX23c7CK7295Rgxct1fwQKyuU9br
n2uj8toDAkEA9HJ85BWlm2OfUm6VI3Q99rjlpCnhRyz70+sEtf7if1SpctVxNTkX
UOnXlpPTohjAHNhzh9fa1hh/ySH9sRMu5wJAa//8uh3br/YBxFsx2lw+OPBQGe4c
lSXtzPu0LCHg5f/PQhYs28I696jbV6IiGFA3Z/0e4/HiohLCUp9HJMWWYwJACE53
pfyCUyRwfomZccn6bQ7dZtWxfQyvRgU/dLvDkJYc5/UO0sMs4qf/lnNRhrmWlaRZ
UK1qF0pf1ULdbw360wJBAObrYopW2kvIlE09j9SEgNtgVsmfZlf85c4EAZrFJP/T
8nMNKQGo92Gd3HvbjJ+ZBOP1IFt+FDAsXeSLWLAwJrg=
-----END RSA PRIVATE KEY-----';
public $pub_key = '-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDvluFNiF8IrIsddK0OXBAvVBJH
11OKvy9er1tRGn9yEJoHCJY3EU/xz2LasCK8AwgRIqGJbvDBgRa70c3QT9j+wPqN
qqJCSoSEKifnDUk1RgUReJT6iqWaJyfM+WM3aHnKl61RZL4NV5qKe4CHMtaH/JtB
CC/JzpuFER1P1IhCtQIDAQAB
-----END PUBLIC KEY-----';
/**
* RSA constructor.
* @param null $publicKeyPath
* @param null $privateKeyPath
* @param null $publicKey
* @param null $privateKey
* @throws FileNotFoundException
*/
public function __construct($publicKeyPath=null, $privateKeyPath=null, $publicKey=null, $privateKey=null) {
if ($this->checkKeyFile($publicKeyPath)) {
$this->pub_key = openssl_pkey_get_public(file_get_contents($publicKeyPath));
}
if ($this->checkKeyFile($privateKeyPath)) {
$this->pri_key = openssl_pkey_get_private(file_get_contents($privateKeyPath));
}
if (!is_null($publicKey)) {
$this->pub_key = openssl_pkey_get_public($this->formatterPublicKey($publicKey));
}
if (!is_null($privateKey)) {
$this->pri_key = openssl_pkey_get_private($this->formatterPrivateKey($privateKey));
}
}
/**
* 校验文件是否存在
* @param $keyPath string 文件路径
* @return bool
* @throws FileNotFoundException
*/
public function checkKeyFile($keyPath)
{
if (!is_null($keyPath)) {
if(!file_exists($keyPath)) {
throw new FileNotFoundException($keyPath);
}
return true;
}
return false;
}
/**
* 格式化公钥
* @param $publicKey string 公钥
* @return string
*/
public function formatterPublicKey($publicKey)
{
if (str_contains('-----BEGIN PUBLIC KEY-----', $publicKey)) return $publicKey;
$str = chunk_split($publicKey, 64, PHP_EOL);//在每一个64字符后加一个\n
$publicKey = "-----BEGIN PUBLIC KEY-----".PHP_EOL.$str."-----END PUBLIC KEY-----";
return $publicKey;
}
/**
* 格式化私钥
* @param $privateKey string 公钥
* @return string
*/
public function formatterPrivateKey($privateKey)
{
if (str_contains('-----BEGIN RSA PRIVATE KEY-----', $privateKey)) return $privateKey;
$str = chunk_split($privateKey, 64, PHP_EOL);//在每一个64字符后加一个\n
$privateKey = "-----BEGIN RSA PRIVATE KEY-----".PHP_EOL.$str."-----END RSA PRIVATE KEY-----";
return $privateKey;
}
/**
* 公钥加密(分段加密)
* emptyStr 需要加密字符串
*/
public function encrypt($str) {
$crypted = array();
$data = $str;
$dataArray = str_split($data, 117);
foreach($dataArray as $subData){
$subCrypted = null;
openssl_public_encrypt($subData, $subCrypted, $this->pub_key);
$crypted[] = $subCrypted;
}
$crypted = implode('',$crypted);
return base64_encode($crypted);
}
/**
* 私钥解密(分段解密)
* @encrypstr 加密字符串
*/
public function decrypt($encryptstr) {
$encryptstr = base64_decode($encryptstr);
$decrypted = array();
$dataArray = str_split($encryptstr, 128);
foreach($dataArray as $subData){
$subDecrypted = null;
openssl_private_decrypt($subData, $subDecrypted, $this->pri_key);
$decrypted[] = $subDecrypted;
}
$decrypted = implode('',$decrypted);
return $decrypted;
}
}
$result = new RSA();
$data = '{"phone":"15256416396","name":"张三","inAcctNo":"8239472342342342","idNo":"342422165897654326","inAcctBankName":"平安银行"}';
$dataEn = $result->encrypt($data);
echo $dataEn;
echo "<pre>";
$dataDe = $result->decrypt($dataEn);
echo $dataDe;
参考:
https://blog.csdn.net/u010144805/article/details/80547370
https://blog.liuguofeng.com/p/5305
https://blog.csdn.net/h1101723183/article/details/102489052
https://blog.csdn.net/draven1122/article/details/55212252/