Skip to content

Commit c8ed87f

Browse files
authored
Merge pull request #2 from neighbourhoodie/v2-to-v3-updates
V2 to v3 updates
2 parents 6fa2490 + e6c0e48 commit c8ed87f

File tree

88 files changed

+744
-93
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

88 files changed

+744
-93
lines changed

README.md

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# phpseclib3_rector
1+
# rector_rules
22

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

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

1313
```
14-
composer require phpseclib/phpseclib3_rector:~1.0
14+
composer require phpseclib/rector_rules:~1.0
1515
```
1616

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

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

@@ -104,10 +104,10 @@ Additionally it replaces the following methods:
104104
| $rsa->getSize() | $rsa->getLength() |
105105
| $rsa->setHash('sha256'); | $rsa = $rsa->withHash('sha256') |
106106
| $rsa->setMGFHash('sha256'); | $rsa = $rsa->withMGFHash('sha256') |
107-
| $rsa->setSaltLength(10); | $rsa->withSaltLength(10) |
108-
| $rsa->setSignatureMode(RSA::SIGNATURE_PKCS1); | $rsa->withPadding(RSA::SIGNATURE_PKCS1); |
109-
| $rsa->setEncryptionMode(RSA::ENCRYPTION_PKCS1); | $rsa->withPadding(RSA::ENCYRPTION_PKCS1); |
110-
| $rsa->setEncryptionMode(RSA::ENCRYPTION_PKCS1); $rsa->setSignatureMode(RSA::SIGNATURE_PKCS1); | $rsa->withPadding(RSA::SIGNATURE_PKCS1 | RSA::ENCYRPTION_PKCS1);|
107+
| $rsa->setSaltLength(10); | $rsa = $rsa->withSaltLength(10) |
108+
| $rsa->setSignatureMode(RSA::SIGNATURE_PKCS1); | $rsa = $rsa->withPadding(RSA::SIGNATURE_PKCS1); |
109+
| $rsa->setEncryptionMode(RSA::ENCRYPTION_PKCS1); | $rsa = $rsa->withPadding(RSA::ENCYRPTION_PKCS1); |
110+
| $rsa->setEncryptionMode(RSA::ENCRYPTION_PKCS1); $rsa->setSignatureMode(RSA::SIGNATURE_PKCS1); | $rsa = $rsa->withPadding(RSA::SIGNATURE_PKCS1 | RSA::ENCYRPTION_PKCS1);|
111111

112112
### Public Key Loader Chained
113113

