上篇文章,咱们理解了对于对称和非对称加密的一些相干的理论知识,也学习了应用 OpenSSL 来进行对称加密的操作。明天,咱们就更进一步,学习 OpenSSL 中的非对称加密是如何实现的。

生成私钥

通过之前的学习,咱们晓得非对称加密是别离须要一个公钥和一个私钥的。咱们就先来生成一个私钥,也就是寄存在咱们这一端一个密钥。请记住,在任何时候,私钥都是不能给他人的哦!

$config = array(    "private_key_bits" => 4096, // 指定应该应用多少位来生成私钥);$res = openssl_pkey_new($config); // 依据配置信息生成私钥openssl_pkey_export($res, $privateKey); // 将一个密钥的可输入示意转换为字符串var_dump($privateKey); // -----BEGIN PRIVATE KEY-----// MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQDFMLW+9t3fNX4C// YBuV0ILSyPAdSYVXtE4CLv32OvNk9yQZgF2nL/ZuIbBGRcYo2Hf5B31doGrAFDGu// NoTR+WA7CBjKROFr/+yValsMFIeiKNtttWMkmBciysDJoEoyd6wjDD+kcHQdoJVo// ……// -----END PRIVATE KEY-----

非常简单的一个函数 openssl_pkey_new() ,它接管一个参数,这个参数是可配置项并且是可选参数。生成的后果是一个私钥句柄,不是咱们能间接读取的内容,所以咱们再应用 openssl_pkey_export() 来提取可输入的字符串。

正文中的内容就是咱们生成的私钥信息了,私钥信息个别会绝对多些,所以省略了前面的内容。

抽取公钥

接下来就是生成公钥了,其实,公钥是从私钥中抽取进去的。所以咱们应用进行加解密的时候,都能够应用私钥或者公钥相互操作。

$publicKey = openssl_pkey_get_details($res); // 抽取公钥信息var_dump($publicKey);// array(4) {//     ["bits"]=>//     int(4096)//     ["key"]=>//     string(800) "-----BEGIN PUBLIC KEY-----//   MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtOIImDdS0W0vAr5Ra1+E//   hR2AJwQQwxntYKgTku8EmJRBX2vU+x8th8W8SnoGiVM/sOItG0HIe4Egf1UxoZHt//   gI6r+jpAp7JbTN0sD/VTPDE09F21+hFGjIVBqrkcLPjuEbf7+tjmgAx8cG8WLGId//   G8Hsub70kRANKJe1bCXIBUggRFk0sQGllxA/hxiG5wANqHTrdpJgJba+ahSi2+4H//   UWnyCV1O3AaPyz6a12HNUsG4Eio/tWv/hOB9POt6nAqwPHuIbhp56i5bv1ijMJZM//   jwRen5f/kwdZ01Ig2fi0uBoTR2y/EEaus7xBYpF/gGzZ/uM7cNUXcDyG5YluM/4R//   MEv4msPMVGB72izItED+C6Cqftxl98iBFRDc+PISFbRSgOU/HsuBhKkM5SYzyi3I//   Ypaej25++qLPqcA+EDr3JNDhNZ0GOhofCRtPq4dsr7iLLLRnZ0TnhIYe9wAbmO49//   uthABNBkM54bG+omOfY4Bkn5n39CKpELbhIiXgOd+lA684XUS/2Aw3Dvelc9Gbag//   oIFvb/wljPYsd0Zmd64CXBpTWbfwXC8K4vCKvFLjytcz2Yp4T6fVjbLT5RA6u8su//   E0WwE4QTFNKhnM5OvfiMN+NMc3Y/esVfcin3eyvotdz4N6Tt45dkybkf6aQE3Scg//   E/JBLIEEA+gjGTveY4cNUiECAwEAAQ==//   -----END PUBLIC KEY-----//   "//     ["rsa"]=>// ……$publicKey = $publicKey['key'];

应用 openssl_pkey_get_details() 抽取进去的内容蕴含很多内容。不过咱们所须要的最次要的内容就是 key 上面的这个公钥。

大家再回过头来好好看一下公钥和私钥的内容,是不是和咱们去申请的 HTTPS 证书中的公私钥内容长得一样,而且也和咱们本人在零碎中应用 openssl 命令行生成的本机的密钥证书一样。它们自身就是一样的货色啦,只是在不同的场景利用的不同而已。HTTPS 证书除了非对称加密的密钥之外,还蕴含有 CA 信息,如果 CA 不通过,浏览器也会认为证书是有效的,因而,咱们应用本人生成的证书来充当 HTTPS 证书是不能够的。而自身生成的个别会用在 SSH 免密登录上,或者是 GitHub 的免密代码仓库操作上。

加密解密数据

好了,公钥和私钥都生成实现了,那么咱们就要进行最重要的加密和解密操作了。

$data = '测试非对称加密';// 公钥加密数据openssl_public_encrypt($data, $encrypted, $publicKey);var_dump($encrypted);// string(512) "��E��2��~��\d����q�O�=(��Y���3L����0�,�J����s�V��VG~'�20���@��6�d�����#Z]�.��<Z��8G�����-�M�0](2��+$�*����\e�7��|SUw�#rFb�8"�s4K�B�Y�'�\S���~!<�"���!U��S(���S ��?e�r��/���c��L�YL�'ŖE*S��[�J�"�n��`(oF$�|kC�*j_y�E�D�O����H5���6�t�TY����b5l^)�`�v�>�1��a��r��D��������@�S�>�t|���匓�z~K�,���y��G��//                                                              yXZ�L#��c `rj睅,nX���@{7�:�qy�nv�o§�@�@,�n&���I�~ǧ�z6���oe!8,T�����;�6�J@A��f����S]��!����2�b��+O��o�<�//                                                                                                                                                                        ����-�+et��})�KG��$���,�Z|�"// 私钥解密数据openssl_private_decrypt($encrypted, $decrypted, $privateKey);var_dump($decrypted);// string(21) "测试非对称加密"

在这里,咱们应用的就是最规范的公钥加密,私钥解密来进行的测试。其实反过来也是能够的,OpenSSL 别离都为咱们提供了公钥的加解密和私钥的加解密函数。

就像上篇文章的图示那样,对方取得咱们的公钥,而后加密数据传输过去,咱们通过本人的私钥解密数据取得原文。而我方也能够取得对方的公钥,并将返回的数据加密后传输给对方,而后对方应用本人的私钥进行解密取得咱们传递给它的原文数据。

而 HTTPS 是通过 CA 颁发的证书来获取公钥的,浏览器通过公钥加密申请数据传输给服务器,服务器也是通过雷同的原理来向浏览器客户端发送密文数据。因而,在数据传输过程中,应用 HTTPS 的传输会更加地平安,即便被截获了,对方也没有证书提供的密钥来进行解密。这就是当初所有 App 和 小程序 利用都要求应用 HTTPS 的起因,当然,咱们如果做网站开发也最好应用 HTTPS ,就连百度对 HTTPS 的收录也有相应的调整。

签名及验证

接下来咱们再接触一个签名的概念。当两端进行通信时,咱们怎么晓得以后传输过去的数据肯定是对端发送过去的的呢,两头有没有黑客进行了篡改呢?这个就能够通过签名机制来进行验证。

// 利用私钥生成签名openssl_sign($data, $signature, $privateKey, OPENSSL_ALGO_SHA256);var_dump($signature);// ��<�~�k�N����M�q��;��h�dŬ�Ğ�m�3�nj��/i���U�_�E2z���>B�N�WM!TN�c�F�/��,5�|���%��c~O)"// ��      >��)y�fn��q��}//                       �`//                         �z��{��_D�s`�����|y�,g>R�D��%�//                                                       �g0�@|��|z}���bZI2,����~Q_���I�LW~���G&���f�|eq�s�D���L���bC'D��~8:�Z����\�9]C�Kd~F96�S� 0��y>�(T��S}��1�謃T//                                                                                                                                                                    �!��!!�Lj�<�ǺfM�o7�3��������� 8ZR<Vya4����V��W����L�QZbv��7?�v`}��?v ǿ�0`�OF��F��@�$b�PBI�o\�v���D���"// 公钥验证签名$r = openssl_verify($data, $signature, $publicKey, OPENSSL_ALGO_SHA256);var_dump($r);// int(1)

咱们通过 openssl_sign() 来生成一个对原始数据的私钥签名,而后就能够应用 openssl_verify() 通过公钥验证数据签名是否统一。

在应用的时候,发送方通过本人的私钥生成签名,因为签名内容是乱码的,咱们能够将它 base64_encode() 一下,而后连同加密数据一起传递给接管方。而后接管方应用公钥并依据签名内容来验证原文数据是否被篡改过。

// 发送方签名$resquestSign = base64_encode($signature);// 假如通过网络申请发送了数据// ……// 接管到取得签名及原始数据// $signature = $_POST['sign'];// openssl_private_decrypt($_POST['data'], $data, $privateKey); $responseSign = base64_decode($signature);// 验证数据有没有被篡改$r = openssl_verify($data, $signature, $publicKey, OPENSSL_ALGO_SHA256);var_dump($r);// int(1)// 假如被篡改$data = '我被批改了';$r = openssl_verify($data, $signature, $publicKey, OPENSSL_ALGO_SHA256);var_dump($r);// int(0)

总结

明天的内容是不是感觉比对称加密简单了许多。特地新引入的签名的这个概念,其实很多证书相干的内容都会和数据签名有关系。也就是说,看似简略的一个 HTTPS ,其实浏览器和服务端的 openssl 帮咱们做了很多事件,远不止你去 CA 申请一套证书而后在 Nginx 配好那么简略。那么,接下来,咱们将要学习的就是生成证书相干的内容了,系好安全带,车还要持续飙。

测试代码:

https://github.com/zhangyue0503/dev-blog/blob/master/php/202007/source/PHP%E7%9A%84OpenSSL%E5%8A%A0%E5%AF%86%E6%89%A9%E5%B1%95%E5%AD%A6%E4%B9%A0%EF%BC%88%E4%BA%8C%EF%BC%89%EF%BC%9A%E9%9D%9E%E5%AF%B9%E7%A7%B0%E5%8A%A0%E5%AF%86.php

参考文档:

https://www.php.net/manual/zh/function.openssl-pkey-new.php

https://www.php.net/manual/zh/function.openssl-pkey-get-details.php

https://www.php.net/manual/zh/function.openssl-pkey-export.php

https://www.php.net/manual/zh/function.openssl-public-encrypt.php

https://www.php.net/manual/zh/function.openssl-private-decrypt.php

https://www.php.net/manual/zh/function.openssl-sign.php

https://www.php.net/manual/zh/function.openssl-verify.php

各自媒体平台均可搜寻【硬核项目经理】