openssl RSA非对称加密、解密、签名、验签

发布时间:2020-07-08 11:33:32 作者:hgditren
来源:网络 阅读:3697

需要先了解的openssl系列函数

<?php
/**
 * Created by PhpStorm.
 * User: zrj
 * Date: 18-11-7
 * Time: 上午10:22
 */
declare(strict_types=1);//开启强类型模式

//私匙
$privateKeyString = <<<EOF
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAxHS1H/9uMS+waaP8vkEHx0EJWqPnRjYIzHKrXeMQ3fjZmxPG
MJmzwKVdADQlaFbA/NePu7dVFyzFo2yrAFlJD9bWs6of79OM2QGxu/AL2GqwjaOZ
/+5tSkxqU8fj+/sb35U9kGxy/k4KPwlatTaHIkXb7qebCGX1hgNw2BkRrNfXWRX+
EVs8Oy/I/d1CMQMF3mvsCFvoUAE/UJVOOAjjQ6rBX+PorWXuTIKgWgSFWwzsRWJN
hQo6P6Y/amx2Jb6Nr0rHIJIREICdYMAp2DSC+uU+jl85NqT3U89BRRG+58feoUOL
DGiv0hRQ7+k1e47MfiwKpCpJOkldEJjywMhl1QIDAQABAoIBAHBQuOyeQAVm2ljL
JEgxLZ1BFXP4mNSPN+CK/mYi1xXQm7gJShmnBhlxcQYYyfoo/xSOuOH9ImypcCTK
j8kXQqoHjaAR90hJjhDS4yYrStpjxKR1kCm9ykXcAj373d/F5F2jGRtkpSm2vCzl
0DIiBogVoHOE5yGaCRChDva8/lnt3ACEurhiL37ZJbOnbZMj2FkNmtv7eCgVEUTH
Ydu9cU8mbC3g1WMDxKSBxwgRhZQYZQSRta4nkWN5xEcO7WAF3RWs1cFJ4ttCQaRy
J/Y0K8R9prLRwh61/jonQPCJN+NGmtpCq9+kgVxxLe7p45k4DO2VxaKzto5IDSZj
hdFTEAECgYEA43cRn8ISAlHQHxi2EOq5Ygk98Bf249WNuBzxOra5SpCBVbRGvTeY
Mrq86FY1PsFK+pOVeiiaaGanZDFtULEJyiZm3KaE2PVRsbfeYO9vSTHW8ikdmpCW
VALpL6B+Q7kRvA/1krnU9Uy8c9k+EpZOELI9Ja8H9pMErMVd7LX+HtUCgYEA3RnK
5gzXNNI4hfphepxXD/+qFxgd0mmwi/jLhc4c62V259sUR2R38jo+xDgBlDvrlmDi
e6H7q56Y3M1Zag+zHc8PgtqxY7CPt5rc8dHd8iYh0UxNCYjlM3QP8dULdPmlnPkC
70KyHNkCoesiDytbT50EN5KnqEO99Kgl3mhqqwECgYAHGQcOwiKHuf/RiJbdzkU8
nuc037qPf3FtplGMsHj1r66peveeHeb85kDQyyfcLnHlgcdvSWcQDOv6P2SW2P9i
NHKPPg71KiqDbiZdRftmAE0hv1CyKwLV2kVmfA6UlGjOQn06N9xCT0OuJcA/GjuT
X8xyqZSJCCtkLMByi3dDhQKBgFmRWk2phADk7Hrx/E1ESkyz4H6siWA06o05g5E3
9yUxHGM+r89gFussx0KMAa/AOmbX5sf4zdAvVnOUSJWbuI7p07nJyDS/UOkrNjhM
MWIoKmj0RP0I1PjsGo14JcUEYR/fDF5KoYboLpXTgB+vC7WLwSqWIY8bqjcTawvX
NucBAoGAPGAi11FCqx5R3r/3pJkySlNoj+m/J04mdYXJpmJV6P6PczJHd0aRjvJF
6ubuKot1pExuhEivYo7dYubr5clmh3S8bs9kyS5Q2Btz5kXhxf4EGmJRVD+CAmvi
EAHNljZQgkfonOZFqRXaxqAsqEziIfQqI7IjpTkcGgts4v43Tlo=
-----END RSA PRIVATE KEY-----
EOF;

