phpseclib: unable to read key error in PublicKeyLoader - phpseclib v3.0.12

  • I am using phpseclib v3.0.12 using composer.
  • PHP code is being run on a CPanel control panel managed CentOS server where RSA 2048 bit SSH keys with passphrase are generated and keys are saved in the following paths.
  • private key (/home/cccv3/.ssh/id_rsa), public key (/home/cccv3/.ssh/id_rsa.pub)
  • public key is copied to target server over putty client and while I am able to connect over ssh on putty, I get error loading the private key irrespective of private key’s absolute path or relative path when I try using key based authentication (https://phpseclib.com/docs/auth#public-key),
PHP Fatal error:  Uncaught phpseclib3\Exception\NoKeyLoadedException: Unable to read key in /home/cccv3/public_html/vendor/phpseclib/phpseclib/phpseclib/Crypt/PublicKeyLoader.php:64
Stack trace:
#0 /home/cccv3/public_html/test-ssh-sftp2.php(23): phpseclib3\Crypt\PublicKeyLoader::load(false, 'gIoNocxIp08y')
#1 {main}
  thrown in /home/cccv3/public_html/vendor/phpseclib/phpseclib/phpseclib/Crypt/PublicKeyLoader.php on line 64
include 'vendor/autoload.php';
//$key = \phpseclib3\Crypt\PublicKeyLoader::load('/home/cccv3/.ssh/id_rsa', 'gIoNocxIp08y');
//$key = \phpseclib3\Crypt\PublicKeyLoader::load('.ssh/id_rsa', 'gIoNocxIp08y');
$key = \phpseclib3\Crypt\PublicKeyLoader::load('../.ssh/id_rsa', 'gIoNocxIp08y');

$ssh = new \phpseclib3\Net\SSH2('167.71.83.55');
echo "getserveridentification: " . $ssh->getServerIdentification() . "<br>";
print_r($ssh->getServerAlgorithms());
print_r($ssh->getAlgorithmsNegotiated());

if (!$ssh->login('root', $key)) {
	exit('Login Failed');
}

echo $ssh->read('root@root:~$');
$ssh->write("ls -la\n");
echo $ssh->read('root@root:~$');
getserveridentification: SSH-2.0-OpenSSH_8.0

Array ( [kex] => Array ( [0] => curve25519-sha256 [1] => curve25519-sha256@libssh.org [2] => ecdh-sha2-nistp256 [3] => ecdh-sha2-nistp384 [4] => ecdh-sha2-nistp521 [5] => diffie-hellman-group-exchange-sha256 [6] => diffie-hellman-group14-sha256 [7] => diffie-hellman-group16-sha512 [8] => diffie-hellman-group18-sha512 [9] => diffie-hellman-group-exchange-sha1 [10] => diffie-hellman-group14-sha1 ) [hostkey] => Array ( [0] => rsa-sha2-512 [1] => rsa-sha2-256 [2] => ssh-rsa [3] => ecdsa-sha2-nistp256 [4] => ssh-ed25519 ) [client_to_server] => Array ( [crypt] => Array ( [0] => aes256-gcm@openssh.com [1] => chacha20-poly1305@openssh.com [2] => aes256-ctr [3] => aes256-cbc [4] => aes128-gcm@openssh.com [5] => aes128-ctr [6] => aes128-cbc ) [mac] => Array ( [0] => hmac-sha2-256-etm@openssh.com [1] => hmac-sha1-etm@openssh.com [2] => umac-128-etm@openssh.com [3] => hmac-sha2-512-etm@openssh.com [4] => hmac-sha2-256 [5] => hmac-sha1 [6] => umac-128@openssh.com [7] => hmac-sha2-512 ) [comp] => Array ( [0] => none [1] => zlib@openssh.com ) [lang] => Array ( [0] => ) ) [server_to_client] => Array ( [crypt] => Array ( [0] => aes256-gcm@openssh.com [1] => chacha20-poly1305@openssh.com [2] => aes256-ctr [3] => aes256-cbc [4] => aes128-gcm@openssh.com [5] => aes128-ctr [6] => aes128-cbc ) [mac] => Array ( [0] => hmac-sha2-256-etm@openssh.com [1] => hmac-sha1-etm@openssh.com [2] => umac-128-etm@openssh.com [3] => hmac-sha2-512-etm@openssh.com [4] => hmac-sha2-256 [5] => hmac-sha1 [6] => umac-128@openssh.com [7] => hmac-sha2-512 ) [comp] => Array ( [0] => none [1] => zlib@openssh.com ) [lang] => Array ( [0] => ) ) )

Array ( [kex] => curve25519-sha256 [hostkey] => ssh-ed25519 [client_to_server] => Array ( [crypt] => aes256-gcm@openssh.com [mac] => hmac-sha2-256-etm@openssh.com [comp] => none ) [server_to_client] => Array ( [crypt] => aes256-gcm@openssh.com [mac] => hmac-sha2-256-etm@openssh.com [comp] => none ) )

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 20 (9 by maintainers)

Commits related to this issue

Most upvoted comments

So one interesting thing about encrypted OpenSSH keys is that node.js can do them super fast:

https://gist.githubusercontent.com/haythemhammami/83e60a81d6066b5652bc57876947c7a3/raw/b4da272983a63687b8931aa6a5cf83524fb677ce/crawlerByTimos_node_modules_bcrypt-pbkdf_index.js

So what I’ve been mulling over is to just port that instead of trying to come up with a brand new green field implementation. If even that doesn’t yield an acceptably fast OpenSSH encrypted key I should at least be able to share a small code samples showing Javascript’s speed vs PHP’s speed. Like right now the best I can do is share one big program vs another big program and that’s not as convincing a demonstration as a small 3 line code snippet would be.

I mean, just considering the history of Javascript vs PHP it isn’t all that surprising that Javascript would be loads faster. Javascript has big money behind it. The PHP Foundation has an annual budget of $600k per https://opencollective.com/phpfoundation#category-BUDGET . Google’s V8 engine probably has whole teams of devs working on it, of which prob 25% of the devs make $500k+ a year. PHP can’t compete with that.

So is there no chance of phpseclib ever supporting ed25519 SSH key passphrases? That seems to be the most recommended key type these days and my use case requires a passphrase. I currently use RSA keys but ed25519 is theoretically faster.

Waiting 30-60s doing it with pure PHP is obviously a non-starter. I am thinking that maybe there is some 3rd party library that supports it or will in the future.

https://github.com/openssh/openssh-portable/blob/master/openbsd-compat/bcrypt_pbkdf.c

@terrafrost

I have an update, “it worked”.

While I tried using file_get_contents in one of the manually managed server setup on ubuntu/centos, I somehow replaced that code with private key path directly, as posted in the sample code in this github issue, when keys are created and code was later uploaded on this cpanel control panel managed centos server.

replaced: $key = \phpseclib3\Crypt\PublicKeyLoader::load('/home/cccv3/.ssh/id_rsa', 'gIoNocxIp08y');

with: $key = \phpseclib3\Crypt\PublicKeyLoader::load(file_get_contents('/home/cccv3/.ssh/id_rsa'), 'gIoNocxIp08y');

while commenting the key reading line of code inwhich I had copied private key content directly.

key takeaways:

  • When deploying code on manually managed servers (when server management control panel is not used), I need to check for open_basedir restrictions and deploy code inside “/home/username/public_html” kind of paths instead of other places like “/usr/share/nginx/html”
  • permissions of id_rsa: 0600 and .ssh folder: 0700 are fine by default
  • I need to ensure RSA private key has to be generated for phpseclib to use and not openssh encrypted key.

thank you

It’s possible that PHP is running as a different user (say www-data) than the user that owns the key. This would be a problem because OpenSSH won’t use the key if the permissions are too open.

A few ideas:

  • You could make the web server run with the same account you login as (probably not a good idea)
  • You could make the key hard-coded in PHP (how often does it change, anyway?)
  • You could password protect the key and put the new key in the same path as your code
  • Maybe setting up an ssh-agent would help. See https://phpseclib.com/docs/auth#ssh-agent for more info

please also confirm if SSH-keygen can be used to generate SSH authentication keypairs irrespective of operating system it is generated upon (like CentOS/Ubuntu/RHEL etc…)? or do I need to be mindful in terms of if OpenSSH related bcrypt encryption is used or not by observing the key header before trying with phpseclib library?

It depends more on the version of OpenSSH being used. Looking at the changelog’s it looks like it was OpenSSH 7.8 that introduced the change:

 * ssh-keygen(1): write OpenSSH format private keys by default
   instead of using OpenSSL's PEM format. The OpenSSH format,
   supported in OpenSSH releases since 2014 and described in the
   PROTOCOL.key file in the source distribution, offers substantially
   better protection against offline password guessing and supports
   key comments in private keys. If necessary, it is possible to write
   old PEM-style keys by adding "-m PEM" to ssh-keygen's arguments
   when generating or updating a key.

Got it - I’ll take a look later today!

-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,0142FBDB17703DC6576C4A30982EBF96

That’s not an OpenSSH formatted key. An encrypted OpenSSH key starts off with -----BEGIN OPENSSH PRIVATE KEY-----. Apologies for assuming that it was.

Private keys of the format you posted are supported.

If you can generate a private key that’ll duplicate the issue - or are willing to share that private key with me - could you do so so that I might be able to reproduce the key? You can email it to terrafrost@php.net if you want!