Oct 14th

0

AES wrapper class with pure php and MCrypt extension support

PHPMCrypt

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.

001 function hex2bin($hex) {
002  
003     return pack ( "H*", $hex );
004  
005 }
006  
007 class Cipher {
008  
009     public $password;
010  
011     public $plainText;
012  
013     public $encryptedText;
014  
015     public $iv;
016  
017     public $mode;
018  
019     const AES_128_ECB = "AES_128_ECB";
020  
021     const AES_128_CBC = "AES_128_CBC";
022  
023     public function __construct() {
024  
025         $this->mode = self::AES_128_ECB;
026  
027     }
028  
029     public function encrypt($useSuppliedIV = false) {
030  
031         if (!$this->plainText) {
032             return "";
033         }
034  
035         switch ($this->mode) {
036  
037             case self::AES_128_ECB :
038             case self::AES_128_CBC :
039                 if (strlen($this->password) > 16) {
040                     $this->password = substr($this->password, 0, 16);
041                 }
042                 break;
043  
044         }
045  
046         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" )) {
047  
048             switch ($this->mode) {
049  
050                 case self::AES_128_ECB :
051                     $td = mcrypt_module_open ( 'rijndael-128', '', 'ecb', '' );
052                     break;
053  
054                 case self::AES_128_CBC :
055                     $td = mcrypt_module_open ( 'rijndael-128', '', 'cbc', '' );
056                     break;
057  
058             }
059  
060             if ($useSuppliedIV) {
061                 if (strlen ( $this->iv ) != mcrypt_enc_get_iv_size ( $td )) {
062                     return null;
063                 }
064             } else {
065                 $this->iv = mcrypt_create_iv ( mcrypt_enc_get_iv_size ( $td ), MCRYPT_RAND );
066             }
067  
068             mcrypt_generic_init ( $td, $this->password, $this->iv );
069             $this->encryptedText = mcrypt_generic ( $td, $this->plainText );
070             mcrypt_generic_deinit ( $td );
071  
072         } else {
073  
074             $aes = new AES128 ( );
075             $key = $aes->makeKey ( $this->password );
076  
077             $plainTextArray = str_split ( $this->plainText, 16 );
078  
079             $lastIndex = count($plainTextArray) - 1;
080             if (strlen($plainTextArray[$lastIndex]) != 16) {
081  
082                 for ($i = strlen($plainTextArray[$lastIndex]); $i < 16; $i++) {
083                     $plainTextArray[$lastIndex] .= chr (0);
084                 }
085  
086             }
087  
088             $this->encryptedText = "";
089  
090             if ($useSuppliedIV) {
091                 if (strlen ( $this->iv ) != 16) {
092                     return null;
093                 }
094             } else {
095                 $this->iv = "";
096                 for ($i = 0; $i < 16; $i++) {
097                     $this->iv .= chr (rand(0, 255));
098                 }
099             }
100  
101             switch ($this->mode) {
102  
103                 case self::AES_128_ECB :
104  
105                     for($i = 0; $i < count ( $plainTextArray ); $i ++) {
106                         $this->encryptedText .= $aes->blockEncrypt ( $plainTextArray [$i], $key );
107                     }
108  
109                     break;
110  
111                 case self::AES_128_CBC :
112                     $encryptedTextArray = array();
113                     for ($i = 0; $i < count ( $plainTextArray ); $i ++) {
114                         if ($i == 0) {
115                             $input = $this->iv ^ $plainTextArray[$i];
116                         } else {
117                             $input = $encryptedTextArray[$i - 1] ^ $plainTextArray[$i];
118                         }
119  
120                         $encryptedTextArray[$i] = $aes->blockEncrypt ( $input, $key );
121                     }
122  
123                     $this->encryptedText = join("", $encryptedTextArray);
124  
125                     break;
126             }
127         }
128  
129     }
130  
131     public function decrypt() {
132         if (!$this->encryptedText) {
133             return "";
134         }
135  
136         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" )) {
137  
138             switch ($this->mode) {
139  
140                 case self::AES_128_ECB :
141                     $td = mcrypt_module_open ( 'rijndael-128', '', 'ecb', '' );
142                     $this->iv = mcrypt_create_iv ( mcrypt_enc_get_iv_size ( $td ), MCRYPT_RAND );
143                     break;
144  
145                 case self::AES_128_CBC :
146                     $td = mcrypt_module_open ( 'rijndael-128', '', 'cbc', '' );
147                     if (strlen ( $this->iv ) != mcrypt_enc_get_iv_size ( $td )) {
148                         return null;
149                     }
150                     break;
151  
152             }
153  
154             mcrypt_generic_init ( $td, $this->password, $this->iv );
155             $this->plainText = mdecrypt_generic ( $td, $this->encryptedText );
156             mcrypt_generic_deinit ( $td );
157  
158         } else {
159  
160             $aes = new AES128 ( );
161             $key = $aes->makeKey ( $this->password );
162  
163             $encryptedTextArray = str_split ( bin2hex ( $this->encryptedText ), 32 );
164  
165             $this->plainText = "";
166  
167             switch ($this->mode) {
168  
169                 case self::AES_128_ECB :
170                     for($i = 0; $i < count ( $encryptedTextArray ); $i ++) {
171                         $this->plainText .= $aes->blockDecrypt ( hex2bin ( $encryptedTextArray [$i] ), $key );
172                     }
173                     break;
174  
175                 case self::AES_128_CBC :
176                     if (strlen ( $this->iv ) != 16) {
177                         return null;
178                     }
179  
180                     $plainTextArray = array();
181                     for ($i = 0; $i < count ( $encryptedTextArray ); $i ++) {
182                         $output = $aes->blockDecrypt ( hex2bin($encryptedTextArray[$i]), $key );
183  
184                         if ($i == 0) {
185                             $plainTextArray[$i] = $this->iv ^ $output;
186                         } else {
187                             $plainTextArray[$i] = hex2bin($encryptedTextArray[$i - 1]) ^ $output;
188                         }
189  
190                         $this->plainText = join("", $plainTextArray);
191                     }
192                     break;
193  
194             }
195  
196         }
197  
198         $this->plainText = trim ( $this->plainText );
199  
200     }
201  
202 }

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:

