0

The following code creates a public/private key pair, opens the key using openssl_pkey_get_private() function successfully and emits the key pair to the display. A previously created key is then copy and pasted back into the code. I try and open that same exact private key, which worked previously, and now it fails.

For whoever is interested, you can obtain the library at: http://phpseclib.sourceforge.net/index.html

I am using phpseclib0.3.1 downloaded yesterday from the source forge website.

What is the problem?

Here is the complete code. The echoed result is ready for a copy and replace.

<?php
    set_include_path(get_include_path() . PATH_SEPARATOR . '../libraries/phpseclib');
    include('../libraries/phpseclib/Net/SSH2.php');
    include('../libraries/phpseclib/Crypt/RSA.php');

    $rsa = new Crypt_RSA();

    //$rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS1);
    //$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);

    //define('CRYPT_RSA_EXPONENT', 65537);
    //define('CRYPT_RSA_SMALLEST_PRIME', 64); // makes it so multi-prime RSA is used
    extract($rsa->createKey()); // == $rsa->createKey(1024) where 1024 is the key size

    echo("<h1 style=\"margin: 0; padding: 0;\"><b><u>Create Keys</u></b></h1><br />");
    echo("\$privatekey2 = \"$privatekey\";<br /><br />");
    echo("\$publickey2 = \"$publickey\";<br /><br />");

    // Decrypt argument
    define("KEY_PASSPHRASE", "");
    $key = openssl_pkey_get_private($privatekey, KEY_PASSPHRASE);
    if (FALSE == $key)
    {
            echo("Failed to get the private key<br />");
            return false;
    }
    else
            echo("Successfully obtained private key.<br />");

    echo("<h1 style=\"margin: 0; padding: 15px 0px 0px 0px;\"><b><u>Read Copy and Pasted Keys</u></b></h1><br />");

    $privatekey2 = "-----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQDPyrp/i8WSh8qmGHhTMaKgZeKj9X/Qh+8PrEFa8BqUMyZs61dGN9Cl9fKUq1iz cgRZWQsMPxNTmRvO4gWjBnkr1HQRELLywpfb6ecOin3uPeGY06Kme/DSRfS9YGOxy5rmhzNaCaSG WLdOUUFnQYCKdO5KkvqJSqnFYoLMBfLzEwIDAQABAoGBAJtAd1Ow1O+Ecc7j3ZMbNMzvEwU5+kOO LPni0/nkB5fPF9ithcm7DjPRrWuTEnUQrVssgmql/gSqEvLiQR/rSEA0jtgQ6n2m87SbWNz0DTLp j9jWFHbLFgo865IfssOiiht44FKWyMhQ9/FeH9gBQ0xTbHQIl8Hf/vm59n8wi3AhAkEA6fm6POv/ P+/u0Xz170FVcFVF8HosyPCiHTesdaf3U27Z8nxpPJmybf2+ZH7eJt5HUQAMvsJB75pe7gp7Iiwc awJBAONaCV5kfgmY1xGsRaWme21o1/wxqW8tX3/8glGQ1HeehiEnQ6krlNifrmeH2sBA+BpGhBGJ SovQKZA66TNFrfkCQEQpMAwXZCCoMRZuJOcyTUWQUfOgY/OVxmRkl6Ue7XoszOlLPQ0eaVCJnzF/ lBAWqQf7z7qytKqsegM2onBuEUkCQCmlY5Pz6paNddAZ84Qdk/x9uRrMahIgiJ7kPWb9lb33vvAx xhYmEpT/4y252Bthi1Ec27JuqMYlsodmEzO+LtkCQAVoE1zVkf/pQnUMcTyEE7vDAUouRjiXZHV7 JZq0uOu4ArQFhFBZILIfB9RYbb3Mr1mh1/pt+JipwtMuQ5Nnh7g= -----END RSA PRIVATE KEY-----";
    $publickey2 = "-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDPyrp/i8WSh8qmGHhTMaKgZeKj9X/Qh+8PrEFa 8BqUMyZs61dGN9Cl9fKUq1izcgRZWQsMPxNTmRvO4gWjBnkr1HQRELLywpfb6ecOin3uPeGY06Km e/DSRfS9YGOxy5rmhzNaCaSGWLdOUUFnQYCKdO5KkvqJSqnFYoLMBfLzEwIDAQAB -----END PUBLIC KEY-----";
    echo("\$privatekey2 = \"$privatekey2\";<br /><br />");
    $key2 = openssl_pkey_get_private($privatekey2, KEY_PASSPHRASE);
    if (FALSE == $key2)
    {
            echo("Failed to get the copy and pasted key<br />");
            return false;
    }
    else
            echo("Successfully obtained private copy and pasted key.<br />");
?>

Here is a sample output. The result here serves as the input (copy and paste) for a subsequent run.

