Creating a PHP RSA Key

I am having trouble creating / using RSA keys created and used in PHP. The problem is that (public and private) keys must be exchanged between different servers (for example, when moving a user account).

Now, opensl-lib PHP does not provide detailed information about the format in which keys are generated. The latest documentation at http://php.net/manual/en/function.openssl-pkey-export.php says that it is in PEM format but does not say if it is in PKCS # 1 or PKCS # 8

In addition, the headers and trailers of the PEM private key are different between PHP versions, as shown in the following code:

<?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(); ?> 

outputs different things:

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

Thus, the title / trailer of the private key changes depending on which version of PHP you are using. This will not be a real problem, but as it turned out, a system that would create a key header with "RSA" would not be able to use a user key WITHOUT "RSA", for example, openssl_sign (): you will get that "the provided key cannot be forced to enter into the private key "... And here he becomes promiscuous.

According to https://tls.mbed.org/kb/cryptography/asn1-key-structures-in-der-and-pem there should be a difference between the private keys of the PEM formats with "RSA" in the header, and those PKCS # 1 and PKCS # 8, i.e. with additional information about the algorithm, etc. or not.

I am having serious problems because of this. The same software written for PHP5.6 cannot run on PHP5.5. On can use a workaround, replacing 5.5 headers with 5.6 compatible ones manually, but it will just be a dirty hack. Is there a “good” way to handle this?

When configured, this replacement code will attempt to create a private key, extract the header, and "remember it." Then all keys used at runtime will be checked. If the headers found do not match the "local" ones, they will need to be exchanged.

But I assume that there is some kind of configuration option (which I have not been able to find yet), where can I configure which format is used?

Next, a more interesting question: what format is created using openssl? PKCS # 1? PKCS # 8? Is it also customizable?

+4
source share
1 answer

No configuration (unfortunately). Just a version of PHP + OpenSSL. BEGIN RSA PRIVATE KEY specifies PKCS # 1 format. Without RSA this is PKCS # 8.

Generate RSA with private key with PKCS1 (my senior post with the same problem)

what is the difference between "BEGIN RSA PRIVATE KEY" and "START PRIVATE KEY" .

You can try the phpsec library or call openssl from the command line ( exec() ). I know that this will not help you, but there seems to be no good solution so far.

Edit

I slightly modified your test script and tested the 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 the default behavior of openssl according to its list of changes.

Changes between 0.9.8n and 1.0.0 [March 29, 2010]

Make PKCS # 8 the default private key record format, replacing the traditional format. This form is standardized, more secure, and does not include implicit MD5 dependency. [Steve Henson]

+1
source

All Articles