Chapter 3. Cryptography

Table of Contents

3.1. Introduction
3.1.1. Dependencies
3.1.2. setKey() and setIV()
3.1.3. setMCrypt()
3.1.4. encrypt() and decrypt()
3.1.5. enableContinuousBuffer() and disableContinuousBuffer()
3.1.6. enablePadding() and disablePadding()
3.2. Crypt_DES
3.2.1. The constructor
3.3. Crypt_TripleDES
3.3.1. The constructor
3.4. Crypt_RC4
3.4.1. The constructor
3.5. Crypt_Rijndael & Crypt_AES
3.5.1. The constructor
3.5.2. AES vs. Rijndael
3.5.3. setKeyLength()
3.5.4. setBlockLength()
3.5.5. Speed Comparisons

3.1. Introduction

All of the cryptographic libraries included in phpseclib use mcrypt, if available, and an internal implementation if it's not. The libraries all use a common interface although some functions, for some algorithms, carry with with them certain caveats. Those that do not have caveats attached (or have relatively few attached) are described below. If you don't know which one to use, try Crypt_TripleDES.

3.1.1. Dependencies

The Crypt_* functions require, minimally, PHP 4.0.0. Crypt_TripleDES additionally requires Crypt/DES.php.

3.1.2. setKey() and setIV()

Sets the key and the initialization vector, respectively. If neither are set, each assumed to be equal to some amount of null bytes. The initialization vector is only used in block ciphers and even then only in CBC mode. If the key or the initialization vector are larger then the block size, they're truncated. If they're smaller, they're padded with null bytes.

3.1.3. setMCrypt()

See php.net's entry on mcrypt_module_open. The first parameter is equal to $algorithm_directory and the second, to $mode_directory.

3.1.4. encrypt() and decrypt()

Self-explanatory. Encrypts or decrypts messages. See the examples in the subsequent sections.

3.1.5. enableContinuousBuffer() and disableContinuousBuffer()

Say you have a 16-byte plaintext $plaintext and that you're using Crypt_DES. Using the default behavior, the two following code snippets will yield different outputs:

    echo $des->encrypt(substr($plaintext, 0, 8));
    echo $des->encrypt(substr($plaintext, 8, 8));
    echo $des->encrypt($plaintext);

The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates another, as demonstrated with the following:

    $des->encrypt(substr($plaintext, 0, 8));
    echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
    echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));

With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different outputs. The reason is due to the fact that the initialization vector's change after every encryption / decryption round when the continuous buffer is enabled. When it's disabled, they remain constant. Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them), however, they are also less intuitive and more likely to cause you problems.

3.1.6. enablePadding() and disablePadding()

Enables / disables PKCS padding on block ciphers. Stream ciphers (Crypt_RC4 is the only stream cipher currently included) ignore this.

3.2. Crypt_DES

Implements DES (a block cipher). Here's an example of how to use it:

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

    $des = new Crypt_DES();

    $des->setKey('abcdefgh');

    $size = 10 * 1024;
    $plaintext = '';
    for ($i = 0; $i < $size; $i++) {
        $plaintext.= 'a';
    }

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

3.2.1. The constructor

The constructor takes one optional parameter - $mode. $mode can be equal to CRYPT_DES_MODE_ECB or CRYPT_DES_MODE_CBC. CRYPT_DES_MODE_CBC is generally considered more secure and is what Crypt_DES uses by default. If you don't know the difference between ECB or CBC, just use the default settings.

3.3. Crypt_TripleDES

Implements TripleDES (a block cipher). Here's an example of how to use it:

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

    $des = new Crypt_TripleDES();

    $des->setKey('abcdefghijklmnopqrstuvwx');

    $size = 10 * 1024;
    $plaintext = '';
    for ($i = 0; $i < $size; $i++) {
        $plaintext.= 'a';
    }

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

3.3.1. The constructor

The constructor takes one optional parameter - $mode. $mode can be equal to CRYPT_DES_MODE_ECB, CRYPT_DES_MODE_CBC, CRYPT_DES_MODE_3CBC, or CRYPT_DES_MODE_CBC3. CRYPT_DES_MODE_CBC3 is an alias CRYPT_DES_MODE_CBC. It's defined to distinguish it from CRYPT_DES_MODE_3CBC, which uses inner chaining to propogate the initialization vector. SSH-1 uses this and it is generally considered to be less secure then CRYPT_DES_MODE_CBC3, which uses outer chaining (and is what SSH-2 uses).

3.4. Crypt_RC4

Implements RC4 (a stream cipher). Here's an example of how to use it:

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

    $rc4 = new Crypt_RC4();

    $rc4->setKey('abcdefghijklmnopqrstuvwx');

    $size = 10 * 1024;
    $plaintext = '';
    for ($i = 0; $i < $size; $i++) {
        $plaintext.= 'a';
    }

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

3.4.1. The constructor

Not much to say about this constructor. Since it's a stream cipher, you don't need to worry about which mode of operation to use.

3.5. Crypt_Rijndael & Crypt_AES

Implements Rijndael / AES. Here's an example of how to use Crypt_AES:

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

    $aes = new Crypt_AES();

    $aes->setKey('abcdefghijklmnop');

    $size = 10 * 1024;
    $plaintext = '';
    for ($i = 0; $i < $size; $i++) {
        $plaintext.= 'a';
    }

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

3.5.1. The constructor

Crypt_AES's constructor takes CRYPT_AES_MODE_ECB and CRYPT_AES_MODE_CBC as parameters. Crypt_Rijndael, CRYPT_RIJNDAEL_MODE_ECB and CRYPT_RIJNDAEL_MODE_CBC. In both cases, if no valid mode is defined, CBC will be used.

3.5.2. AES vs. Rijndael

AES is a subset of Rijndael. Both have variable key sizes, however, AES's block size is fixed at 128 bytes, whereas Rijndael's is variable. Also, Rijndael supports, by means of an extension to the specification, two key sizes that AES does not - 160 bits and 224 bits.

3.5.3. setKeyLength()

Valid key lengths for AES are 128 bits, 192 bits, and 256 bits. If the key that is assigned is invalid and less than 256 bits, they key length is rounded up to the next closest valid size and the key will be null padded to that amount. If the key length is greater than 256 bits, it will be truncated to 256 bits.

As an example, if the key is 136 bits, it will be null padded to 192 bits (or 160 bits if Rijndael is being used).

If setKeyLength() has been called, this behavior changes somewhat. Say you've set the key length, via this function, to 256 bits. Then, instead of an invalid key being null padded to 192 or 160 bits, it will be null padded to 256 bits.

3.5.4. setBlockLength()

setBlockLength() operates in a manner similar to setKeyLength(), with one exception. setBlockLength() only works on Rijndael. Although Crypt_AES inherits setBlockLength() as a function, the function doesn't do anything in AES.

3.5.5. 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.

Table 3.1. AES Speed Comparisons

movable-type.phpsphpaes.phpsphpclasses1.phpsphpclasses2.phpsphpseclib-aes.phpsphpseclib-rijndael.phps
15.684415817239.953724813515.010015010862.5917131900793.57283110815.24388728142

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.