Oct 14th

0

AES wrapper class with pure php and MCrypt extension support

4 years 9 months ago comment No Comments

The code below is a wrapper class around the AES-128 implementation at http://www.phpclasses.org/browse/package/3650.html and the MCrypt extension. It use the MCrypt extension if it is enabled and use the pure PHP AES-128 class otherwise.

function hex2bin($hex) {

	return pack ( "H*", $hex );

}

class Cipher {

	public $password;

	public $plainText;

	public $encryptedText;

	public $iv;

	public $mode;

	const AES_128_ECB = "AES_128_ECB";

	const AES_128_CBC = "AES_128_CBC";

	public function __construct() {

		$this->mode = self::AES_128_ECB;

	}

	public function encrypt($useSuppliedIV = false) {

		if (!$this->plainText) {
			return "";
		}

		switch ($this->mode) {

			case self::AES_128_ECB :
			case self::AES_128_CBC :
				if (strlen($this->password) > 16) {
					$this->password = substr($this->password, 0, 16);
				}
				break;

		}

		if (function_exists ( "mcrypt_module_open" ) && function_exists ( "mcrypt_create_iv" ) && function_exists ( "mcrypt_generic_init" ) && function_exists ( "mcrypt_generic" ) && function_exists ( "mcrypt_generic_deinit" )) {

			switch ($this->mode) {

				case self::AES_128_ECB :
					$td = mcrypt_module_open ( 'rijndael-128', '', 'ecb', '' );
					break;

				case self::AES_128_CBC :
					$td = mcrypt_module_open ( 'rijndael-128', '', 'cbc', '' );
					break;

			}

			if ($useSuppliedIV) {
				if (strlen ( $this->iv ) != mcrypt_enc_get_iv_size ( $td )) {
					return null;
				}
			} else {
				$this->iv = mcrypt_create_iv ( mcrypt_enc_get_iv_size ( $td ), MCRYPT_RAND );
			}

			mcrypt_generic_init ( $td, $this->password, $this->iv );
			$this->encryptedText = mcrypt_generic ( $td, $this->plainText );
			mcrypt_generic_deinit ( $td );

		} else {

			$aes = new AES128 ( );
			$key = $aes->makeKey ( $this->password );

			$plainTextArray = str_split ( $this->plainText, 16 );

			$lastIndex = count($plainTextArray) - 1;
			if (strlen($plainTextArray[$lastIndex]) != 16) {

				for ($i = strlen($plainTextArray[$lastIndex]); $i < 16; $i++) {
					$plainTextArray[$lastIndex] .= chr (0);
				}

			}

			$this->encryptedText = "";

			if ($useSuppliedIV) {
				if (strlen ( $this->iv ) != 16) {
					return null;
				}
			} else {
				$this->iv = "";
				for ($i = 0; $i < 16; $i++) {
					$this->iv .= chr (rand(0, 255));
				}
			}

			switch ($this->mode) {

				case self::AES_128_ECB :

					for($i = 0; $i < count ( $plainTextArray ); $i ++) {
						$this->encryptedText .= $aes->blockEncrypt ( $plainTextArray [$i], $key );
					}

					break;

				case self::AES_128_CBC :
					$encryptedTextArray = array();
					for ($i = 0; $i < count ( $plainTextArray ); $i ++) {
						if ($i == 0) {
							$input = $this->iv ^ $plainTextArray[$i];
						} else {
							$input = $encryptedTextArray[$i - 1] ^ $plainTextArray[$i];
						}

						$encryptedTextArray[$i] = $aes->blockEncrypt ( $input, $key );
					}

					$this->encryptedText = join("", $encryptedTextArray);

					break;
			}
		}

	}

