问题
I have an issue with creating/using RSA keys created and used in PHP. Problem is, that the (public AND private) keys should be exchanged between different servers (e.g. when a user account is moved).
Now, the openssl-lib of PHP does not provide any detailed info on in what format the keys are created. The latest documentation at http://php.net/manual/en/function.openssl-pkey-export.php just states, that it is "in PEM format", but it does not say whether it is in PKCS#1 or PKCS#8
Additionally, the headers and trailers of the private key PEM differ between PHP versions as the following code demonstrates:
<?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();
?>
will output different stuff:
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-----
"
So the private key header/trailer changes based on what PHP version you use. This wouldn't be a real problem, but as it turns out, a system which would create a key header WITH "RSA" will not be able to user key WITHOUT "RSA" for e.g., openssl_sign(): You'll get an error stating that the "provided key couldn't be coerced into a private key"... And this is where it gets messy.
According to https://tls.mbed.org/kb/cryptography/asn1-key-structures-in-der-and-pem, there should be a distinction between Private key PEM formats with the "RSA" in the header an those without, being PKCS#1 and PKCS#8, i.e. with additinal info about the algorithm etc. or not.
I am running into serious problems due to this. The same software written for PHP5.6 cannot run on PHP5.5. On could use a workaround by replacing the 5.5-headers with 5.6-compatible ones manually, but this would just be a "dirty hack". Is there a "good" way how to deal with this?
At setup, this replacement-code would attempt to create a private key, extract the header and "remember it". All keys used at runtime would then be checked. If the headers found would not fit to the "local" ones, they would need to be exchanged.
But I guess there is some kind of configuration option (which I haven't managed to find yet) where I can configure which format is used?
Next, more interesting question: What format is created exactly by openssl? PKCS#1? PKCS#8? Is this also configurable?
回答1:
No configuration (unfortunatelly). Just PHP + OpenSSL version issue. BEGIN RSA PRIVATE KEY
indicates PKCS#1 format. Without RSA
it's PKCS#8.
Generate private key RSA with PKCS1 (my older post to the same problem)
what is the differences between "BEGIN RSA PRIVATE KEY" and "BEGIN PRIVATE KEY".
You can try phpsec library or call openssl from command line (exec()
). I know it does not help you but it seems there is not good solution yet.
Edit
I altered your test script a little bit and tested private key format on my 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-----
These results reproduce default behaviour of openssl according to its changelog.
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]
来源:https://stackoverflow.com/questions/31922094/php-rsa-key-creation