Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 42 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# phpseclib3_rector
# rector_rules

Rector rules to upgrade a phpseclib v2.0 install to phpseclib v3.0

Expand All @@ -11,7 +11,7 @@ You can use [phpseclib2_compat](https://github.com/phpseclib/phpseclib2_compat)
With [Composer](https://getcomposer.org/):

```
composer require phpseclib/phpseclib3_rector:~1.0
composer require phpseclib/rector_rules:~1.0
```

## Usage
Expand All @@ -21,10 +21,10 @@ Create a rector.php file with the following contents:
```php
<?php
use Rector\Config\RectorConfig;
use phpseclib\phpseclib3Rector\Set;
use phpseclib\rectorRules\Set\V2toV3Set;

return RectorConfig::configure()
->withSets([Set::PATH]);
->withSets([V2toV3Set::PATH]);
```
In the same directory where you created that file you can then run Rector by doing either of these commands:

Expand Down Expand Up @@ -104,10 +104,10 @@ Additionally it replaces the following methods:
| $rsa->getSize() | $rsa->getLength() |
| $rsa->setHash('sha256'); | $rsa = $rsa->withHash('sha256') |
| $rsa->setMGFHash('sha256'); | $rsa = $rsa->withMGFHash('sha256') |
| $rsa->setSaltLength(10); | $rsa->withSaltLength(10) |
| $rsa->setSignatureMode(RSA::SIGNATURE_PKCS1); | $rsa->withPadding(RSA::SIGNATURE_PKCS1); |
| $rsa->setEncryptionMode(RSA::ENCRYPTION_PKCS1); | $rsa->withPadding(RSA::ENCYRPTION_PKCS1); |
| $rsa->setEncryptionMode(RSA::ENCRYPTION_PKCS1); $rsa->setSignatureMode(RSA::SIGNATURE_PKCS1); | $rsa->withPadding(RSA::SIGNATURE_PKCS1 | RSA::ENCYRPTION_PKCS1);|
| $rsa->setSaltLength(10); | $rsa = $rsa->withSaltLength(10) |
| $rsa->setSignatureMode(RSA::SIGNATURE_PKCS1); | $rsa = $rsa->withPadding(RSA::SIGNATURE_PKCS1); |
| $rsa->setEncryptionMode(RSA::ENCRYPTION_PKCS1); | $rsa = $rsa->withPadding(RSA::ENCYRPTION_PKCS1); |
| $rsa->setEncryptionMode(RSA::ENCRYPTION_PKCS1); $rsa->setSignatureMode(RSA::SIGNATURE_PKCS1); | $rsa = $rsa->withPadding(RSA::SIGNATURE_PKCS1 | RSA::ENCYRPTION_PKCS1);|

### Public Key Loader Chained

Expand Down Expand Up @@ -198,3 +198,37 @@ $sftp = new SFTP('...');
$sftp->login('username', 'password');
echo $sftp->filesize('/path/to/filename.ext');
```

### Symmetric Key Constructor

This rule is for `v2` -> `v3` upgrade.

In phpseclib v2 you'd instantiate the constructor by doing stuff like this:

```php
$cipher = new AES(AES::MODE_CTR);
```

In phpseclib v3 that's been replaced with strings. eg.

```php
$cipher = new AES('ctr');
```

Also, in phpseclib v2, `$cipher = new AES()` was the same as `$cipher = new AES(AES::MODE_CBC)`.
In v3 it doesn't default to cbc - the mode needs to be explicitly defined.


This is true for all the classes that extend `\phpseclib3\Crypt\Common\BlockCipher` in v3:

| v2 | v3 |
|---------------------------------------------------|---------------------------------------|
| $default = new DES(); | $default = new DES('cbc'); |
| $des = new DES(DES::MODE_CBC); | $des = new DES('cbc'); |
| $rijndael = new Rijndael(Rijndael::MODE_ECB); | $rijndael = new Rijndael('ecb'); |
| $tripleDES = new TripleDES(TripleDES::MODE_CTR); | $tripleDES = new TripleDES('ctr'); |
| $blowfish = new Blowfish(Blowfish::MODE_CFB); | $blowfish = new Blowfish('cfb'); |
| $twofish = new Twofish(Twofish::MODE_CFB8); | $twofish = new Twofish('cfb8'); |
| $rc2 = new RC2(RC2::MODE_OFB); | $rc2 = new RC2('ofb'); |
| $aes = new AES(AES::MODE_OFB8); | $aes = new AES('ofb8'); |
| $aes2 = new AES(AES::MODE_GCM); | $aes2 = new AES('gcm'); |
13 changes: 9 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "phpseclib/phpseclib3_rector",
"description": "Rector rules for upgrading from phpseclib v2 to phpseclib v3",
"name": "phpseclib/rector_rules",
"description": "Rector rules for upgrading from phpseclib v2 to phpseclib v3 or from phpseclib v3 to phpseclib v4",
"type": "rector-extension",
"require": {
"rector/rector": "^2.0.0"
Expand All @@ -11,8 +11,13 @@
"license": "MIT",
"autoload": {
"psr-4": {
"phpseclib\\phpseclib3Rector\\": "src/",
"phpseclib\\phpseclib3Rector\\Tests\\": "tests/"
"phpseclib\\rectorRules\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"phpseclib\\rectorRules\\": "src/",
"phpseclib\\rectorRules\\Tests\\": "tests/"
}
},
"authors": [
Expand Down
34 changes: 34 additions & 0 deletions config/v2-to-v3.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php
use Rector\Config\RectorConfig;
use Rector\Renaming\Rector\Name\RenameClassRector;

use phpseclib\rectorRules\Rector\V2toV3\CreateKey;
use phpseclib\rectorRules\Rector\V2toV3\SFTPFilesize;
use phpseclib\rectorRules\Rector\V2toV3\HashLength;
use phpseclib\rectorRules\Rector\V2toV3\PublicKeyLoader;
use phpseclib\rectorRules\Rector\V2toV3\PublicKeyLoaderChained;
use phpseclib\rectorRules\Rector\V2toV3\SymmetricKeyConstructor;

return RectorConfig::configure()
->withRules([
CreateKey::class,
SFTPFilesize::class,
HashLength::class,
PublicKeyLoader::class,
PublicKeyLoaderChained::class,
SymmetricKeyConstructor::class,
])
->withConfiguredRule(RenameClassRector::class, [
'phpseclib\Crypt\RSA' => 'phpseclib3\Crypt\RSA',
'phpseclib\Net\SSH2' => 'phpseclib3\Net\SSH2',
'phpseclib\Net\SFTP' => 'phpseclib3\Net\SFTP',
'phpseclib\Math\BigInteger' => 'phpseclib3\Math\BigInteger',
'phpseclib\Crypt\Rijndael' => 'phpseclib3\Crypt\Rijndael',
'phpseclib\Crypt\DES' => 'phpseclib3\Crypt\DES',
'phpseclib\Crypt\TripleDES' => 'phpseclib3\Crypt\TripleDES',
'phpseclib\Crypt\Blowfish' => 'phpseclib3\Crypt\Blowfish',
'phpseclib\Crypt\Twofish' => 'phpseclib3\Crypt\Twofish',
'phpseclib\Crypt\RC2' => 'phpseclib3\Crypt\RC2',
'phpseclib\Crypt\AES' => 'phpseclib3\Crypt\AES',
])
->withImportNames(removeUnusedImports: true);
4 changes: 2 additions & 2 deletions rector.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
declare(strict_types=1);

use Rector\Config\RectorConfig;
use phpseclib\phpseclib3Rector\Set;
use phpseclib\rectorRules\Set\V2toV3Set;

return RectorConfig::configure()
->withSets([Set::PATH]);
->withSets([V2toV3Set::PATH]);
2 changes: 1 addition & 1 deletion src/CreateKey.php → src/Rector/V2toV3/CreateKey.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

declare(strict_types=1);

namespace phpseclib\phpseclib3Rector;
namespace phpseclib\rectorRules\Rector\V2toV3;

use PhpParser\Node;
use PhpParser\Node\Name;
Expand Down
2 changes: 1 addition & 1 deletion src/HashLength.php → src/Rector/V2toV3/HashLength.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

declare(strict_types=1);

namespace phpseclib\phpseclib3Rector;
namespace phpseclib\rectorRules\Rector\V2toV3;

use Rector\Rector\AbstractRector;

Expand Down
48 changes: 25 additions & 23 deletions src/PublicKeyLoader.php → src/Rector/V2toV3/PublicKeyLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

declare(strict_types=1);

namespace phpseclib\phpseclib3Rector;
namespace phpseclib\rectorRules\Rector\V2toV3;

use Rector\Rector\AbstractRector;

Expand All @@ -13,7 +13,6 @@
use PhpParser\Node\Arg;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\UseUse;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Expr\MethodCall;
Expand Down Expand Up @@ -178,20 +177,16 @@ public function refactor(Node $node): null|Node|int
$expr->args
);

if ($newMethod === 'getLength' || $newMethod === 'withSaltLength') {
return $this->wrap(
$newMethodCall,
$node
);
}
// In v2, Crypt/RSA.php was not immutable. In v3, it is.
return $this->wrap(
new Assign(
// Don't make getLength a fluent method
$replacement = $newMethod === 'getLength'
? $newMethodCall
: new Assign(
new Variable($this->rsaVarName),
$newMethodCall
),
$node
);
);

// In v2, Crypt/RSA.php was not immutable. In v3, it is.
return $this->wrap($replacement, $node);
}

if ($this->isName($expr->name, 'setEncryptionMode')) {
Expand All @@ -202,9 +197,12 @@ public function refactor(Node $node): null|Node|int

$this->withPaddingInserted = true;
return new Expression(
new MethodCall(
new Assign(
new Variable($this->rsaVarName),
new Identifier('withPadding')
new MethodCall(
new Variable($this->rsaVarName),
new Identifier('withPadding')
)
)
);
}
Expand All @@ -216,9 +214,12 @@ public function refactor(Node $node): null|Node|int

$this->withPaddingInserted = true;
return new Expression(
new MethodCall(
new Assign(
new Variable($this->rsaVarName),
new Identifier('withPadding')
new MethodCall(
new Variable($this->rsaVarName),
new Identifier('withPadding')
)
)
);
}
Expand All @@ -229,11 +230,12 @@ private function findWithPaddingMethodCall(array $nodes): ?MethodCall
{
foreach ($nodes as $node) {
if (
$node instanceof Expression
&& $node->expr instanceof MethodCall
&& $this->isName($node->expr->name, 'withPadding')
$node instanceof Expression &&
$node->expr instanceof Assign
&& $node->expr->expr instanceof MethodCall
&& $this->isName($node->expr->expr->name, 'withPadding')
) {
return $node->expr;
return $node->expr->expr;
}

// Descend into nested statement lists
Expand Down Expand Up @@ -278,4 +280,4 @@ public function afterTraverse(array $nodes): ?array
$this->signatureParam = null;
return $nodes;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

declare(strict_types=1);

namespace phpseclib\phpseclib3Rector;
namespace phpseclib\rectorRules\Rector\V2toV3;

use Rector\Rector\AbstractRector;

Expand All @@ -14,7 +14,6 @@
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\UseUse;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Expr\MethodCall;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

declare(strict_types=1);

namespace phpseclib\phpseclib3Rector;
namespace phpseclib\rectorRules\Rector\V2toV3;

use Rector\Rector\AbstractRector;

Expand Down
100 changes: 100 additions & 0 deletions src/Rector/V2toV3/SymmetricKeyConstructor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<?php

declare(strict_types=1);

namespace phpseclib\rectorRules\Rector\V2toV3;

use PhpParser\Node;
use PhpParser\Node\Name;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\UseUse;

use Rector\Rector\AbstractRector;

final class SymmetricKeyConstructor extends AbstractRector {

private $hasBlockCipherImport = false;
private const BLOCK_CIPHER_IMPORTS = [
'phpseclib\Crypt\Rijndael',
'phpseclib\Crypt\DES',
'phpseclib\Crypt\TripleDES',
'phpseclib\Crypt\Blowfish',
'phpseclib\Crypt\Twofish',
'phpseclib\Crypt\RC2',
'phpseclib\Crypt\AES',
];
private const MODE_MAP = [
'MODE_ECB' => 'ecb',
'MODE_CBC' => 'cbc',
'MODE_CTR' => 'ctr',
'MODE_CFB' => 'cfb',
'MODE_CFB8' => 'cfb8',
'MODE_OFB' => 'ofb',
'MODE_OFB8' => 'ofb8',
'MODE_GCM' => 'gcm',
];

public function getNodeTypes(): array {
return [
UseUse::class,
New_::class,
];
}

public function refactor(Node $node): ?Node {
// apply for all the classes that extend \phpseclib3\Crypt\Common\BlockCipher in v3
if ($node instanceof UseUse) {
foreach (self::BLOCK_CIPHER_IMPORTS as $class) {
if ($this->isName($node->name, $class)) {
$this->hasBlockCipherImport = true;
break;
}
}
return null;
}

if (!$this->hasBlockCipherImport) {
return null;
}

if (! $node instanceof New_) {
return null;
}
if (! $node->class instanceof Name) {
return null;
}

// Add the default mode when there are no args
if (empty($node->args)) {
$node->args[0] = new Arg(new String_('cbc'));
return $node;
}
$firstArg = $node->args[0]->value;

// Only handle constants like AES::MODE_*
if (!$firstArg instanceof ClassConstFetch) {
return null;
}

$constClass = $this->getName($firstArg->class);
if ($constClass === null) {
return null;
}
if (! in_array($constClass, self::BLOCK_CIPHER_IMPORTS, true)) {
return null;
}

$modeName = $this->getName($firstArg->name);

if (!isset(self::MODE_MAP[$modeName])) {
return null;
}

$node->args[0] = new Arg(new String_(self::MODE_MAP[$modeName]));

return $node;
}
}
Loading