PHP Conference Japan 2024

openssl_pkey_export

(PHP 4 >= 4.2.0, PHP 5, PHP 7, PHP 8)

openssl_pkey_export将密钥的可导出表示形式获取到字符串中

描述

openssl_pkey_export(
    #[\SensitiveParameter] OpenSSLAsymmetricKey|OpenSSLCertificate|数组|字符串 $key,
    字符串 &$output,
    #[\SensitiveParameter] ?字符串 $passphrase = null,
    ?数组 $options = null
): 布尔值

openssl_pkey_export()key 导出为 PEM 编码的字符串,并将其存储到 output 中(通过引用传递)。

注意: 您需要安装有效的 openssl.cnf 才能使此函数正常工作。有关更多信息,请参阅安装部分下的说明。

参数

key

output

passphrase

密钥可以选择由 passphrase 保护。

options

options 可用于通过指定和/或覆盖 openssl 配置文件选项来微调导出过程。有关 options 的更多信息,请参阅 openssl_csr_new()

返回值

成功时返回 true,失败时返回 false

变更日志

版本 描述
8.0.0 key 现在接受 OpenSSLAsymmetricKeyOpenSSLCertificate 实例;以前,接受类型为 OpenSSL keyOpenSSL X.509资源
添加注释

用户贡献的注释 6 条注释

chris dot kistner at gmail dot com
13 年前
请注意,较旧版本的 PHP/OpenSSL 会使用“-----BEGIN RSA PRIVATE KEY-----” PEM 标签导出 RSA 私钥,其中仅包含 privateKey 字段,因此省略了 version 和 privateKeyAlgorithm 字段。

这样做的影响是,如果您将其转换为 DER,然后转换回 PEM,但使用“-----BEGIN PRIVATE KEY-----” PEM 标签,则 openssl_pkey_get_privatekey() 函数将失败!

Senthryl 的代码可用于再次在 PEM 编码数据前添加 version 和 privateKeyAlgorithm 字段。

较新的 PHP/OpenSSL 版本使用“-----BEGIN PRIVATE KEY-----” PEM 标签导出 RSA 私钥,其中包含 version 和 privateKeyAlgorithm 字段。

我在我的两台服务器之间注意到了这些差异
PHP 版本 5.3.3(OpenSSL 1.0.0a-fips 2010 年 6 月 1 日)在 Fedora Core 12 x64 上
PHP 版本 5.2.9(OpenSSL 0.9.8g 2007 年 10 月 19 日)在 Fedora Core 10 x64 上
eric at ericseastrand dot com
12 年前
我今天一直在撞墙,试图弄清楚为什么我生成的 RSA 密钥被加密了(它们包含这些东西)
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,BEA1180EADE1524F

我最终意识到问题在于我无意中将密码传递给了“openssl_pkey_export”方法。

所以故事的寓意是:您必须使用 NULL 作为密码。使用空字符串仍会导致密钥被加密。
robbat2 at gentoo dot org
20 年前
警告,此函数不能导出 PEM 编码的公钥。它只能导出私钥。
Senthryl
14 年前
此函数可用于创建供 Java 中 JCE 使用的私钥。例如,私钥可以由 PHP 脚本生成,其结果可以在 Java 客户端应用程序中使用。

Java 需要以 DER 格式的私钥以及一些额外的 ASN.1 包装。以下函数可用于将 openssl_pkey_export 的输出转换为适合输入 JCE 的格式

<?php
function derLength($length) {
if (
$length < 128) return str_pad(dechex($length), 2, '0', STR_PAD_LEFT);
$output = dechex($length);
if (
strlen($output) % 2 != 0) $output = '0'.$output;
return
dechex(128 + strlen($output)/2) . $output;
}
function
convertPemToDer($pem) {
$matches = array();
if (!
preg_match('~^-----BEGIN ([A-Z ]+)-----\s*?([A-Za-z0-9+=/\r\n]+)\s*?-----END \1-----\s*$~D', $pem, $matches)) {
die(
'遇到无效的PEM格式。'."\n");
}
$derData = base64_decode(str_replace(array("\r", "\n"), array('', ''), $matches[2]));
$derData = pack('H*', '020100300d06092a864886f70d010101050004'.derLength(strlen($derData))) . $derData;
$derData = pack('H*', '30'.derLength(strlen($derData))) . $derData;
return
$derData;
}
?>

示例用法
<?php
$keys
= openssl_pkey_new(array('digest_alg' => 'sha1', 'private_key_type' => OPENSSL_KEYTYPE_RSA, 'private_key_bits' => 2048));
if (
$keys === false) die('密钥对生成失败。'."\n");
if (!
openssl_pkey_export($keys, $privateKey)) die('无法检索私钥。'."\n");
$javaKey = convertPemToDer($privateKey);

file_put_contents('key_for_java.der', $javaKey);
?>

导出用于JCE的公钥比较棘手,因为Java库要求将密钥作为字节数组输入。实际上,由openssl_pkey_get_details()输出的公钥必须像上面一样进行base64解码,然后作为ASN.1进行解析以接收实际的密钥字节(这可以在PHP端或Java端完成)。

以下链接是理解这些函数输出的宝贵资源
“ASN.1、BER和DER的门外汉指南”
http://luca.ntop.org/Teaching/Appunti/asn1.html
phpRocks dot net上的Tk
15年前
加密数据的完整示例...
=)
<pre>
<?php
// 创建密钥对
$res=openssl_pkey_new();

