phpseclib: Symmetric Key Encryption Examples and Notes

Cipher:

Encryption Mode:

Chaining:

Key Length:

Key Length:

Block Length:

Key Derivation:

<?php
include('Crypt/AESRijndaelDESTripleDESRC4.php');

$cipher = new Crypt_AESRijndaelDESTripleDESRC4(
CRYPT_DESAESRIJNDAEL_MODE_
ECBCFBOFBCTRCRYPT_DES_MODE_3CBC);
 // could use CRYPT_DES_MODE_CBC // could use CRYPT_DES_MODE_CBC or CRYPT_DES_MODE_CBC3 // could use CRYPT_RIJNDAEL_MODE_CBC // could use CRYPT_AES_MODE_CBC
$cipher->setBlockLength(160);
$cipher->setBlockLength(192);
$cipher->setBlockLength(224);
$cipher->setBlockLength(256);
// keys are null-padded to the closest valid size
// longer than the longest key and it's truncated
//$cipher->setKeyLength(128160192224256);
//$cipher->setKeyLength(128192256);
$cipher->setKey('abcdefghijklmnopqrstuvwxijklmnopijklmnopqrstuvwxqrstuvwxyz123456yz3456');
$cipher->setPassword('whatever');
// the following does the same thing:
//$cipher->setPassword('whatever', 'pbkdf2', 'sha1', 'phpseclib/salt', 1000, 128 / 8, 128192256 / 8, 128160192224256 / 8);
//$cipher->setIV('...'); // defaults to all-NULLs if not explicitely defined
$cipher->disablePadding();

$size = 10 * 1024;
$size-= 16; // make the plaintext length a multiple of the block length
$size-= 16; // make the plaintext length a multiple of the block length
$size-= 4; // make the plaintext length a multiple of the block length
$plaintext = str_repeat('a', $size);

echo $cipher->decrypt($cipher->encrypt($plaintext));

// without continuous mode the following would yield the same output as the above
// with continuous mode it's treated the same way str_repeat('a', 2 * $size) would be
$plaintext = str_repeat('a', $size);

echo $cipher->decrypt($cipher->encrypt($plaintext));
?>

A departure from mcrypt

In theory, encrypting a string using a stream cipher should yield the same results no matter how that string is partitioned out. At least when enableContinuousBuffer() has been called. This is not the case with mcrypt. The following link demonstrates how phpseclib's rewritten CFB implementation (CFB mode is one of several modes that turn block ciphers into stream ciphers) guarantees this behavior:

http://phpseclib.sourceforge.net/crypt/cfb-demo.phps

Word of caution about stream ciphers

Most stream ciphers (and block ciphers operating in a mode - like CTR, CFB and OFB - that turns them into stream ciphers) work by generating a stream of pseudorandom characters called a keystream and then XOR'ing that with the plaintext. This *effectively* makes them one-time pads which, in theory, can provide perfect secrecy. The problem with one-time pads is that they're not as versatile as one might desire. Among other things, a keystream must never be reset, lest it be possible for an attacker to recover the keystream via a known-plaintext attack. ie. $ciphertext ^ $plaintext = $key. If $key is constant (because the keystream's being reset or something) than an attacker can recover any $plaintext, but if not - if it's dynamic - then the only key that an attacker could recover is their own.

Inner Chaining vs. Outer Chaining

Inner chaining, as used by SSH1, does DES three times on the whole string. Outer chaining, as used by SSH2 and most other 3DES implementations, does DES three times on each block. Outer chaining is generally considered more secure.

Speed Comparisons

The following table compares the speed of five different pure-PHP implementations of AES (one of which is Crypt_Rijndael and one of which is Crypt_AES) when ran on 150KB of text on a 1.8GHz Pentium 4-M. The numbers listed are averaged from five different trials and are measured in seconds. phpseclib's two implementations are highlighted. All implementations can be viewed by clicking on their names.

Implementation Speed
movable-type.phps 15.6844158172
phpaes.phps 39.9537248135
phpclasses1.phps 15.0100150108
phpclasses2.phps 62.591713190079
phpseclib-aes.phps 2.03581542968752
phpseclib-rijndael.phps 2.62501101493836

As can be seen, phpseclib's implementations are the fastest. phpseclib-aes.phps is faster than phpseclib-rijndael.phps because phpseclib-rijndael.phps has to contend with multiple block sizes whereas phpseclib-aes.phps does not. Note that if mcrypt weren't explicitily disabled phpseclib would have been even faster.