PHP OpenSSL扩展 - 非对称加密

2018-02-09 12:41:23来源:https://www.jianshu.com/p/901be4dd9a3d作者:切糕糕人点击

分享


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 的 n、e1、e2 值。。。不用深究这几个值,他们已经是密码学原理才能解释的东西了。我们只关心分析结果的 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;

结果:



最新文章

123