Create Keys
$privatekey2 = "-----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQDA5Ehy7A/nZ0CB+xikxods0MzID8OQfJof4nCiKAa7dEv4Z/FA5KpxVSPj+ZQj X+zdm7QLHfqOGTz6ac1eOtmBCmm1VtNh5cxRQwR00GV+PTpuaUjOghL/upcJ8RlC2UAkBMIlw+7O 3rZ+B5ykHSWF2fWyX9uk7N9Ls4LUjDLs7QIDAQABAoGAFp/wG4Kyztqeh2BzYIhkxA+tpV2r+5uR 3GGMAokdWQloC8ftVUY887Qf1JKmnIuY1dl4gcFPbTFqpJiaXQ4cCsFWMjYKcVrTZj38QaWp/ikc 4ZEuYfV6dr2FDUaQaIYlqPvCxmrc7eISHDZEvPNT9LUZcAtxzeJMTIXrbf6T9MECQQD0nH2fGglp FweVVjec/fp2coJuxiI3rtWuLP0Gy3a95d/UbSTxw+gXgVdTTSZy2FfHsTrc4J49jAbTYvVHqPj9 AkEAyd9Zep/jlbGOPIim+UTzvNJsQnJRC4jS1BsYjP/digMkNDQG/nt4R2QZVlTHXM7+abdbeXYA yW3AOPHzP8++sQJBAMJHmK7JKzhAhlFiDQGv50I0aMw6qeq3/hc8vCqtZz4kWcaKeZFcG/avUABl gmgs1GtSpIHSFVyk3rb+HfowhrECQBRFdmHG7n6YrtTLUCEV2HfslWxyuEq1OZ6M/gEirGdwe1E2 rEEfuutIVPcDWmWqb4fEHs5qmBeiCrxtJ2UQAnECQCoUFle3/XAll4sACiV5/Endd7DKCM1g6jQd rtCbvzHh/j6P3sZEGuTZcuDWYmtNVUy6E2HHfNNwztZxVEJZqW4= -----END RSA PRIVATE KEY-----";
$publickey2 = "-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDA5Ehy7A/nZ0CB+xikxods0MzID8OQfJof4nCi KAa7dEv4Z/FA5KpxVSPj+ZQjX+zdm7QLHfqOGTz6ac1eOtmBCmm1VtNh5cxRQwR00GV+PTpuaUjO ghL/upcJ8RlC2UAkBMIlw+7O3rZ+B5ykHSWF2fWyX9uk7N9Ls4LUjDLs7QIDAQAB -----END PUBLIC KEY-----";

Successfully obtained private key.

Read Copy and Pasted Keys
Failed to get the copy and pasted key

UPDATE 1: It appears that phpseclib0.3.1 does not have that change, however the change does not, at least from a copy and paste, solve the problem. I manually made the change to RSA.php (line 795-804 on v0.3.1):

$RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
                                 "Proc-Type: 4,ENCRYPTED\r\n" .
                                 "DEK-Info: DES-EDE3-CBC,$iv\r\n" .
                                 "\r\n" .
                                 chunk_split(base64_encode($des->encrypt($RSAPrivateKey)), 64) .
                                 '-----END RSA PRIVATE KEY-----';
            } else {
                $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
                                 chunk_split(base64_encode($RSAPrivateKey), 64) .
                                 '-----END RSA PRIVATE KEY-----';

UPDATE 2: I got the code to work. I am not sure if the inclusion of ", 64" above did the trick or is needed, but what did do the trick was replacing the character that looked like a space, probably was from a copy and paste job, with "\n". As soon as I did that, then voila! Probably both edits were needed.

Sarah Weinberger
  • 15,041
  • 25
  • 83
  • 130

1 Answers1

1

Are you using the latest Git version of phpseclib? I ask because a while ago there was this commit:

https://github.com/phpseclib/phpseclib/commit/e4ccaef7bf74833891386232946d2168a9e2fce2#phpseclib/Crypt/RSA.php

The commit was inspired by https://stackoverflow.com/a/13908986/569976

Community
  • 1
  • 1
  • I am using phpseclib0.3.1, which appears to be the latest. I hovered my mouse over the download phpseclib under the files tab and saw a link to the same version. That being said, you may have stumbled onto the solution. I quite literally copy and pasted the $privatekey2 from my browser into my text editor, saved, uploaded, and reran the code. The referenced link, as I now recall previously yesterday, says that pem lines must be 64 bytes long. I have one line for the entire thing, so that could be the issue. I will try it in short order. – Sarah Weinberger Mar 27 '13 at 16:59
  • See update 2 above. I needed to replace the character that looked like a space, probably was, in my copy and paste job, with a "\n" character. The inclusion of ", 64" by itself did not do the job, although the inclusion of ", 64" is probably necessary, otherwise why would the line get broken into 64-byte lengths nice and neatly. This problem was not obvious, not at all and a bug in the library. – Sarah Weinberger Mar 27 '13 at 17:19
  • 1
    I wouldn't say it's a bug in the library but more an issue with OpenSSL being excessively strict. It's excessive strictness has caused problems with OpenSSL being unable to read keys generated from other things too. And in any event this "bug" has been fixed as noted in the commit that loanpoint linked to. It was fixed three months ago. It just so happens that no release has been made since. Hence loanpoint's "the latest Git version" comment. The latest release version != latest Git version. – neubert Mar 27 '13 at 17:49