PHP OpenSSL扩展 - 非对称加密

PHP OpenSSL扩展 - 非对称加密


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;

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

发布了43 篇原创文章 · 获赞 50 · 访问量 68万+

猜你喜欢

转载自blog.csdn.net/supergao222/article/details/79293465