【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字符后加一个

        $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字符后加一个

        $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/

原文地址:https://www.cnblogs.com/meetuj/p/14954533.html