//公匙
$publicKeyString = <<<EOF
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxHS1H/9uMS+waaP8vkEH
x0EJWqPnRjYIzHKrXeMQ3fjZmxPGMJmzwKVdADQlaFbA/NePu7dVFyzFo2yrAFlJ
D9bWs6of79OM2QGxu/AL2GqwjaOZ/+5tSkxqU8fj+/sb35U9kGxy/k4KPwlatTaH
IkXb7qebCGX1hgNw2BkRrNfXWRX+EVs8Oy/I/d1CMQMF3mvsCFvoUAE/UJVOOAjj
Q6rBX+PorWXuTIKgWgSFWwzsRWJNhQo6P6Y/amx2Jb6Nr0rHIJIREICdYMAp2DSC
+uU+jl85NqT3U89BRRG+58feoUOLDGiv0hRQ7+k1e47MfiwKpCpJOkldEJjywMhl
1QIDAQAB
-----END PUBLIC KEY-----
EOF;

$data = "helloworld";

try {
    //从证书中解析获取私钥。成功,返回真实的密钥资源标识符
    $privateKeyResourceID = openssl_pkey_get_private($privateKeyString);
    if ($privateKeyResourceID === false) throw new \Exception('private key string is wrong');

    //从证书中解析获取公钥,以供使用。成功,返回真实的密钥资源标识符
    $publicKeyResourceID = openssl_pkey_get_public($publicKeyString);//这个函数可用来判断公钥是否是可用的
    if ($publicKeyResourceID === false) throw new \Exception('public key string is wrong');

    //使用私钥key加密数据data并且将结果保存至变量crypted中。
    //加密后的数据可以通过openssl_public_decrypt()函数来解密。
    openssl_private_encrypt($data, $encrypted, $privateKeyResourceID, OPENSSL_PKCS1_PADDING);

    //私钥加密
    $encrypted = base64_encode($encrypted);//加密之后的结果,base64只是为了避免特殊字符

    openssl_public_decrypt(base64_decode($encrypted), $decrypted, $publicKeyResourceID, OPENSSL_PKCS1_PADDING);//私钥加密的内容通过公钥可用解密出来

    echo $decrypted . PHP_EOL;

} catch (\Exception $e) {
    die($e->getMessage());
}
加密、解密系列
封装
<?php
/**
 * Created by PhpStorm.
 * User: zrj
 * Date: 18-11-5
 * Time: 下午8:32
 */
declare(strict_types=1);//开启强类型模式

class RSA
{
    private $publicKeyResourceID = false;//公钥资源
    private $privateKeyresourceID = false;//私钥资源
    private $publicKeyContent = '';
    private $privateKeyContent = '';

    public function __construct(string $publicKeyPath, string $privatePath)
    {
        $this->checkFilePath($publicKeyPath);
        $this->checkFilePath($privatePath);
        $this->publicKeyContent = file_get_contents($publicKeyPath);
        $this->privateKeyContent = file_get_contents($privatePath);
        if (empty($this->publicKeyContent)) throw new \Exception('Public key is empty');
        if (empty($this->privateKeyContent)) throw new \Exception('Private key is empty');

        $this->publicKeyResourceID = !empty($this->publicKeyContent) ? openssl_pkey_get_public($this->getPublicKey()) : false;
        $this->privateKeyresourceID = !empty($this->privateKeyContent) ? openssl_pkey_get_private($this->getPrivatekey()) : false;

        if ($this->publicKeyResourceID === false) throw new \Exception('解析公钥内容失败');
        if ($this->privateKeyresourceID === false) throw new \Exception('解析私钥内容失败');
    }

    /**
     * 校验文件路径
     * @param string $filePath
     * @throws Exception
     */
    public function checkFilePath(string $filePath)
    {
        if (!is_file($filePath)) throw new \Exception($filePath . ' is not a regular file');
        if (!file_exists($filePath)) throw new \Exception($filePath . ' is not exists');
    }

    //获取私有key字符串,重新格式化,为保证任何key都可以识别
    public function getPrivatekey(): string
    {
        $search = [
            "-----BEGIN RSA PRIVATE KEY-----",
            "-----END RSA PRIVATE KEY-----",
            "\n",
            "\r",
            "\r\n"
        ];

        $privateKey = str_replace($search, "", $this->privateKeyContent);
        //打断字符串为指定数量的字串
        return $search[0] . PHP_EOL . wordwrap($privateKey, 64, "\n", true) . PHP_EOL . $search[1];
    }

