phpseclib/phpseclib — pull request #49 by petrich (2013-01-12 19:01:43+00:00)
Title: DES: Fixed CFB/OFB and continuousBuffer

FIXED: multiple calls to enable/disableMode() will work now
FIXED: CFB/OFB modes
FIXED: "Illegal string offset" and strlen(array()) Warning/Notice

Example for multiple calls to enable/disableMode():
```php
ini_set('error_reporting',E_ALL);
define('CRYPT_DES_MODE',CRYPT_DES_MODE_INTERNAL); // or CRYPT_DES_MODE_MCRYPT

$des = new Crypt_DES(CRYPT_DES_MODE_CTR); // or CRYPT_DES_MODE_OFB or CRYPT_DES_MODE_CFB (similar results)
$des->enableContinuousBuffer();
$ciphertext = $des->encrypt('12345678').$des->encrypt('9');
$des->disableContinuousBuffer();

echo bin2hex($ciphertext)."\n";
echo bin2hex($des->encrypt('123456789'));
```
Output (besides the PHP Warnings/Notices):
bd947eddf487149f2f
5a72877e8f7de1b49f

Expected:
bd947eddf487149f2f
bd947eddf487149f2f

Output after bugfix:
bd947eddf487149f2f
bd947eddf487149f2f

...

Example for broken CFB:
```php
ini_set('error_reporting',E_ALL);
define('CRYPT_DES_MODE',CRYPT_DES_MODE_MCRYPT);

$des = new Crypt_DES(CRYPT_DES_MODE_CFB);
$des->enableContinuousBuffer();
$ciphertext = $des->encrypt('12345678').$des->encrypt('9');

$des = new Crypt_DES(CRYPT_DES_MODE_CFB);
echo bin2hex($ciphertext)."\n";
echo bin2hex($des->encrypt('123456789'));
```
Output:
bd947eddf487149fb5
bd947eddf487149f1a

Expected:
bd947eddf487149f1a
bd947eddf487149f1a

Output after bugfix:
bd947eddf487149f1a
bd947eddf487149f1a

...

CFB code is rewriten, it's also faster now.
Speedtest result using CFB, enableContinuousBuffer(), MODE_MCRYPT

Old code:
1000000 bytes, randomly partitionated between 1 and 1 bytes)... Time: 91.19
1000000 bytes, randomly partitionated between 8 and 8 bytes)... Time: 2.07
1000000 bytes, randomly partitionated between 8 and 9 bytes)... Time: 69.86
1000000 bytes, randomly partitionated between 1 and 10 bytes)... Time: 75.87
1000000 bytes, randomly partitionated between 1 and 50 bytes)... Time: 22.48
1000000 bytes, randomly partitionated between 1 and 100 bytes)... Time: 11.75
1000000 bytes, randomly partitionated between 1 and 200 bytes)... Time: 6.11
1000000 bytes, randomly partitionated between 1 and 300 bytes)... Time: 4.12
1000000 bytes, randomly partitionated between 1 and 400 bytes)... Time: 3.17
1000000 bytes, randomly partitionated between 1 and 500 bytes)... Time: 2.58
1000000 bytes, randomly partitionated between 1 and 600 bytes)... Time: 2.23
1000000 bytes, randomly partitionated between 1 and 700 bytes)... Time: 1.9
1000000 bytes, randomly partitionated between 1 and 800 bytes)... Time: 1.67
1000000 bytes, randomly partitionated between 1 and 900 bytes)... Time: 1.52
1000000 bytes, randomly partitionated between 1 and 1000 bytes)... Time: 1.38
1000000 bytes, randomly partitionated between 1 and 10000 bytes)... Time: 0.34
1000000 bytes, randomly partitionated between 1 and 100000 bytes)... Time: 0.23

New Code:
1000000 bytes, randomly partitionated between 1 and 1 bytes)... Time: 8.69
1000000 bytes, randomly partitionated between 8 and 8 bytes)... Time: 1.99
1000000 bytes, randomly partitionated between 8 and 9 bytes)... Time: 2.44
1000000 bytes, randomly partitionated between 1 and 10 bytes)... Time: 2.91
1000000 bytes, randomly partitionated between 1 and 50 bytes)... Time: 1.81
1000000 bytes, randomly partitionated between 1 and 100 bytes)... Time: 1.57
1000000 bytes, randomly partitionated between 1 and 200 bytes)... Time: 1.46
1000000 bytes, randomly partitionated between 1 and 300 bytes)... Time: 1.45
1000000 bytes, randomly partitionated between 1 and 400 bytes)... Time: 1.41
1000000 bytes, randomly partitionated between 1 and 500 bytes)... Time: 1.41
1000000 bytes, randomly partitionated between 1 and 600 bytes)... Time: 1.4
1000000 bytes, randomly partitionated between 1 and 700 bytes)... Time: 1.34
1000000 bytes, randomly partitionated between 1 and 800 bytes)... Time: 1.28
1000000 bytes, randomly partitionated between 1 and 900 bytes)... Time: 1.19
1000000 bytes, randomly partitionated between 1 and 1000 bytes)... Time: 1.15
1000000 bytes, randomly partitionated between 1 and 10000 bytes)... Time: 0.33
1000000 bytes, randomly partitionated between 1 and 100000 bytes)... Time: 0.22

Using this speedtestscript:
```php
$aes = new Crypt_DES(CRYPT_DES_MODE_CFB);
$aes->enableContinuousBuffer();
mt_srand(1);//fixed seed

foreach(array(array(1000000,1,1),array(1000000,8,8),array(1000000,8,9),array(1000000,1,10),array(1000000,1,50),array(1000000,1,100),array(1000000,1,200),array(1000000,1,300),array(1000000,1,400),array(1000000,1,500),array(1000000,1,600),array(1000000,1,700),array(1000000,1,800),array(1000000,1,900),array(1000000,1,1000),array(1000000,1,10000),array(1000000,1,100000)) as $k=>$v)
{
$bytes_len=$v[0];
$part_min=$v[1];
$part_max=$v[2];
for($j=0;$j<1;$j++)
{
echo str_pad($bytes_len." bytes, randomly partitionated between $part_min and $part_max bytes)... ",70);
$s=microtime(true);

for($i=0;$i<$bytes_len;)
{
$part_len=mt_rand($part_min,$part_max);
$aes->decrypt($aes->encrypt(str_repeat('a',$part_len)));
#$aes->encrypt(substr($text,$i,$part_len));
$i+=$part_len;
}

$e=microtime(true);
echo "Time: ".round($e-$s,2)."\n";
}
}
```

I think DES would be fine now... or?