	public function decrypt() {
		if (!$this->encryptedText) {
			return "";
		}

		if (function_exists ( "mcrypt_module_open" ) && function_exists ( "mcrypt_create_iv" ) && function_exists ( "mcrypt_enc_get_iv_size" ) && function_exists ( "mcrypt_generic_init" ) && function_exists ( "mcrypt_generic" ) && function_exists ( "mcrypt_generic_deinit" )) {

			switch ($this->mode) {

				case self::AES_128_ECB :
					$td = mcrypt_module_open ( 'rijndael-128', '', 'ecb', '' );
					$this->iv = mcrypt_create_iv ( mcrypt_enc_get_iv_size ( $td ), MCRYPT_RAND );
					break;

				case self::AES_128_CBC :
					$td = mcrypt_module_open ( 'rijndael-128', '', 'cbc', '' );
					if (strlen ( $this->iv ) != mcrypt_enc_get_iv_size ( $td )) {
						return null;
					}
					break;

			}

			mcrypt_generic_init ( $td, $this->password, $this->iv );
			$this->plainText = mdecrypt_generic ( $td, $this->encryptedText );
			mcrypt_generic_deinit ( $td );

		} else {

			$aes = new AES128 ( );
			$key = $aes->makeKey ( $this->password );

			$encryptedTextArray = str_split ( bin2hex ( $this->encryptedText ), 32 );

			$this->plainText = "";

			switch ($this->mode) {

				case self::AES_128_ECB :
					for($i = 0; $i < count ( $encryptedTextArray ); $i ++) {
						$this->plainText .= $aes->blockDecrypt ( hex2bin ( $encryptedTextArray [$i] ), $key );
					}
					break;

				case self::AES_128_CBC :
					if (strlen ( $this->iv ) != 16) {
						return null;
					}

					$plainTextArray = array();
					for ($i = 0; $i < count ( $encryptedTextArray ); $i ++) {
						$output = $aes->blockDecrypt ( hex2bin($encryptedTextArray[$i]), $key );

						if ($i == 0) {
							$plainTextArray[$i] = $this->iv ^ $output;
						} else {
							$plainTextArray[$i] = hex2bin($encryptedTextArray[$i - 1]) ^ $output;
						}

						$this->plainText = join("", $plainTextArray);
					}
					break;

			}

		}

		$this->plainText = trim ( $this->plainText );

	}

}

Save the code above to cipher.php. In addition to this, you will need the AES128.php file from http://www.phpclasses.org/browse/package/3650.html

Here’s an example of AES-128 ECB mode encryption:

include_once ("AES128.php");
include_once ("cipher.php");

$encrypt = new Cipher;
$encrypt->password = "password";
$encrypt->plainText = "this is a very long string that we would like to encrypt using AES128";
$encrypt->encrypt();

echo "encrypted: " . bin2hex( $encrypt->encryptedText ) . "<br>";

$decrypt = new Cipher;
$decrypt->password = "password";
$decrypt->encryptedText = $encrypt->encryptedText;
$decrypt->decrypt();

echo "plain text: " . $decrypt->plainText;

The default mode is ECB. So, we don’t need to set $encrypt->mode and $decrypt->mode to Cipher::AES_128_ECB .

Here’s an example of AES-128 CBC mode encryption using an initialization vector:

include_once ("AES128.php");
include_once ("cipher.php");

$encrypt = new Cipher;
$encrypt->mode = Cipher::AES_128_CBC;
$encrypt->password = "password";
$encrypt->plainText = "this is a very long string that we would like to encrypt using AES128";
$encrypt->encrypt();

echo "iv: " . bin2hex( $encrypt->iv ) . "<br>";
echo "encrypted: " . bin2hex( $encrypt->encryptedText ) . "<br>";

$decrypt = new Cipher;
$decrypt->mode = Cipher::AES_128_CBC;
$decrypt->iv = $encrypt->iv;
$decrypt->password = "password";
$decrypt->encryptedText = $encrypt->encryptedText;
$decrypt->decrypt();

echo "plain text: " . $decrypt->plainText;

Related posts:

  1. cURL wrapper class with executable and PHP extension support

Leave a Reply