    /**
     *
     * 获取公共key字符串,重新格式化,为保证任何key都可以识别
     */
    public function getPublicKey()
    {
        $search = [
            "-----BEGIN PUBLIC KEY-----",
            "-----END PUBLIC KEY-----",
            "\n",
            "\r",
            "\r\n"
        ];
        $publicKey = str_replace($search, "", $this->publicKeyContent);
        //打断字符串为指定数量的字串
        return $search[0] . PHP_EOL . wordwrap($publicKey, 64, "\n", true) . PHP_EOL . $search[1];
    }

    public function createKey()
    {
        $result = openssl_pkey_new();// 生成一个新的私钥和公钥对,
        if ($result === false) return false;
        openssl_pkey_export($result, $privateKey);//将key当作PEM编码字符串导出并且将之保存到$privateKey(通过引用传递的)中。
        $publicKey = openssl_pkey_get_details($result);//返回包含密钥详情的数组
        return array('public_key' => $publicKey["key"], 'private_key' => $this->getPrivatekey());
    }

    //使用私钥加密
    public function encryptByPrivateKey(string $data): string
    {
        openssl_private_encrypt($data, $output, $this->privateKeyresourceID);
        return base64_encode($output);
    }

    //使用公钥解密
    public function decryptByPublicKey(string $data): string
    {
        openssl_public_decrypt(base64_decode($data), $output, $this->publicKeyResourceID);
        return $output;
    }

    //使用公钥加密
    public function encryptByPublicKey(string $data): string
    {
        openssl_public_encrypt($data, $output, $this->publicKeyResourceID);
        return base64_encode($output);
    }

    //使用私钥解密
    public function decryptByPrivateKey(string $data): string
    {
        openssl_private_decrypt(base64_decode($data), $output, $this->privateKeyresourceID);
        return $output;
    }

    //生成签名
    public function generateSignature(string $data, int $signType = OPENSSL_ALGO_SHA1): string
    {
        openssl_sign($data, $outSignature, $this->privateKeyresourceID, $signType);//Generate signature
        return base64_encode($outSignature);
    }

    //校验签名 OPENSSL_ALGO_SHA256为RSA2
    public function checkSignature(string $originalData, string $signature, int $signType = OPENSSL_ALGO_SHA1): bool
    {
        //如果签名正确返回 1, 签名错误返回 0, 内部发生错误则返回-1
        $result = openssl_verify($originalData, base64_decode($signature), $this->publicKeyResourceID, $signType);
        return $result == 1;
    }

    public function __destruct()
    {
        openssl_free_key($this->publicKeyResourceID);
        openssl_free_key($this->privateKeyresourceID);
    }
}

$rsaObj = new RSA('/home/zrj/.ssh/rsa_public.key', '/home/zrj/.ssh/rsa_private.key');

$str = 'Hello world';
echo '原始数据:' . $str . PHP_EOL;
echo '公钥加密私钥解密如下:' . PHP_EOL;
$tmpstr = $rsaObj->encryptByPublicKey($str); //用公钥加密
echo '加密后的数据:' . PHP_EOL;
echo $tmpstr . PHP_EOL;
$tmpstr = $rsaObj->decryptByPrivateKey($tmpstr); //用私钥解密
echo '解密结果:' . $tmpstr . PHP_EOL;
echo PHP_EOL;
echo PHP_EOL;
echo '私钥加密公钥解密如下:' . PHP_EOL;
$tmpstr = $rsaObj->encryptByPrivateKey($str); //用私钥加密
echo '私钥加密后的数据:' . PHP_EOL;
echo $tmpstr . PHP_EOL;
$tmpstr = $rsaObj->decryptByPublicKey($tmpstr); //用公钥解密
echo '公钥解密结果:' . $tmpstr . PHP_EOL;

echo PHP_EOL;
echo PHP_EOL;
$signature = $rsaObj->generateSignature($tmpstr);
echo '签名结果为:' . $signature . PHP_EOL;

var_dump($rsaObj->checkSignature($tmpstr, $signature));
推荐阅读:
  1. openssl+http实现https
  2. 使用php openssl扩展实现非对称加密

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

php openssl 非对称式加密解密

上一篇:SQL Server中如何存储过程邮件以格式形式发送

下一篇:网络知识&http协议

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》