@@ -198,3 +198,37 @@ $sftp = new SFTP('...');
198198
$sftp->login('username', 'password');
199199
echo $sftp->filesize('/path/to/filename.ext');
200200
```
201+
202+
### Symmetric Key Constructor
203+
204+
This rule is for `v2` -> `v3` upgrade.
205+
206+
In phpseclib v2 you'd instantiate the constructor by doing stuff like this:
207+
208+
```php
209+
$cipher = new AES(AES::MODE_CTR);
210+
```
211+
212+
In phpseclib v3 that's been replaced with strings. eg.
213+
214+
```php
215+
$cipher = new AES('ctr');
216+
```
217+
218+
Also, in phpseclib v2, `$cipher = new AES()` was the same as `$cipher = new AES(AES::MODE_CBC)`.
219+
In v3 it doesn't default to cbc - the mode needs to be explicitly defined.
220+
221+
222+
This is true for all the classes that extend `\phpseclib3\Crypt\Common\BlockCipher` in v3:
223+
224+
| v2 | v3 |
225+
|---------------------------------------------------|---------------------------------------|
226+
| $default = new DES(); | $default = new DES('cbc'); |
227+
| $des = new DES(DES::MODE_CBC); | $des = new DES('cbc'); |
228+
| $rijndael = new Rijndael(Rijndael::MODE_ECB); | $rijndael = new Rijndael('ecb'); |
229+
| $tripleDES = new TripleDES(TripleDES::MODE_CTR); | $tripleDES = new TripleDES('ctr'); |
230+
| $blowfish = new Blowfish(Blowfish::MODE_CFB); | $blowfish = new Blowfish('cfb'); |
231+
| $twofish = new Twofish(Twofish::MODE_CFB8); | $twofish = new Twofish('cfb8'); |
232+
| $rc2 = new RC2(RC2::MODE_OFB); | $rc2 = new RC2('ofb'); |
233+
| $aes = new AES(AES::MODE_OFB8); | $aes = new AES('ofb8'); |
234+
| $aes2 = new AES(AES::MODE_GCM); | $aes2 = new AES('gcm'); |

composer.json

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
2-
"name": "phpseclib/phpseclib3_rector",
3-
"description": "Rector rules for upgrading from phpseclib v2 to phpseclib v3",
2+
"name": "phpseclib/rector_rules",
3+
"description": "Rector rules for upgrading from phpseclib v2 to phpseclib v3 or from phpseclib v3 to phpseclib v4",
44
"type": "rector-extension",
55
"require": {
66
"rector/rector": "^2.0.0"
@@ -11,8 +11,13 @@
1111
"license": "MIT",
1212
"autoload": {
1313
"psr-4": {
14-
"phpseclib\\phpseclib3Rector\\": "src/",
15-
"phpseclib\\phpseclib3Rector\\Tests\\": "tests/"
14+
"phpseclib\\rectorRules\\": "src/"
15+
}
16+
},
17+
"autoload-dev": {
18+
"psr-4": {
19+
"phpseclib\\rectorRules\\": "src/",
20+
"phpseclib\\rectorRules\\Tests\\": "tests/"
1621
}
1722
},
1823
"authors": [

config/v2-to-v3.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
use Rector\Config\RectorConfig;
3+
use Rector\Renaming\Rector\Name\RenameClassRector;
4+
5+
use phpseclib\rectorRules\Rector\V2toV3\CreateKey;
6+
use phpseclib\rectorRules\Rector\V2toV3\SFTPFilesize;
7+
use phpseclib\rectorRules\Rector\V2toV3\HashLength;
8+
use phpseclib\rectorRules\Rector\V2toV3\PublicKeyLoader;
9+
use phpseclib\rectorRules\Rector\V2toV3\PublicKeyLoaderChained;
10+
use phpseclib\rectorRules\Rector\V2toV3\SymmetricKeyConstructor;
11+
12+
return RectorConfig::configure()
13+
->withRules([
14+
CreateKey::class,
15+
SFTPFilesize::class,
16+
HashLength::class,
17+
PublicKeyLoader::class,
18+
PublicKeyLoaderChained::class,
19+
SymmetricKeyConstructor::class,
20+
])
21+
->withConfiguredRule(RenameClassRector::class, [
22+
'phpseclib\Crypt\RSA' => 'phpseclib3\Crypt\RSA',
23+
'phpseclib\Net\SSH2' => 'phpseclib3\Net\SSH2',
24+
'phpseclib\Net\SFTP' => 'phpseclib3\Net\SFTP',
25+
'phpseclib\Math\BigInteger' => 'phpseclib3\Math\BigInteger',
26+
'phpseclib\Crypt\Rijndael' => 'phpseclib3\Crypt\Rijndael',
27+
'phpseclib\Crypt\DES' => 'phpseclib3\Crypt\DES',
28+
'phpseclib\Crypt\TripleDES' => 'phpseclib3\Crypt\TripleDES',
29+
'phpseclib\Crypt\Blowfish' => 'phpseclib3\Crypt\Blowfish',
30+
'phpseclib\Crypt\Twofish' => 'phpseclib3\Crypt\Twofish',
31+
'phpseclib\Crypt\RC2' => 'phpseclib3\Crypt\RC2',
32+
'phpseclib\Crypt\AES' => 'phpseclib3\Crypt\AES',
33+
])
34+
->withImportNames(removeUnusedImports: true);

rector.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
declare(strict_types=1);
44

55
use Rector\Config\RectorConfig;
6-
use phpseclib\phpseclib3Rector\Set;
6+
use phpseclib\rectorRules\Set\V2toV3Set;
77

88
return RectorConfig::configure()
9-
->withSets([Set::PATH]);
9+
->withSets([V2toV3Set::PATH]);
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
declare(strict_types=1);
44

5-
namespace phpseclib\phpseclib3Rector;
5+
namespace phpseclib\rectorRules\Rector\V2toV3;
66

77
use PhpParser\Node;
88
use PhpParser\Node\Name;
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
declare(strict_types=1);
44

5-
namespace phpseclib\phpseclib3Rector;
5+
namespace phpseclib\rectorRules\Rector\V2toV3;
66

77
use Rector\Rector\AbstractRector;
88

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
declare(strict_types=1);
44

5-
namespace phpseclib\phpseclib3Rector;
5+
namespace phpseclib\rectorRules\Rector\V2toV3;
66

77
use Rector\Rector\AbstractRector;
88

@@ -13,7 +13,6 @@
1313
use PhpParser\Node\Arg;
1414
use PhpParser\Node\Stmt\Expression;
1515
use PhpParser\Node\Stmt\UseUse;
16-
use PhpParser\Node\Stmt\ClassMethod;
1716
use PhpParser\Node\Expr\Assign;
1817
use PhpParser\Node\Expr\New_;
1918
use PhpParser\Node\Expr\MethodCall;
@@ -178,20 +177,16 @@ public function refactor(Node $node): null|Node|int
178177
$expr->args
179178
);
180179

181-
if ($newMethod === 'getLength' || $newMethod === 'withSaltLength') {
182-
return $this->wrap(
183-
$newMethodCall,
184-
$node
185-
);
186-
}
187-
// In v2, Crypt/RSA.php was not immutable. In v3, it is.
188-
return $this->wrap(
189-
new Assign(
180+
// Don't make getLength a fluent method
181+
$replacement = $newMethod === 'getLength'
182+
? $newMethodCall
183+
: new Assign(
190184
new Variable($this->rsaVarName),
191185
$newMethodCall
192-
),
193-
$node
194-
);
186+
);
187+
188+
// In v2, Crypt/RSA.php was not immutable. In v3, it is.
189+
return $this->wrap($replacement, $node);
195190
}
196191

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

203198
$this->withPaddingInserted = true;
204199
return new Expression(
205-
new MethodCall(
200+
new Assign(
206201
new Variable($this->rsaVarName),
207-
new Identifier('withPadding')
202+
new MethodCall(
203+
new Variable($this->rsaVarName),
204+
new Identifier('withPadding')
205+
)
208206
)
209207
);
210208
}
@@ -216,9 +214,12 @@ public function refactor(Node $node): null|Node|int
216214

217215
$this->withPaddingInserted = true;
218216
return new Expression(
219-
new MethodCall(
217+
new Assign(
220218
new Variable($this->rsaVarName),
221-
new Identifier('withPadding')
219+
new MethodCall(
220+
new Variable($this->rsaVarName),
221+
new Identifier('withPadding')
222+
)
222223
)
223224
);
224225
}
@@ -229,11 +230,12 @@ private function findWithPaddingMethodCall(array $nodes): ?MethodCall
229230
{
230231
foreach ($nodes as $node) {
231232
if (
232-
$node instanceof Expression
233-
&& $node->expr instanceof MethodCall
234-
&& $this->isName($node->expr->name, 'withPadding')
233+
$node instanceof Expression &&
234+
$node->expr instanceof Assign
235+
&& $node->expr->expr instanceof MethodCall
236+
&& $this->isName($node->expr->expr->name, 'withPadding')
235237
) {
236-
return $node->expr;
238+
return $node->expr->expr;
237239
}
238240

239241
// Descend into nested statement lists
@@ -278,4 +280,4 @@ public function afterTraverse(array $nodes): ?array
278280
$this->signatureParam = null;
279281
return $nodes;
280282
}
281-
}
283+
}

src/PublicKeyLoaderChained.php renamed to src/Rector/V2toV3/PublicKeyLoaderChained.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
declare(strict_types=1);
44

5-
namespace phpseclib\phpseclib3Rector;
5+
namespace phpseclib\rectorRules\Rector\V2toV3;
66

77
use Rector\Rector\AbstractRector;
88

@@ -14,7 +14,6 @@
1414
use PhpParser\Node\Stmt\Expression;
1515
use PhpParser\Node\Stmt\UseUse;
1616
use PhpParser\Node\Stmt\ClassMethod;
17-
use PhpParser\Node\Stmt\Class_;
1817
use PhpParser\Node\Expr\Assign;
1918
use PhpParser\Node\Expr\New_;
2019
use PhpParser\Node\Expr\MethodCall;
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
declare(strict_types=1);
44

5-
namespace phpseclib\phpseclib3Rector;
5+
namespace phpseclib\rectorRules\Rector\V2toV3;
66

77
use Rector\Rector\AbstractRector;
88

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace phpseclib\rectorRules\Rector\V2toV3;
6+
7+
use PhpParser\Node;
8+
use PhpParser\Node\Name;
9+
use PhpParser\Node\Arg;
10+
use PhpParser\Node\Expr\New_;
11+
use PhpParser\Node\Expr\ClassConstFetch;
12+
use PhpParser\Node\Scalar\String_;
13+
use PhpParser\Node\Stmt\UseUse;
14+
15+
use Rector\Rector\AbstractRector;
16+
17+
final class SymmetricKeyConstructor extends AbstractRector {
18+
19+
private $hasBlockCipherImport = false;
20+
private const BLOCK_CIPHER_IMPORTS = [
21+
'phpseclib\Crypt\Rijndael',
22+
'phpseclib\Crypt\DES',
23+
'phpseclib\Crypt\TripleDES',
24+
'phpseclib\Crypt\Blowfish',
25+
'phpseclib\Crypt\Twofish',
26+
'phpseclib\Crypt\RC2',
27+
'phpseclib\Crypt\AES',
28+
];
29+
private const MODE_MAP = [
30+
'MODE_ECB' => 'ecb',
31+
'MODE_CBC' => 'cbc',
32+
'MODE_CTR' => 'ctr',
33+
'MODE_CFB' => 'cfb',
34+
'MODE_CFB8' => 'cfb8',
35+
'MODE_OFB' => 'ofb',
36+
'MODE_OFB8' => 'ofb8',
37+
'MODE_GCM' => 'gcm',
38+
];
39+
40+
public function getNodeTypes(): array {
41+
return [
42+
UseUse::class,
43+
New_::class,
44+
];
45+
}
46+
47+
public function refactor(Node $node): ?Node {
48+
// apply for all the classes that extend \phpseclib3\Crypt\Common\BlockCipher in v3
49+
if ($node instanceof UseUse) {
50+
foreach (self::BLOCK_CIPHER_IMPORTS as $class) {
51+
if ($this->isName($node->name, $class)) {
52+
$this->hasBlockCipherImport = true;
53+
break;
54+
}
55+
}
56+
return null;
57+
}
58+
59+
if (!$this->hasBlockCipherImport) {
60+
return null;
61+
}
62+
63+
if (! $node instanceof New_) {
64+
return null;
65+
}
66+
if (! $node->class instanceof Name) {
67+
return null;
68+
}
69+
70+
// Add the default mode when there are no args
71+
if (empty($node->args)) {
72+
$node->args[0] = new Arg(new String_('cbc'));
73+
return $node;
74+
}
75+
$firstArg = $node->args[0]->value;
76+
77+
// Only handle constants like AES::MODE_*
78+
if (!$firstArg instanceof ClassConstFetch) {
79+
return null;
80+
}
81+
82+
$constClass = $this->getName($firstArg->class);
83+
if ($constClass === null) {
84+
return null;
85+
}
86+
if (! in_array($constClass, self::BLOCK_CIPHER_IMPORTS, true)) {
87+
return null;
88+
}
89+
90+
$modeName = $this->getName($firstArg->name);
91+
92+
if (!isset(self::MODE_MAP[$modeName])) {
93+
return null;
94+
}
95+
96+
$node->args[0] = new Arg(new String_(self::MODE_MAP[$modeName]));
97+
98+
return $node;
99+
}
100+
}

0 commit comments

Comments
 (0)