我在创建/使用 PHP 中创建和使用的 RSA 密钥时遇到问题。问题是,(公共和私人)密钥应该在不同的服务器之间交换(例如,当用户帐户移动时)。
现在,PHP 的 openssl-lib 没有提供任何有关创建密钥格式的详细信息。http://php.net/manual/en/function.openssl-pkey-export.php上的最新文档只是声明它是“PEM 格式”,但没有说明它是 PKCS#1 还是PKCS#8
此外,私钥 PEM 的标头和尾标在 PHP 版本之间有所不同,如以下代码所示:
<?php
$config = array(
"digest_alg" => 'sha512',
"private_key_bits" => 4096,
"private_key_type" => OPENSSL_KEYTYPE_RSA
);
$keyPair = openssl_pkey_new($config);
$privateKey = NULL;
openssl_pkey_export($keyPair, $privateKey);
var_dump($privateKey);
$keyDetails = openssl_pkey_get_details($keyPair);
$publicKey = $keyDetails['key'];
var_dump($publicKey);
die();
?>
将输出不同的东西:
PHP v 5.4:
string(3272) "-----BEGIN PRIVATE KEY-----
MIIJRAIBADANBgkqhkiG9w0BAQEFAASCCS4wggkqA//...
-----END PRIVATE KEY-----
"
string(800) "-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAO//...
-----END PUBLIC KEY-----
"
PHP v 5.5:
string(3272) "-----BEGIN RSA PRIVATE KEY-----
MIIJRAIBADANBgkqhkiG9w0BAQEFAASCCS4wggkqA//...
-----END RSA PRIVATE KEY-----
"
string(800) "-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAO//...
-----END PUBLIC KEY-----
"
PHP v 5.6:
string(3272) "-----BEGIN PRIVATE KEY-----
MIIJQgIBADANBggsdisdVUCJDSQCjqgl2XqzR+bSv//...
-----END PRIVATE KEY-----
"
string(800) "-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BsdvQEFAAOdfAg8AMIICFAgEAo6oJdl6s0fm0r7QlaN/U//...
-----END PUBLIC KEY-----
"
因此,私钥头/尾随您使用的 PHP 版本而变化。这不会是一个真正的问题,但事实证明,一个将创建一个带有“RSA”的密钥头的系统将无法使用没有“RSA”的密钥,例如,openssl_sign():你会得到一个错误指出“提供的密钥不能被强制转换为私钥”......这就是它变得混乱的地方。
根据https://tls.mbed.org/kb/cryptography/asn1-key-structures-in-der-and-pem,标头中带有“RSA”的私钥 PEM 格式和那些没有,是 PKCS#1 和 PKCS#8,即是否有关于算法等的附加信息。
因此,我遇到了严重的问题。为 PHP5.6 编写的相同软件无法在 PHP5.5 上运行。On 可以通过手动将 5.5 标题替换为 5.6 兼容的标题来使用解决方法,但这只是一个“肮脏的黑客”。有没有一种“好”的方法来处理这个问题?
在设置时,这个替换代码会尝试创建一个私钥,提取标题并“记住它”。然后将检查运行时使用的所有密钥。如果找到的标头不适合“本地”标头,则需要交换它们。
但我想有某种配置选项(我还没有找到)可以配置使用哪种格式?
接下来,更有趣的问题:openssl 究竟创建了什么格式?PKCS#1?PKCS#8?这也是可配置的吗?