01 include_once ("AES128.php");
02 include_once ("cipher.php");
03  
04 $encrypt = new Cipher;
05 $encrypt->password = "password";
06 $encrypt->plainText = "this is a very long string that we would like to encrypt using AES128";
07 $encrypt->encrypt();
08  
09 echo "encrypted: " . bin2hex( $encrypt->encryptedText ) . "<br>";
10  
11 $decrypt = new Cipher;
12 $decrypt->password = "password";
13 $decrypt->encryptedText = $encrypt->encryptedText;
14 $decrypt->decrypt();
15  
16 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:

01 include_once ("AES128.php");
02 include_once ("cipher.php");
03  
04 $encrypt = new Cipher;
05 $encrypt->mode = Cipher::AES_128_CBC;
06 $encrypt->password = "password";
07 $encrypt->plainText = "this is a very long string that we would like to encrypt using AES128";
08 $encrypt->encrypt();
09  
10 echo "iv: " . bin2hex( $encrypt->iv ) . "<br>";
11 echo "encrypted: " . bin2hex( $encrypt->encryptedText ) . "<br>";
12  
13 $decrypt = new Cipher;
14 $decrypt->mode = Cipher::AES_128_CBC;
15 $decrypt->iv = $encrypt->iv;
16 $decrypt->password = "password";
17 $decrypt->encryptedText = $encrypt->encryptedText;
18 $decrypt->decrypt();
19  
20 echo "plain text: " . $decrypt->plainText;

Related posts:

  1. cURL wrapper class with executable and PHP extension support