// 获取私钥
openssl_pkey_export($res, $privkey, "PassPhrase number 1" );

// 获取公钥
$pubkey=openssl_pkey_get_details($res);
$pubkey=$pubkey["key"];
//var_dump($privkey);
//var_dump($pubkey);

// 创建密钥对
$res2=openssl_pkey_new();

// 获取私钥
openssl_pkey_export($res2, $privkey2, "This is a passPhrase *µà" );

// 获取公钥
$pubkey2=openssl_pkey_get_details($res2);
$pubkey2=$pubkey2["key"];
var_dump($privkey2);
var_dump($pubkey2);

$data = "Only I know the purple fox. Trala la !";

openssl_seal($data, $sealed, $ekeys, array($pubkey, $pubkey2));

var_dump("sealed");
var_dump(base64_encode($sealed));
var_dump(base64_encode($ekeys[0]));
var_dump(base64_encode($ekeys[1]));

// 解密数据并将其存储在$open中
if (openssl_open($sealed, $open, $ekeys[1], openssl_pkey_get_private ($privkey2 ,"This is a passPhrase *µà" ) ) ) {
echo
"这是解密后的数据:", $open;
} else {
echo
"解密数据失败";
}

?>
</pre>

输出
string(963) "-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,DA1943487C9C83B2

1/j65PJgfYqYMJSWRBk9UzXaa3USMdpkq4ztzL7IPMTPgTwVKxZbvBxzsGUXUmh6
dkWpF1jzi3B44o06mw55t2LHNkGAph/iKVP4Zvnyp/KWaZJSF+pNkvukle1u2/40
WpbNy1f8LA+ZDr7ICOCY1jy/bz/xzOCrVjqY/F4ukQik9M6bL9ZwI5fyhrcHq6EG
KsUX49XKtP/a+kQhluejzIw1aDBqmHpJTCzkL7teCk6l8x8r8mMmss1D9XqggjFm
TQncqR6IU5DClklO53JdWSFC5zTcFYMgq9lMwCQ5o4bs8iBKiE+TOFEKiggtn5zA
v189tlPtM6YePcXAm5Ymgy90Ovq3lGS4k+JkCB2Hm3HgUAB3pd9v3fOeyuFMeing
XHBuLR5nmWITzcfRuAsh0p9xe2puTVFdrLkrQFnh5Xkerm+YUQ6oTecTKRFq7S3l
hLlFIg7KbXxDjg3H5f87DCEp/isV70Rc7flvIBP6u5GX+GrmCFWjQxmGefEJQ5fZ
P7sOzHEdkOHZV7yYn+5MwQ4vDHLKQxvMqUolgvuEAzcL1o976KHAQP0accmwApXz
jry3zVqRnGvyPHo+nGwRiATJj0lAgX/j8cghJg+oo+TiXD2cM5i+Hut4dmImZNDL
3Fn2uLzklQHPlaoaz2dACyaN/sUtmVLtdnn00nuwIy2xDfHDl9MOQ6WHocU78DWo
Mw+x8B+SBsALm3Ah6JzqA8l3OAYSRxjp7YQXLQLkdCi7jEjjTl/0NVTnqU+W89XB
GBH3r8ZgIpifl3M7ZYTKLnToNL7Y/AehPs+tKgFHkXtGMKu4cIt9Ag==
-----END RSA PRIVATE KEY-----
"
string(272) "-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDH82E/Dn37torKz/vhAkpji9ZS
HCyfM7JuXCbh70F75Zh2/rEVvz38yNf6f01DNXiSpzO5eTmoXD7Blsb635AOjYbl
X/WljpFbwQ2QUUDlNDAslrqXYlMzht2MCq/pjtGgk0zJx6i+HjFyV7mebeePQY/x
NOzMpmy/Ke3u+SSHRwIDAQAB
-----END PUBLIC KEY-----
"
string(6) "sealed"
string(52) "y4L3+SDVJwTfa9Em61R3X2p/LElr8N/xPCXw8kqm0co4bn3V1Tw="
string(172) "ezUo2rWLGHPv9bHE5gG8fe5qy8erGlITsSs+qGr2o8aoi98SLnyIFm4N
EQWJrmU43Ehlw72NujJ
B8chYNw2NkIDfaLChvLH54CBuCfyuF+1lWEAUwL8
FU1LftqIIt1ikjSu/8qFU6S6wikJx1pFf1IbXfOeeJVvZ1UJM2rBbudI="
string(172) "RPYLXGBXDnXDIUrFy1/GOM+//Ew/mn2syKDbhIegOJJPnpd
X6ffwXkWH5Bp8kOdz0aO9gK3whG+c
/QF+9eqcTw9SvvlrDqsP0gkRGNIOgMUiBFLoMT92JQWSI7ZesDAU0
JPRWpXsKaIOEkBGmxOMYfEd6OJWp0Mwe4COL3lP2PQ="
这是解密后的数据:Only I know the purple fox. Trala la !
匿名
17年前
您可以使用openssl_pkey_get_details(resource $key ) 函数获取公钥

<?php

$pub_key
= openssl_pkey_get_public(file_get_contents('./cert.crt'));
$keyData = openssl_pkey_get_details($pub_key);
fule_put_contents('./key.pub', $keyData['key']);

?>
To Top