PHP RSA 密钥创建
PHP RSA key creation
我对在 PHP 中创建和使用的 creating/using RSA 密钥有疑问。问题是,(public AND private)密钥应该在不同的服务器之间交换(例如,当用户帐户被移动时)。
现在,PHP 的 openssl-lib 没有提供任何关于密钥创建格式的详细信息。 http://php.net/manual/en/function.openssl-pkey-export.php 的最新文档只是说明它是 "in PEM format",但没有说明它是在 PKCS#1 还是 PKCS#8
此外,私钥 PEM 的 headers 和尾部在 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-----
"
因此私钥 header/trailer 会根据您使用的 PHP 版本而变化。这不会是一个真正的问题,但事实证明,一个系统将创建一个密钥 header WITH "RSA" 将无法在没有 "RSA" 的情况下使用密钥,例如,openssl_sign():你会收到一条错误消息,指出 "provided key couldn't be coerced into a private key"... 这就是它变得混乱的地方。
根据 https://tls.mbed.org/kb/cryptography/asn1-key-structures-in-der-and-pem,在 header 中带有 "RSA" 的私钥 PEM 格式和没有 PKCS#1 和 PKCS#8 的私钥 PEM 格式应该有所区别,即是否包含有关算法等的附加信息。
因此,我 运行 遇到了严重的问题。为 PHP5.6 编写的同一软件不能在 PHP5.5 上 运行。 On 可以通过手动将 5.5-header 替换为 5.6 兼容的版本来使用变通方法,但这只是一个 "dirty hack"。有没有 "good" 的方法来处理这个问题?
在设置时,这个 replacement-code 会尝试创建私钥,提取 header 和 "remember it"。然后将检查在 运行 时间使用的所有密钥。如果找到的 header 不适合 "local" 的,则需要交换它们。
但我想有某种配置选项(我还没有设法找到)可以配置使用哪种格式?
接下来,更有趣的问题:openssl到底创建了什么格式? PKCS#1? PKCS#8?这也可以配置吗?
没有配置(不幸的是)。只是 PHP + OpenSSL 版本问题。 BEGIN RSA PRIVATE KEY
表示 PKCS#1 格式。没有 RSA
它是 PKCS#8。
(我的老post同样的问题)
what is the differences between "BEGIN RSA PRIVATE KEY" and "BEGIN PRIVATE KEY".
您可以尝试 phpsec 库或从命令行调用 openssl (exec()
)。我知道这对你没有帮助,但似乎还没有好的解决方案。
编辑
我稍微修改了你的测试脚本并在我的 windows 7.
上测试了私钥格式
<?php
$keyPair = openssl_pkey_new(array(
"digest_alg" => 'sha512',
"private_key_bits" => 4096,
"private_key_type" => OPENSSL_KEYTYPE_RSA
));
$privateKey = null;
openssl_pkey_export($keyPair, $privateKey);
echo sprintf("PHP: %s\n", phpversion());
echo sprintf("OpenSSL: %s\n", OPENSSL_VERSION_TEXT);
echo sprintf("Private key header: %s\n", current(explode("\n", $privateKey)));
PHP: 5.4.44
OpenSSL: OpenSSL 0.9.8zf 19 Mar 2015
Private key header: -----BEGIN RSA PRIVATE KEY-----
PHP: 5.5.28
OpenSSL: OpenSSL 1.0.1p 9 Jul 2015
Private key header: -----BEGIN PRIVATE KEY-----
PHP: 5.6.12
OpenSSL: OpenSSL 1.0.1p 9 Jul 2015
Private key header: -----BEGIN PRIVATE KEY-----
根据更新日志,这些结果重现了 openssl 的默认行为。
Changes between 0.9.8n and 1.0.0 [29 Mar 2010]
Make PKCS#8 the default write format for private keys, replacing the
traditional format. This form is standardised, more secure and doesn't
include an implicit MD5 dependency.
[Steve Henson]
我对在 PHP 中创建和使用的 creating/using RSA 密钥有疑问。问题是,(public AND private)密钥应该在不同的服务器之间交换(例如,当用户帐户被移动时)。
现在,PHP 的 openssl-lib 没有提供任何关于密钥创建格式的详细信息。 http://php.net/manual/en/function.openssl-pkey-export.php 的最新文档只是说明它是 "in PEM format",但没有说明它是在 PKCS#1 还是 PKCS#8
此外,私钥 PEM 的 headers 和尾部在 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-----
"
因此私钥 header/trailer 会根据您使用的 PHP 版本而变化。这不会是一个真正的问题,但事实证明,一个系统将创建一个密钥 header WITH "RSA" 将无法在没有 "RSA" 的情况下使用密钥,例如,openssl_sign():你会收到一条错误消息,指出 "provided key couldn't be coerced into a private key"... 这就是它变得混乱的地方。
根据 https://tls.mbed.org/kb/cryptography/asn1-key-structures-in-der-and-pem,在 header 中带有 "RSA" 的私钥 PEM 格式和没有 PKCS#1 和 PKCS#8 的私钥 PEM 格式应该有所区别,即是否包含有关算法等的附加信息。
因此,我 运行 遇到了严重的问题。为 PHP5.6 编写的同一软件不能在 PHP5.5 上 运行。 On 可以通过手动将 5.5-header 替换为 5.6 兼容的版本来使用变通方法,但这只是一个 "dirty hack"。有没有 "good" 的方法来处理这个问题?
在设置时,这个 replacement-code 会尝试创建私钥,提取 header 和 "remember it"。然后将检查在 运行 时间使用的所有密钥。如果找到的 header 不适合 "local" 的,则需要交换它们。
但我想有某种配置选项(我还没有设法找到)可以配置使用哪种格式?
接下来,更有趣的问题:openssl到底创建了什么格式? PKCS#1? PKCS#8?这也可以配置吗?
没有配置(不幸的是)。只是 PHP + OpenSSL 版本问题。 BEGIN RSA PRIVATE KEY
表示 PKCS#1 格式。没有 RSA
它是 PKCS#8。
what is the differences between "BEGIN RSA PRIVATE KEY" and "BEGIN PRIVATE KEY".
您可以尝试 phpsec 库或从命令行调用 openssl (exec()
)。我知道这对你没有帮助,但似乎还没有好的解决方案。
编辑
我稍微修改了你的测试脚本并在我的 windows 7.
上测试了私钥格式<?php
$keyPair = openssl_pkey_new(array(
"digest_alg" => 'sha512',
"private_key_bits" => 4096,
"private_key_type" => OPENSSL_KEYTYPE_RSA
));
$privateKey = null;
openssl_pkey_export($keyPair, $privateKey);
echo sprintf("PHP: %s\n", phpversion());
echo sprintf("OpenSSL: %s\n", OPENSSL_VERSION_TEXT);
echo sprintf("Private key header: %s\n", current(explode("\n", $privateKey)));
PHP: 5.4.44
OpenSSL: OpenSSL 0.9.8zf 19 Mar 2015
Private key header: -----BEGIN RSA PRIVATE KEY-----
PHP: 5.5.28
OpenSSL: OpenSSL 1.0.1p 9 Jul 2015
Private key header: -----BEGIN PRIVATE KEY-----
PHP: 5.6.12
OpenSSL: OpenSSL 1.0.1p 9 Jul 2015
Private key header: -----BEGIN PRIVATE KEY-----
根据更新日志,这些结果重现了 openssl 的默认行为。
Changes between 0.9.8n and 1.0.0 [29 Mar 2010]
Make PKCS#8 the default write format for private keys, replacing the traditional format. This form is standardised, more secure and doesn't include an implicit MD5 dependency. [Steve Henson]