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:
