RSA非对称加密

用OpenSSL转换PFX证书

openssl pkcs12 -in szkingdom_pri.pfx -nocerts -nodes -out xch.key
openssl ras -in xch.key -out xch_private.key
openssl ras -in xch.key -pubout -out xch_public.key
<?php

$cipher = new LRSAHelper();
$cipher->initKey(file_get_contents($this->privatePem), file_get_contents($this->publicPem), 1024);
$cipher->initSignature(OPENSSL_ALGO_MD5);//设置验签算法
$requestData = $cipher->encrypt(json_encode($data));
$requestSign = $cipher->sign(json_encode($data));
//requestData、requestSign 传给对方
$msg = $cipher->decrypt($response);
$cipher->verify($msg, $sign);//sign 是对方返回的

class LRSAHelper
{
    const KEY_ALGORITHM = "RSA";
    const SIGNATURE_ALGORITHM = OPENSSL_ALGO_SHA1; //"SHA1withRSA";
    const CIPHER_ALGORITHM = OPENSSL_PKCS1_PADDING; //"RSA/ECB/PKCS1Padding"; //加密block需要预留11字节
    const KEYBIT = 2048;
    const RESERVEBYTES = 11;

    private $signature_alg;
    private $padding;

    private $localPrivKey;
    private $peerPubKey;
    private $encryptBlock;
    private $decryptBlock;

    public function __construct()
    {
        $this->signature_alg = self::SIGNATURE_ALGORITHM;
        $this->padding = self::CIPHER_ALGORITHM;

        $this->localPrivKey = null;
        $this->peerPubKey = null;
        $this->decryptBlock = self::KEYBIT / 8; //256 bytes
        $this->encryptBlock = $this->decryptBlock - self::RESERVEBYTES; //245 bytes
    }

    /**
     * 初始化自己的私钥,对方的公钥以及密钥长度.
     * `openssl genrsa -out rsa_2048.key 2048` #指定生成的密钥的位数: 2048
     * `openssl pkcs8 -topk8 -inform PEM -in rsa_2048.key -outform PEM -nocrypt -out pkcs8.txt` #for Java 转换成PKCS#8编码
     * `openssl rsa -in rsa_2048.key -pubout -out rsa_2048_pub.key` #导出pubkey
     * @param $localPrivKeyPEMStr mixed a key, returned by openssl_get_publickey() or a PEM formatted key, example, "-----BEGIN PUBLIC KEY----- MIIBCgK..."
     * @param $peerPubKeyPEMStr mixed a key, returned by openssl_get_publickey() or a PEM formatted key, example, "-----BEGIN PUBLIC KEY----- MIIBCgK..."
     * @param $keySize int 密钥长度, 一般2048
     */

    public function initKey($localPrivKeyPEMStr, $peerPubKeyPEMStr, $keySize)
    {
        $this->localPrivKey = $localPrivKeyPEMStr;
        $this->peerPubKey = $peerPubKeyPEMStr;
        $this->decryptBlock = $keySize / 8;
        $this->encryptBlock = $this->decryptBlock - self::RESERVEBYTES;
    }

    public function initSignature($algorithm)
    {
        $this->signature_alg = $algorithm;
    }

    public function sign($plaintext)
    {
        $signature = '';
        if (openssl_sign($plaintext, $signature, $this->localPrivKey, $this->signature_alg))
        {
            return base64_encode($signature);
        }
        else
        {
            return '';
        }
    }

    public function verify($plaintext, $signBase64Str)
    {
        $signature = base64_decode($signBase64Str);
        $ret = openssl_verify($plaintext, $signature, $this->peerPubKey, $this->signature_alg);
        if ($ret === 1)
        {
            return true;
        }
        else
        {
            //($ret == -1)表示出错
            return false;
        }
    }

    public function initCipher($padding)
    {
        $this->padding = $padding;
    }

    public function encrypt($plaintext)
    {
        //计算分段加密的block数 (向上取整)
        $dataLength = strlen($plaintext);
        $nBlock = ($dataLength / $this->encryptBlock);
        if (($dataLength % $this->encryptBlock) != 0) //余数非0block数再加1
        {
            $nBlock = $nBlock + 1;
        }
        //for debug. printf ("encryptBlock: %d/%d ~ %d\n", data.length, encryptBlock, nBlock);

        //输出buffer, 大小为nBlock个decryptBlock
        $outBuf = '';

        //分段加密
        for ($offset = 0; $offset < $dataLength; $offset += $this->encryptBlock)
        {
            //block大小: encryptBlock 或 剩余字节数
            $data = substr($plaintext, $offset, $this->encryptBlock);

            //得到分段加密结果
            $encryptedBlock = '';
            if (!openssl_public_encrypt($data, $encryptedBlock, $this->peerPubKey, $this->padding))
            {
                return ''; //出错返回空
            }
            else
            {
                //追加结果到输出buffer中
                $outBuf .= $encryptedBlock;
            }
        }

        return base64_encode($outBuf); //ciphertext
    }

    public function decrypt($encryptedBase64Str)
    {
        $ciphertext = base64_decode($encryptedBase64Str);

        //计算分段解密的block数 (理论上应该能整除)
        $dataLength = strlen($ciphertext);
        $nBlock = ($dataLength / $this->decryptBlock);
        //for debug. printf("decryptBlock: %d/%d ~ %d\n", data.length, decryptBlock, nBlock);

        //输出buffer, , 大小为nBlock个encryptBlock
        $outBuf = '';

        //分段解密
        for ($offset = 0; $offset < $dataLength; $offset += $this->decryptBlock)
        {
            //block大小: decryptBlock 或 剩余字节数
            $data = substr($ciphertext, $offset, $this->decryptBlock);

            //得到分段解密结果
            $decryptedBlock = '';
            if (!openssl_private_decrypt($data, $decryptedBlock, $this->localPrivKey, $this->padding))
            {
                return ''; //出错返回空
            }
            else
            {
                //追加结果到输出buffer中
                $outBuf .= $decryptedBlock;
            }
        }

        return $outBuf;
    }

    public function setLocalPrivKey($localPrivKey)
    {
        $this->localPrivKey = $localPrivKey;
    }

    public function getLocalPrivKey()
    {
        return $this->localPrivKey;
    }

    public function setPeerPubKey($peerPubKey)
    {
        $this->peerPubKey = $peerPubKey;
    }

    public function getPeerPubKey()
    {
        return $this->peerPubKey;
    }
}
Posted in : php


发表评论

电子邮件地址不会被公开。 必填项已用*标注