mirror of
https://github.com/phpseclib/phpseclib.git
synced 2024-12-30 20:59:14 +00:00
Merge branch '3.0'
This commit is contained in:
commit
7cbd239124
@ -3,6 +3,8 @@
|
|||||||
/**
|
/**
|
||||||
* PuTTY Formatted Key Handler
|
* PuTTY Formatted Key Handler
|
||||||
*
|
*
|
||||||
|
* See PuTTY's SSHPUBK.C and https://tartarus.org/~simon/putty-snapshots/htmldoc/AppendixC.html
|
||||||
|
*
|
||||||
* PHP version 5
|
* PHP version 5
|
||||||
*
|
*
|
||||||
* @category Crypt
|
* @category Crypt
|
||||||
@ -128,8 +130,14 @@ abstract class PuTTY
|
|||||||
$components = [];
|
$components = [];
|
||||||
|
|
||||||
$key = preg_split('#\r\n|\r|\n#', trim($key));
|
$key = preg_split('#\r\n|\r|\n#', trim($key));
|
||||||
$type = trim(preg_replace('#PuTTY-User-Key-File-2: (.+)#', '$1', $key[0]));
|
if (Strings::shift($key[0], strlen('PuTTY-User-Key-File-')) != 'PuTTY-User-Key-File-') {
|
||||||
$components['type'] = $type;
|
return false;
|
||||||
|
}
|
||||||
|
$version = (int) Strings::shift($key[0], 3); // should be either "2: " or "3: 0" prior to int casting
|
||||||
|
if ($version != 2 && $version != 3) {
|
||||||
|
throw new \RuntimeException('Only v2 and v3 PuTTY private keys are supported');
|
||||||
|
}
|
||||||
|
$components['type'] = $type = rtrim($key[0]);
|
||||||
if (!in_array($type, static::$types)) {
|
if (!in_array($type, static::$types)) {
|
||||||
$error = count(static::$types) == 1 ?
|
$error = count(static::$types) == 1 ?
|
||||||
'Only ' . static::$types[0] . ' keys are supported. ' :
|
'Only ' . static::$types[0] . ' keys are supported. ' :
|
||||||
@ -152,30 +160,82 @@ abstract class PuTTY
|
|||||||
|
|
||||||
$components['public'] = $public;
|
$components['public'] = $public;
|
||||||
|
|
||||||
$privateLength = trim(preg_replace('#Private-Lines: (\d+)#', '$1', $key[$publicLength + 4]));
|
switch ($version) {
|
||||||
$private = Base64::decode(implode('', array_map('trim', array_slice($key, $publicLength + 5, $privateLength))));
|
case 3:
|
||||||
|
$hashkey = '';
|
||||||
switch ($encryption) {
|
break;
|
||||||
case 'aes256-cbc':
|
case 2:
|
||||||
$symkey = self::generateSymmetricKey($password, 32);
|
$hashkey = 'putty-private-key-file-mac-key';
|
||||||
$crypto = new AES('cbc');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$hashkey = 'putty-private-key-file-mac-key';
|
$offset = $publicLength + 4;
|
||||||
|
switch ($encryption) {
|
||||||
|
case 'aes256-cbc':
|
||||||
|
$crypto = new AES('cbc');
|
||||||
|
switch ($version) {
|
||||||
|
case 3:
|
||||||
|
if (!function_exists('sodium_crypto_pwhash')) {
|
||||||
|
throw new \RuntimeException('sodium_crypto_pwhash needs to exist for Argon2 password hasing');
|
||||||
|
}
|
||||||
|
$flavour = trim(preg_replace('#Key-Derivation: (.*)#', '$1', $key[$offset++]));
|
||||||
|
switch ($flavour) {
|
||||||
|
case 'Argon2i':
|
||||||
|
$flavour = SODIUM_CRYPTO_PWHASH_ALG_ARGON2I13;
|
||||||
|
break;
|
||||||
|
case 'Argon2id':
|
||||||
|
$flavour = SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new UnsupportedAlgorithmException('Only Argon2i and Argon2id are supported');
|
||||||
|
}
|
||||||
|
$memory = trim(preg_replace('#Argon2-Memory: (\d+)#', '$1', $key[$offset++]));
|
||||||
|
$passes = trim(preg_replace('#Argon2-Passes: (\d+)#', '$1', $key[$offset++]));
|
||||||
|
$parallelism = trim(preg_replace('#Argon2-Parallelism: (\d+)#', '$1', $key[$offset++]));
|
||||||
|
$salt = pack('H*', trim(preg_replace('#Argon2-Salt: ([0-9a-f]+)#', '$1', $key[$offset++])));
|
||||||
|
|
||||||
|
$length = 80; // keylen + ivlen + mac_keylen
|
||||||
|
$temp = sodium_crypto_pwhash($length, $password, $salt, $passes, $memory << 10, $flavour);
|
||||||
|
|
||||||
|
$symkey = substr($temp, 0, 32);
|
||||||
|
$symiv = substr($temp, 32, 16);
|
||||||
|
$hashkey = substr($temp, -32);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
$symkey = '';
|
||||||
|
$sequence = 0;
|
||||||
|
while (strlen($symkey) < 32) {
|
||||||
|
$temp = pack('Na*', $sequence++, $password);
|
||||||
|
$symkey.= pack('H*', sha1($temp));
|
||||||
|
}
|
||||||
|
$symkey = substr($symkey, 0, 32);
|
||||||
|
$symiv = str_repeat("\0", $crypto->getBlockLength() >> 3);
|
||||||
|
$hashkey.= $password;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($version) {
|
||||||
|
case 3:
|
||||||
|
$hash = new Hash('sha256');
|
||||||
|
$hash->setKey($hashkey);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
$hash = new Hash('sha1');
|
||||||
|
$hash->setKey(sha1($hashkey, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
$privateLength = trim(preg_replace('#Private-Lines: (\d+)#', '$1', $key[$offset++]));
|
||||||
|
$private = Base64::decode(implode('', array_map('trim', array_slice($key, $offset, $privateLength))));
|
||||||
|
|
||||||
if ($encryption != 'none') {
|
if ($encryption != 'none') {
|
||||||
$hashkey.= $password;
|
|
||||||
$crypto->setKey($symkey);
|
$crypto->setKey($symkey);
|
||||||
$crypto->setIV(str_repeat("\0", $crypto->getBlockLength() >> 3));
|
$crypto->setIV($symiv);
|
||||||
$crypto->disablePadding();
|
$crypto->disablePadding();
|
||||||
$private = $crypto->decrypt($private);
|
$private = $crypto->decrypt($private);
|
||||||
}
|
}
|
||||||
|
|
||||||
$source.= Strings::packSSH2('s', $private);
|
$source.= Strings::packSSH2('s', $private);
|
||||||
|
|
||||||
$hash = new Hash('sha1');
|
$hmac = trim(preg_replace('#Private-MAC: (.+)#', '$1', $key[$offset + $privateLength]));
|
||||||
$hash->setKey(sha1($hashkey, true));
|
|
||||||
$hmac = trim(preg_replace('#Private-MAC: (.+)#', '$1', $key[$publicLength + $privateLength + 5]));
|
|
||||||
$hmac = Hex::decode($hmac);
|
$hmac = Hex::decode($hmac);
|
||||||
|
|
||||||
if (!hash_equals($hash->hash($source), $hmac)) {
|
if (!hash_equals($hash->hash($source), $hmac)) {
|
||||||
|
@ -1150,4 +1150,80 @@ n9dyFZYXxil/cgFG/PDMnuXy1Wcl8hb8iwQag4Y7ohiLXVTJa/0BAgMBAAE=
|
|||||||
|
|
||||||
$this->assertSame($str1, $str2);
|
$this->assertSame($str1, $str2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testPuTTYV3NoPW()
|
||||||
|
{
|
||||||
|
$key = 'PuTTY-User-Key-File-3: ssh-rsa
|
||||||
|
Encryption: none
|
||||||
|
Comment: rsa-key-20220216
|
||||||
|
Public-Lines: 6
|
||||||
|
AAAAB3NzaC1yc2EAAAADAQABAAABAQCJ39DLYw81oZmBMeRze+Plu0p8+kJezer4
|
||||||
|
mRpltRoqpZ0yRnyb5k0FtXrDeYL9IyCceOTsse/qks3CtVWQ2q7C2tqyezmk8mDf
|
||||||
|
aKXqnaSG3hHZo7vJcy76J7NNB6Mz2BxF9RGvb+sylEKdWOJdgmYC6dzyvpg/0qs6
|
||||||
|
yNPQGA5QOOzy2AstxnsujDl16I0GGsjw7ybc5844Hq4VhIQaft2Yd35UqGt5G1hs
|
||||||
|
nIZu1cLO/F+8xs+0xEY04FvJRNAoJGlVc8oPx7slU7vF5m22AmBqrhkljbid72OR
|
||||||
|
oXpI+4c7zc0dYZBIMoAEIJKTbliQE1WV0lYiXkS9RY3UjUyPLho9
|
||||||
|
Private-Lines: 14
|
||||||
|
AAABAQCI4IliEeMcpGVILOcXe2yCO1E1CCLyCc53pU/en0/t/OM18WJuR9I5k7Tf
|
||||||
|
8XeIpeIPVbo3/mMn5zydS/c5ytDrI+kwfkN5LSPdSABIDt8zAa6I+hNJaK+/q8BG
|
||||||
|
/gkZRDi1fxpiqGLAoQ4NNhvtJ7Lsu44d8/gkjJpvzsbx9Z/oJVK8ID10Wiiz9R7u
|
||||||
|
WPCOJbrETGU1LaY4N0hwhbqD28xtX4ypBh+HQ9umCqOMopeqVhebMolAZ62K5V+N
|
||||||
|
SbdN1JFk2FPQxMv3v4ApDW48AcJ1dNgO6euncaySLaQv3tnxYVjKVaf3JO0ALzoq
|
||||||
|
zsR2uj5bJUvhSapj9uWdDJTurGzFAAAAgQDY5t/F2Ruoa5wtF/XTiIxFpb//xQ+2
|
||||||
|
JhQOWd1fZZ+oMclqNS5E45E11TWnKthgr5NN4UB6TH4rtUETjsypD3w2PYZamTD1
|
||||||
|
QzeoOS0xRxjKfQu08ApDV94mx9LfX6Xi2IqTW0pC+IbBx8AUnK7J7scva8TYn7Qu
|
||||||
|
1QLSY4/tn3BBBwAAAIEAorolHJnR+w5FajTc8VeqN5E9bfc39Mr+2lQcqtARJGAM
|
||||||
|
2jLhN3ZWGIboG3Ttqcbfuicv/WzFe+gGRA8awvMS4v2C5/knZl4Vq859KCP7JOeW
|
||||||
|
63+5mLw5OKZOzWkguMu8+IfkUtIMv1JFuCU2eRL5elUthKlK6WFcMejuygNTrZsA
|
||||||
|
AACARP7yi23FNxAqHcgbx5MlrLYbMSjxp5yT+1XeNVTSpM/dvDVsy+8ETi/c1870
|
||||||
|
UfAzuIHQl2fu6NdtPBQUoqWKgBRtp46J/BoWF3Ty6klz+FAP2of4gojYvqa87H+6
|
||||||
|
dW7G8+QXxXM704cxjbBQAApItfVw3upWPrYP9FDy7xvtYRY=
|
||||||
|
Private-MAC: 7979eb6f604fb3e0bd191295479517f641598649167835402c6cbfde6cbf21ef';
|
||||||
|
|
||||||
|
$key = PublicKeyLoader::load($key);
|
||||||
|
$this->assertInstanceOf(PrivateKey::class, $key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testPuTTYV3PW()
|
||||||
|
{
|
||||||
|
if (!function_exists('sodium_crypto_pwhash')) {
|
||||||
|
self::markTestSkipped('sodium_crypto_pwhash() function is not available.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$key = 'PuTTY-User-Key-File-3: ssh-rsa
|
||||||
|
Encryption: aes256-cbc
|
||||||
|
Comment: rsa-key-20220216
|
||||||
|
Public-Lines: 6
|
||||||
|
AAAAB3NzaC1yc2EAAAADAQABAAABAQCJ39DLYw81oZmBMeRze+Plu0p8+kJezer4
|
||||||
|
mRpltRoqpZ0yRnyb5k0FtXrDeYL9IyCceOTsse/qks3CtVWQ2q7C2tqyezmk8mDf
|
||||||
|
aKXqnaSG3hHZo7vJcy76J7NNB6Mz2BxF9RGvb+sylEKdWOJdgmYC6dzyvpg/0qs6
|
||||||
|
yNPQGA5QOOzy2AstxnsujDl16I0GGsjw7ybc5844Hq4VhIQaft2Yd35UqGt5G1hs
|
||||||
|
nIZu1cLO/F+8xs+0xEY04FvJRNAoJGlVc8oPx7slU7vF5m22AmBqrhkljbid72OR
|
||||||
|
oXpI+4c7zc0dYZBIMoAEIJKTbliQE1WV0lYiXkS9RY3UjUyPLho9
|
||||||
|
Key-Derivation: Argon2id
|
||||||
|
Argon2-Memory: 8192
|
||||||
|
Argon2-Passes: 13
|
||||||
|
Argon2-Parallelism: 1
|
||||||
|
Argon2-Salt: d9bfa07d14a450a26ada4eb5d30c4dae
|
||||||
|
Private-Lines: 14
|
||||||
|
L3TUmo97jnxJVYIScxzPIaq19/yNQ5HDQKGSTz4vqUrQR3wXQEyhzxlN2mm5zZtT
|
||||||
|
pst7K61P0awtjs4kHUfsKxXh/upv7ndS9u9G7cnnBfP5mjs0wAE2VaghbP4UXprH
|
||||||
|
/MQC9Dr13Iuydv5Oih+PLpkvM3DbY5t+nrIWy/29yDLYe/QjLvy346Gz3pnLmCfb
|
||||||
|
hbEFfjefdppa+6QZ+qU6ai/NMAM/Q5OxjRlIo1brrKJNvMrbzP7irZ4+Ao2Or/hX
|
||||||
|
nb2ZZLY0eUotD8iFuOk2EjjqP9iakag1OHdvdy6EcPzkIObN5YeZGz9/hRDFr9Ml
|
||||||
|
xNxdaw5c1BhqU5pm0B0HUDqW5kmYTiugUKQiGr0+1ckliUt6jsb7YImnqJIgL7PS
|
||||||
|
vKcqNvz95u4on77gHPl2JdsXxuz6jOkDwc9jvsJCtIMJ8qhAVXGS7WaH2aF9ty7B
|
||||||
|
4E+f2yIbsRr0RFCZoTTjTmhtYsVd7DYo0Jftya3Sh/lVO1MLo1z8em0MFJdR683N
|
||||||
|
tRDA2lbRPOdKYaiKdyp5bAsl4fqPR1e2GR9ybalPn/XSFDRtDfdMr7hyQboBR7uC
|
||||||
|
X3nYsh5OiXakUSr2ST41pP27s8F48590M6xWb9LGFJA+JqmAZ5rxPTxFYjkz27y9
|
||||||
|
Yvlq6lvM+XsUREPrxhWrHya4Jyp4WtyVtJXDg626hoZBSEtcOY/mbPfwVFnoU9vz
|
||||||
|
V8TI/YU837mUceEJlEQEbT+bFJfh0W5jzAYx2xX6uPnDkodBMK2p6QS3ZKib0NJ7
|
||||||
|
W+jQr9TT40H0agZhtAmPKaLGxtgdpUps1CDPV+8Y/pBf28CsI2DjFaOYopZXcW9s
|
||||||
|
vCIjXopt4wAKbXiLyb5JXzFfB7CVron48NHB7wzuwvnUoYa/4dbjeEos+1y72xoP
|
||||||
|
Private-MAC: d26baf87446604974287b682ed9e0c00ce54e460e1cb719953a81291147b3c59
|
||||||
|
';
|
||||||
|
|
||||||
|
$key = PublicKeyLoader::load($key, 'demo');
|
||||||
|
$this->assertInstanceOf(PrivateKey::class, $key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user