美文网首页PHP实战PHP经验分享自留地
PHP OpenSSL扩展 - 非对称加密

PHP OpenSSL扩展 - 非对称加密

作者: 切糕糕 | 来源:发表于2018-02-08 20:40 被阅读99次

    PHP 在进入7.x 时代后,默认就不再附带 mcrypt 扩展,mcrypt 将被 openssl_* 一族函数所替代。所以,对于 PHPer 来说,有必要学习一下 PHP 的 OpenSSL 扩展。

    上一篇文章《PHP中OpenSSL扩展 - 对称加密》 ,介绍了 OpenSSL 扩展中对称加密的使用方法,本文将介绍非对称加密的使用方法。

    PHP 的 OpenSSL 扩展中,非对称加密的相关函数有:

    • openssl_pkey_new
    • openssl_pkey_export
    • openssl_pkey_export_to_file
    • openssl_pkey_get_details
    • openssl_pkey_free
    • openssl_pkey_get_private
    • openssl_pkey_get_public
    • openssl_get_privatekey
    • openssl_get_publickey
    • openssl_private_decrypt
    • openssl_private_encrypt
    • openssl_public_decrypt
    • openssl_public_encrypt

    别被这么多函数吓倒,经过本文的讲解,你会发现非对称加密的过程并不繁琐。让我们通过实例来讲解每个函数的作用。

    1. 生成密钥对

    首先,想要进行非对称加密 / 解密,你得有一对公钥(Public key)和私钥(Private key)。在Linux环境下,公钥私钥可以用 openssl 命令生成。PHP的 OpenSSL 扩展中,openssl_pkey_new() 函数可以完成同样的事:

    <?php
    // 生成私钥
    $privateKey = openssl_pkey_new();
    openssl_pkey_export($privateKey, $out);
    echo $out;
    

    上面两行代码生成了一个私钥,并导出到了 $out 变量中。

    延伸一下,如果你打印 $out 变量,会看见一个由大小写字母和数字组成的“乱码块”,外层被-----BEGIN PRIVATE KEY----------END PRIVATE KEY-----包裹着。这其实是 PEM 格式的私钥,乱码块是被 Base64 编码的二进制数据。

    注意到现在只生成了一个私钥,那么公钥在哪呢?OpenSSL扩展并没有生成公钥的函数,公钥是从私钥当中提取出来的,使用 openssl_pkey_get_details() 函数:

    从私钥提取公钥
    <?php
    $privateKey = openssl_pkey_new();
    $detail = openssl_pkey_get_details($privateKey);
    $publicKeyString = $detail['key'];
    echo $publicKeyString;
    

    openssl_pkey_get_details() 接受一个私钥对象,返回一个 array 包含私钥中附带的相关信息,比如 RSA 的 ne1e2 值。。。不用深究这几个值,他们已经是密码学原理才能解释的东西了。我们只关心分析结果的 key 值,key 值就是提取出来的公钥啦。

    我们将公钥私钥分别保存到磁盘上:

    <?php
    // 如果密钥已经是PEM格式的了,那就直接写到磁盘上
    file_put_contents('public.key', $publicKeyString);
    
    // 否则需要用 openssl_pkey_export()
    // 或者openssl_pkey_export_to_file()
    // 转换成PEM格式
    openssl_pkey_export_to_file($privateKey, 'private.key');
    

    有了一对公钥、私钥之后,就可以进行非对称加密了。注意 公钥 可以分发给别人用的,而 私钥 只能你自己知道,否则非对称加密系统就完全失效了。

    2. 非对称 加密 与 解密

    在不管是加密还是解密,都要先读取密钥。上一节我们保存在磁盘上的密钥是PEM格式的,不能直接用,需要用 openssl_pkey_get_public()openssl_pkey_get_private() 读取:

    <?php
    $privateKey = openssl_pkey_get_private(file_get_contents('private.key'));
    $publicKey = openssl_pkey_get_public(file_get_contents('public.key'));
    

    另外还有两个函数:openssl_get_privatekey()openssl_get_publickey(),只是上述两个函数的别名,完成的功能相同。

    介绍了一大堆,终于到了真正的加密解密了。因为是非对称加密,所以公钥和私钥是交错使用的:公钥加密的数据用密钥解密,同样,私钥加密的数据用公钥解密。

    公钥加密私钥解密:
    // 加密
    $publicKey = openssl_pkey_get_public(file_get_contents('public.key'));
    openssl_public_encrypt('PHP是世界上最好的语言!', $encrypted, $publicKey, OPENSSL_PKCS1_OAEP_PADDING);
    echo $encrypted . PHP_EOL;
    
    // 解密
    $privateKey = openssl_pkey_get_private(file_get_contents('private.key'));
    openssl_private_decrypt($encrypted, $decrypted, $privateKey, OPENSSL_PKCS1_OAEP_PADDING);
    echo $decrypted . PHP_EOL;
    

    结果:

    񏳻qz¬icG߇!?ꕦNׇ.¿0QM]_+B󽷧i=輬©𥆈>¹N`Z㹔̡ד䴹¨Z9qr죡¾<zɥH«󿿻dy򿴁я³T򚧢G¾q»HE𥊮SAxd綧h` 񧘔6䡝פ𲐍£n𻕞Q¹ۉq񨻃򧂳󂎚
    PHP是世界上最好的语言!
    

    可以看到经过加密后,明文已经变成完全无法阅读的乱码了。经过解密后又变回了原文。公钥加密私钥解密满足了最常见的数据保密的需求,别人用你的公钥加密的数据,只能用你自己的私钥解开。

    私钥加密公钥解密
    // 加密
    $privateKey = openssl_pkey_get_private(file_get_contents('private.key'));
    openssl_private_encrypt('PHP是世界上最好的语言!', $encrypted, $privateKey);
    echo $encrypted . PHP_EOL;
    
    // 解密
    $publicKey = openssl_pkey_get_public(file_get_contents('public.key'));
    openssl_public_decrypt($encrypted, $decrypted, $publicKey);
    echo $decrypted . PHP_EOL;
    

    输出的结果与公钥加密类似,就不再赘述了。私钥加密公钥解密一般用于签名,因为用你的私钥加密的内容,大家只能用你的公钥解开,从而保证了加密的信息确实是由你发出的。

    相关文章

      网友评论

      • 3cab0738da23:学习啦,我想问问,有没有办法用PHP代码生成-----BEGIN RSA PRIVATE KEY-----这种PKCS1的
      • 阿拉侬:大神,加油!真棒👍
      • 1a59cc26bf59:哇,大神太专业了,深入浅出、条理清晰,加个微信好友吧
        切糕糕:有你赞我就有动力多写点,帮助大家整理知识,省的网上乱搜还不全

      本文标题:PHP OpenSSL扩展 - 非对称加密

      本文链接:https://www.haomeiwen.com/subject/aofwzxtx.html