PHP RSA密钥创建


PHP RSA key creation

我有一个问题,创建/使用在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();
?>

将输出不同的内容:

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-----
"

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,私钥PEM格式在报头中有"RSA"和没有"RSA"的格式之间应该有区别,即pkcs# 1和pkcs# 8,即是否有关于算法等的附加信息。

因此我遇到了严重的问题。为PHP5.6编写的相同软件不能在PHP5.5上运行。我可以使用一个变通方法,用5.6兼容的手工替换5.5头,但这只是一个"肮脏的hack"。有没有一个"好"的方法来处理这个问题?

在设置时,这个替换代码将尝试创建一个私钥,提取标题并"记住它"。然后将检查运行时使用的所有键。如果找到的标头不适合"本地"标头,则需要交换它们。

但我猜有某种配置选项(我还没有设法找到)在哪里我可以配置使用哪种格式?

下一个更有趣的问题:openssl到底创建了什么格式?PKCS # 1 ?PKCS # 8 ?这也是可配置的吗?

没有配置(很遗憾)。只是PHP + OpenSSL版本问题。BEGIN RSA PRIVATE KEY表示pkcs# 1格式。没有RSA,它是pkcs# 8。

生成私钥RSA与PKCS1(我以前的帖子相同的问题)

"BEGIN RSA PRIVATE KEY"and "BEGIN PRIVATE KEY"

您可以尝试phpsec库或从命令行(exec())调用openssl。我知道这对你没有帮助,但似乎还没有好的解决办法。

编辑

我改变了你的测试脚本一点点和测试私钥格式在我的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的变更日志重现openssl的默认行为。

0.9.8n和1.0.0的变化[29 Mar 2010]

将pkcs# 8作为私钥的默认写格式,取代传统的格式。这种形式是标准化的,更安全,而且不会包含隐式MD5依赖项。(史蒂夫·亨森)