Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP RSA key creation

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?

like image 792
Xenonite Avatar asked Aug 10 '15 14:08

Xenonite


People also ask

What is RSA key generator?

Online RSA Encryption, Decryption And Key Generator Tool(Free) RSA(Rivest-Shamir-Adleman) is an Asymmetric encryption technique that uses two different keys as public and private keys to perform the encryption and decryption.

What is RSA key format?

RSA key is a private key based on RSA algorithm. Private Key is used for authentication and a symmetric key exchange during establishment of an SSL/TLS session. It is a part of the public key infrastructure that is generally used in case of SSL certificates.


1 Answers

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]

like image 143
kba Avatar answered Oct 28 '22 06:10

kba