| @@ -1,27 +1,30 @@ | ||
| 1 | 1 | <?php |
| 2 | -/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ | |
| 3 | 2 | |
| 4 | 3 | /** |
| 5 | 4 | * Pure-PHP implementation of AES. |
| 6 | 5 | * |
| 7 | - * Uses mcrypt, if available, and an internal implementation, otherwise. | |
| 6 | + * Uses mcrypt, if available/possible, and an internal implementation, otherwise. | |
| 8 | 7 | * |
| 9 | 8 | * PHP versions 4 and 5 |
| 10 | 9 | * |
| 11 | - * If {@link Crypt_AES::setKeyLength() setKeyLength()} isn't called, it'll be calculated from | |
| 12 | - * {@link Crypt_AES::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's 136-bits | |
| 13 | - * it'll be null-padded to 160-bits and 160 bits will be the key length until {@link Crypt_Rijndael::setKey() setKey()} | |
| 10 | + * NOTE: Since AES.php is (for compatibility and phpseclib-historical reasons) virtually | |
| 11 | + * just a wrapper to Rijndael.php you may consider using Rijndael.php instead of | |
| 12 | + * to save one include_once(). | |
| 13 | + * | |
| 14 | + * If {@link self::setKeyLength() setKeyLength()} isn't called, it'll be calculated from | |
| 15 | + * {@link self::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's 136-bits | |
| 16 | + * it'll be null-padded to 192-bits and 192 bits will be the key length until {@link self::setKey() setKey()} | |
| 14 | 17 | * is called, again, at which point, it'll be recalculated. |
| 15 | 18 | * |
| 16 | 19 | * Since Crypt_AES extends Crypt_Rijndael, some functions are available to be called that, in the context of AES, don't |
| 17 | - * make a whole lot of sense. {@link Crypt_AES::setBlockLength() setBlockLength()}, for instance. Calling that function, | |
| 20 | + * make a whole lot of sense. {@link self::setBlockLength() setBlockLength()}, for instance. Calling that function, | |
| 18 | 21 | * however possible, won't do anything (AES has a fixed block length whereas Rijndael has a variable one). |
| 19 | 22 | * |
| 20 | 23 | * Here's a short example of how to use this library: |
| 21 | 24 | * <code> |
| 22 | 25 | * <?php |
| 23 | - * include('Crypt/AES.php'); | |
| 26 | + * include 'Crypt/AES.php'; | |
| 24 | 27 | * |
| 25 | 28 | * $aes = new Crypt_AES(); |
| 26 | 29 | * |
| 27 | 30 | * $aes->setKey('abcdefghijklmnop'); |
| @@ -41,12 +44,12 @@ | ||
| 41 | 44 | * in the Software without restriction, including without limitation the rights |
| 42 | 45 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 43 | 46 | * copies of the Software, and to permit persons to whom the Software is |
| 44 | 47 | * furnished to do so, subject to the following conditions: |
| 45 | - * | |
| 48 | + * | |
| 46 | 49 | * The above copyright notice and this permission notice shall be included in |
| 47 | 50 | * all copies or substantial portions of the Software. |
| 48 | - * | |
| 51 | + * | |
| 49 | 52 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 50 | 53 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 51 | 54 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 52 | 55 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| @@ -53,15 +56,14 @@ | ||
| 53 | 56 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 54 | 57 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| 55 | 58 | * THE SOFTWARE. |
| 56 | 59 | * |
| 57 | - * @category Crypt | |
| 58 | - * @package Crypt_AES | |
| 59 | - * @author Jim Wigginton <terrafrost@php.net> | |
| 60 | - * @copyright MMVIII Jim Wigginton | |
| 61 | - * @license http://www.opensource.org/licenses/mit-license.html MIT License | |
| 62 | - * @version $Id: AES.php,v 1.7 2010/02/09 06:10:25 terrafrost Exp $ | |
| 63 | - * @link http://phpseclib.sourceforge.net | |
| 60 | + * @category Crypt | |
| 61 | + * @package Crypt_AES | |
| 62 | + * @author Jim Wigginton <terrafrost@php.net> | |
| 63 | + * @copyright 2008 Jim Wigginton | |
| 64 | + * @license http://www.opensource.org/licenses/mit-license.html MIT License | |
| 65 | + * @link http://phpseclib.sourceforge.net | |
| 64 | 66 | */ |
| 65 | 67 | |
| 66 | 68 | /** |
| 67 | 69 | * Include Crypt_Rijndael |
| @@ -66,15 +68,15 @@ | ||
| 66 | 68 | /** |
| 67 | 69 | * Include Crypt_Rijndael |
| 68 | 70 | */ |
| 69 | 71 | if (!class_exists('Crypt_Rijndael')) { |
| 70 | - require_once 'Rijndael.php'; | |
| 72 | + include_once 'Rijndael.php'; | |
| 71 | 73 | } |
| 72 | 74 | |
| 73 | 75 | /**#@+ |
| 74 | 76 | * @access public |
| 75 | - * @see Crypt_AES::encrypt() | |
| 76 | - * @see Crypt_AES::decrypt() | |
| 77 | + * @see self::encrypt() | |
| 78 | + * @see self::decrypt() | |
| 77 | 79 | */ |
| 78 | 80 | /** |
| 79 | 81 | * Encrypt / decrypt using the Counter mode. |
| 80 | 82 | * |
| @@ -81,177 +83,61 @@ | ||
| 81 | 83 | * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode. |
| 82 | 84 | * |
| 83 | 85 | * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 |
| 84 | 86 | */ |
| 85 | -define('CRYPT_AES_MODE_CTR', -1); | |
| 87 | +define('CRYPT_AES_MODE_CTR', CRYPT_MODE_CTR); | |
| 86 | 88 | /** |
| 87 | 89 | * Encrypt / decrypt using the Electronic Code Book mode. |
| 88 | 90 | * |
| 89 | 91 | * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29 |
| 90 | 92 | */ |
| 91 | -define('CRYPT_AES_MODE_ECB', 1); | |
| 93 | +define('CRYPT_AES_MODE_ECB', CRYPT_MODE_ECB); | |
| 92 | 94 | /** |
| 93 | 95 | * Encrypt / decrypt using the Code Book Chaining mode. |
| 94 | 96 | * |
| 95 | 97 | * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 |
| 96 | 98 | */ |
| 97 | -define('CRYPT_AES_MODE_CBC', 2); | |
| 99 | +define('CRYPT_AES_MODE_CBC', CRYPT_MODE_CBC); | |
| 98 | 100 | /** |
| 99 | 101 | * Encrypt / decrypt using the Cipher Feedback mode. |
| 100 | 102 | * |
| 101 | 103 | * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 |
| 102 | 104 | */ |
| 103 | -define('CRYPT_AES_MODE_CFB', 3); | |
| 105 | +define('CRYPT_AES_MODE_CFB', CRYPT_MODE_CFB); | |
| 104 | 106 | /** |
| 105 | 107 | * Encrypt / decrypt using the Cipher Feedback mode. |
| 106 | 108 | * |
| 107 | 109 | * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 |
| 108 | 110 | */ |
| 109 | -define('CRYPT_AES_MODE_OFB', 4); | |
| 111 | +define('CRYPT_AES_MODE_OFB', CRYPT_MODE_OFB); | |
| 110 | 112 | /**#@-*/ |
| 111 | 113 | |
| 112 | -/**#@+ | |
| 113 | - * @access private | |
| 114 | - * @see Crypt_AES::Crypt_AES() | |
| 115 | - */ | |
| 116 | 114 | /** |
| 117 | - * Toggles the internal implementation | |
| 118 | - */ | |
| 119 | -define('CRYPT_AES_MODE_INTERNAL', 1); | |
| 120 | -/** | |
| 121 | - * Toggles the mcrypt implementation | |
| 122 | - */ | |
| 123 | -define('CRYPT_AES_MODE_MCRYPT', 2); | |
| 124 | -/**#@-*/ | |
| 125 | - | |
| 126 | -/** | |
| 127 | 115 | * Pure-PHP implementation of AES. |
| 128 | 116 | * |
| 117 | + * @package Crypt_AES | |
| 129 | 118 | * @author Jim Wigginton <terrafrost@php.net> |
| 130 | - * @version 0.1.0 | |
| 131 | 119 | * @access public |
| 132 | - * @package Crypt_AES | |
| 133 | 120 | */ |
| 134 | -class Crypt_AES extends Crypt_Rijndael { | |
| 121 | +class Crypt_AES extends Crypt_Rijndael | |
| 122 | +{ | |
| 135 | 123 | /** |
| 136 | - * mcrypt resource for encryption | |
| 124 | + * The namespace used by the cipher for its constants. | |
| 137 | 125 | * |
| 138 | - * The mcrypt resource can be recreated every time something needs to be created or it can be created just once. | |
| 139 | - * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. | |
| 140 | - * | |
| 141 | - * @see Crypt_AES::encrypt() | |
| 142 | - * @var String | |
| 126 | + * @see Crypt_Base::const_namespace | |
| 127 | + * @var string | |
| 143 | 128 | * @access private |
| 144 | 129 | */ |
| 145 | - var $enmcrypt; | |
| 130 | + var $const_namespace = 'AES'; | |
| 146 | 131 | |
| 147 | 132 | /** |
| 148 | - * mcrypt resource for decryption | |
| 149 | - * | |
| 150 | - * The mcrypt resource can be recreated every time something needs to be created or it can be created just once. | |
| 151 | - * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. | |
| 152 | - * | |
| 153 | - * @see Crypt_AES::decrypt() | |
| 154 | - * @var String | |
| 155 | - * @access private | |
| 156 | - */ | |
| 157 | - var $demcrypt; | |
| 158 | - | |
| 159 | - /** | |
| 160 | - * mcrypt resource for CFB mode | |
| 161 | - * | |
| 162 | - * @see Crypt_AES::encrypt() | |
| 163 | - * @see Crypt_AES::decrypt() | |
| 164 | - * @var String | |
| 165 | - * @access private | |
| 166 | - */ | |
| 167 | - var $ecb; | |
| 168 | - | |
| 169 | - /** | |
| 170 | - * Default Constructor. | |
| 171 | - * | |
| 172 | - * Determines whether or not the mcrypt extension should be used. $mode should only, at present, be | |
| 173 | - * CRYPT_AES_MODE_ECB or CRYPT_AES_MODE_CBC. If not explictly set, CRYPT_AES_MODE_CBC will be used. | |
| 174 | - * | |
| 175 | - * @param optional Integer $mode | |
| 176 | - * @return Crypt_AES | |
| 177 | - * @access public | |
| 178 | - */ | |
| 179 | - function Crypt_AES($mode = CRYPT_AES_MODE_CBC) | |
| 180 | - { | |
| 181 | - if ( !defined('CRYPT_AES_MODE') ) { | |
| 182 | - switch (true) { | |
| 183 | - case extension_loaded('mcrypt') && in_array('rijndael-128', mcrypt_list_algorithms()): | |
| 184 | - define('CRYPT_AES_MODE', CRYPT_AES_MODE_MCRYPT); | |
| 185 | - break; | |
| 186 | - default: | |
| 187 | - define('CRYPT_AES_MODE', CRYPT_AES_MODE_INTERNAL); | |
| 188 | - } | |
| 189 | - } | |
| 190 | - | |
| 191 | - switch ( CRYPT_AES_MODE ) { | |
| 192 | - case CRYPT_AES_MODE_MCRYPT: | |
| 193 | - switch ($mode) { | |
| 194 | - case CRYPT_AES_MODE_ECB: | |
| 195 | - $this->paddable = true; | |
| 196 | - $this->mode = MCRYPT_MODE_ECB; | |
| 197 | - break; | |
| 198 | - case CRYPT_AES_MODE_CTR: | |
| 199 | - // ctr doesn't have a constant associated with it even though it appears to be fairly widely | |
| 200 | - // supported. in lieu of knowing just how widely supported it is, i've, for now, opted not to | |
| 201 | - // include a compatibility layer. the layer has been implemented but, for now, is commented out. | |
| 202 | - $this->mode = 'ctr'; | |
| 203 | - //$this->mode = in_array('ctr', mcrypt_list_modes()) ? 'ctr' : CRYPT_AES_MODE_CTR; | |
| 204 | - break; | |
| 205 | - case CRYPT_AES_MODE_CFB: | |
| 206 | - $this->mode = 'ncfb'; | |
| 207 | - break; | |
| 208 | - case CRYPT_AES_MODE_OFB: | |
| 209 | - $this->mode = MCRYPT_MODE_NOFB; | |
| 210 | - break; | |
| 211 | - case CRYPT_AES_MODE_CBC: | |
| 212 | - default: | |
| 213 | - $this->paddable = true; | |
| 214 | - $this->mode = MCRYPT_MODE_CBC; | |
| 215 | - } | |
| 216 | - | |
| 217 | - $this->debuffer = $this->enbuffer = ''; | |
| 218 | - | |
| 219 | - break; | |
| 220 | - default: | |
| 221 | - switch ($mode) { | |
| 222 | - case CRYPT_AES_MODE_ECB: | |
| 223 | - $this->paddable = true; | |
| 224 | - $this->mode = CRYPT_RIJNDAEL_MODE_ECB; | |
| 225 | - break; | |
| 226 | - case CRYPT_AES_MODE_CTR: | |
| 227 | - $this->mode = CRYPT_RIJNDAEL_MODE_CTR; | |
| 228 | - break; | |
| 229 | - case CRYPT_AES_MODE_CFB: | |
| 230 | - $this->mode = CRYPT_RIJNDAEL_MODE_CFB; | |
| 231 | - break; | |
| 232 | - case CRYPT_AES_MODE_OFB: | |
| 233 | - $this->mode = CRYPT_RIJNDAEL_MODE_OFB; | |
| 234 | - break; | |
| 235 | - case CRYPT_AES_MODE_CBC: | |
| 236 | - default: | |
| 237 | - $this->paddable = true; | |
| 238 | - $this->mode = CRYPT_RIJNDAEL_MODE_CBC; | |
| 239 | - } | |
| 240 | - } | |
| 241 | - | |
| 242 | - if (CRYPT_AES_MODE == CRYPT_AES_MODE_INTERNAL) { | |
| 243 | - parent::Crypt_Rijndael($this->mode); | |
| 244 | - } | |
| 245 | - } | |
| 246 | - | |
| 247 | - /** | |
| 248 | 133 | * Dummy function |
| 249 | 134 | * |
| 250 | 135 | * Since Crypt_AES extends Crypt_Rijndael, this function is, technically, available, but it doesn't do anything. |
| 251 | 136 | * |
| 137 | + * @see Crypt_Rijndael::setBlockLength() | |
| 252 | 138 | * @access public |
| 253 | - * @param Integer $length | |
| 139 | + * @param int $length | |
| 254 | 140 | */ |
| 255 | 141 | function setBlockLength($length) |
| 256 | 142 | { |
| 257 | 143 | return; |
| @@ -256,356 +142,56 @@ | ||
| 256 | 142 | { |
| 257 | 143 | return; |
| 258 | 144 | } |
| 259 | 145 | |
| 260 | - | |
| 261 | 146 | /** |
| 262 | - * Sets the initialization vector. (optional) | |
| 147 | + * Sets the key length | |
| 263 | 148 | * |
| 264 | - * SetIV is not required when CRYPT_RIJNDAEL_MODE_ECB is being used. If not explictly set, it'll be assumed | |
| 265 | - * to be all zero's. | |
| 149 | + * Valid key lengths are 128, 192, and 256. If the length is less than 128, it will be rounded up to | |
| 150 | + * 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount. | |
| 266 | 151 | * |
| 152 | + * @see Crypt_Rijndael:setKeyLength() | |
| 267 | 153 | * @access public |
| 268 | - * @param String $iv | |
| 154 | + * @param int $length | |
| 269 | 155 | */ |
| 270 | - function setIV($iv) | |
| 156 | + function setKeyLength($length) | |
| 271 | 157 | { |
| 272 | - parent::setIV($iv); | |
| 273 | - if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) { | |
| 274 | - $this->changed = true; | |
| 158 | + switch ($length) { | |
| 159 | + case 160: | |
| 160 | + $length = 192; | |
| 161 | + break; | |
| 162 | + case 224: | |
| 163 | + $length = 256; | |
| 275 | 164 | } |
| 165 | + parent::setKeyLength($length); | |
| 276 | 166 | } |
| 277 | 167 | |
| 278 | 168 | /** |
| 279 | - * Encrypts a message. | |
| 169 | + * Sets the key. | |
| 280 | 170 | * |
| 281 | - * $plaintext will be padded with up to 16 additional bytes. Other AES implementations may or may not pad in the | |
| 282 | - * same manner. Other common approaches to padding and the reasons why it's necessary are discussed in the following | |
| 283 | - * URL: | |
| 171 | + * Rijndael supports five different key lengths, AES only supports three. | |
| 284 | 172 | * |
| 285 | - * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html} | |
| 286 | - * | |
| 287 | - * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does. | |
| 288 | - * strlen($plaintext) will still need to be a multiple of 16, however, arbitrary values can be added to make it that | |
| 289 | - * length. | |
| 290 | - * | |
| 291 | - * @see Crypt_AES::decrypt() | |
| 173 | + * @see Crypt_Rijndael:setKey() | |
| 174 | + * @see setKeyLength() | |
| 292 | 175 | * @access public |
| 293 | - * @param String $plaintext | |
| 176 | + * @param string $key | |
| 294 | 177 | */ |
| 295 | - function encrypt($plaintext) | |
| 178 | + function setKey($key) | |
| 296 | 179 | { |
| 297 | - if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) { | |
| 298 | - $changed = $this->changed; | |
| 299 | - $this->_mcryptSetup(); | |
| 300 | - /* | |
| 301 | - if ($this->mode == CRYPT_AES_MODE_CTR) { | |
| 302 | - $iv = $this->encryptIV; | |
| 303 | - $xor = mcrypt_generic($this->enmcrypt, $this->_generate_xor(strlen($plaintext), $iv)); | |
| 304 | - $ciphertext = $plaintext ^ $xor; | |
| 305 | - if ($this->continuousBuffer) { | |
| 306 | - $this->encryptIV = $iv; | |
| 307 | - } | |
| 308 | - return $ciphertext; | |
| 309 | - } | |
| 310 | - */ | |
| 311 | - // re: http://phpseclib.sourceforge.net/cfb-demo.phps | |
| 312 | - // using mcrypt's default handing of CFB the above would output two different things. using phpseclib's | |
| 313 | - // rewritten CFB implementation the above outputs the same thing twice. | |
| 314 | - if ($this->mode == 'ncfb') { | |
| 315 | - if ($changed) { | |
| 316 | - $this->ecb = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, ''); | |
| 317 | - mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); | |
| 318 | - } | |
| 180 | + parent::setKey($key); | |
| 319 | 181 | |
| 320 | - if (strlen($this->enbuffer)) { | |
| 321 | - $ciphertext = $plaintext ^ substr($this->encryptIV, strlen($this->enbuffer)); | |
| 322 | - $this->enbuffer.= $ciphertext; | |
| 323 | - if (strlen($this->enbuffer) == 16) { | |
| 324 | - $this->encryptIV = $this->enbuffer; | |
| 325 | - $this->enbuffer = ''; | |
| 326 | - mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV); | |
| 327 | - } | |
| 328 | - $plaintext = substr($plaintext, strlen($ciphertext)); | |
| 329 | - } else { | |
| 330 | - $ciphertext = ''; | |
| 331 | - } | |
| 332 | - | |
| 333 | - $last_pos = strlen($plaintext) & 0xFFFFFFF0; | |
| 334 | - $ciphertext.= $last_pos ? mcrypt_generic($this->enmcrypt, substr($plaintext, 0, $last_pos)) : ''; | |
| 335 | - | |
| 336 | - if (strlen($plaintext) & 0xF) { | |
| 337 | - if (strlen($ciphertext)) { | |
| 338 | - $this->encryptIV = substr($ciphertext, -16); | |
| 339 | - } | |
| 340 | - $this->encryptIV = mcrypt_generic($this->ecb, $this->encryptIV); | |
| 341 | - $this->enbuffer = substr($plaintext, $last_pos) ^ $this->encryptIV; | |
| 342 | - $ciphertext.= $this->enbuffer; | |
| 343 | - } | |
| 344 | - | |
| 345 | - return $ciphertext; | |
| 346 | - } | |
| 347 | - | |
| 348 | - if ($this->paddable) { | |
| 349 | - $plaintext = $this->_pad($plaintext); | |
| 350 | - } | |
| 351 | - | |
| 352 | - $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext); | |
| 353 | - | |
| 354 | - if (!$this->continuousBuffer) { | |
| 355 | - mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv); | |
| 356 | - } | |
| 357 | - | |
| 358 | - return $ciphertext; | |
| 359 | - } | |
| 360 | - | |
| 361 | - return parent::encrypt($plaintext); | |
| 362 | - } | |
| 363 | - | |
| 364 | - /** | |
| 365 | - * Decrypts a message. | |
| 366 | - * | |
| 367 | - * If strlen($ciphertext) is not a multiple of 16, null bytes will be added to the end of the string until it is. | |
| 368 | - * | |
| 369 | - * @see Crypt_AES::encrypt() | |
| 370 | - * @access public | |
| 371 | - * @param String $ciphertext | |
| 372 | - */ | |
| 373 | - function decrypt($ciphertext) | |
| 374 | - { | |
| 375 | - if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) { | |
| 376 | - $changed = $this->changed; | |
| 377 | - $this->_mcryptSetup(); | |
| 378 | - /* | |
| 379 | - if ($this->mode == CRYPT_AES_MODE_CTR) { | |
| 380 | - $iv = $this->decryptIV; | |
| 381 | - $xor = mcrypt_generic($this->enmcrypt, $this->_generate_xor(strlen($ciphertext), $iv)); | |
| 382 | - $plaintext = $ciphertext ^ $xor; | |
| 383 | - if ($this->continuousBuffer) { | |
| 384 | - $this->decryptIV = $iv; | |
| 385 | - } | |
| 386 | - return $plaintext; | |
| 387 | - } | |
| 388 | - */ | |
| 389 | - if ($this->mode == 'ncfb') { | |
| 390 | - if ($changed) { | |
| 391 | - $this->ecb = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, ''); | |
| 392 | - mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); | |
| 393 | - } | |
| 394 | - | |
| 395 | - if (strlen($this->debuffer)) { | |
| 396 | - $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($this->debuffer)); | |
| 397 | - | |
| 398 | - $this->debuffer.= substr($ciphertext, 0, strlen($plaintext)); | |
| 399 | - if (strlen($this->debuffer) == 16) { | |
| 400 | - $this->decryptIV = $this->debuffer; | |
| 401 | - $this->debuffer = ''; | |
| 402 | - mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV); | |
| 403 | - } | |
| 404 | - $ciphertext = substr($ciphertext, strlen($plaintext)); | |
| 405 | - } else { | |
| 406 | - $plaintext = ''; | |
| 407 | - } | |
| 408 | - | |
| 409 | - $last_pos = strlen($ciphertext) & 0xFFFFFFF0; | |
| 410 | - $plaintext.= $last_pos ? mdecrypt_generic($this->demcrypt, substr($ciphertext, 0, $last_pos)) : ''; | |
| 411 | - | |
| 412 | - if (strlen($ciphertext) & 0xF) { | |
| 413 | - if (strlen($plaintext)) { | |
| 414 | - $this->decryptIV = substr($ciphertext, $last_pos - 16, 16); | |
| 415 | - } | |
| 416 | - $this->decryptIV = mcrypt_generic($this->ecb, $this->decryptIV); | |
| 417 | - $this->debuffer = substr($ciphertext, $last_pos); | |
| 418 | - $plaintext.= $this->debuffer ^ $this->decryptIV; | |
| 419 | - } | |
| 420 | - | |
| 421 | - return $plaintext; | |
| 422 | - } | |
| 423 | - | |
| 424 | - if ($this->paddable) { | |
| 425 | - // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic : | |
| 426 | - // "The data is padded with "\0" to make sure the length of the data is n * blocksize." | |
| 427 | - $ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 15) & 0xFFFFFFF0, chr(0)); | |
| 428 | - } | |
| 429 | - | |
| 430 | - $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext); | |
| 431 | - | |
| 432 | - if (!$this->continuousBuffer) { | |
| 433 | - mcrypt_generic_init($this->demcrypt, $this->key, $this->iv); | |
| 434 | - } | |
| 435 | - | |
| 436 | - return $this->paddable ? $this->_unpad($plaintext) : $plaintext; | |
| 437 | - } | |
| 438 | - | |
| 439 | - return parent::decrypt($ciphertext); | |
| 440 | - } | |
| 441 | - | |
| 442 | - /** | |
| 443 | - * Setup mcrypt | |
| 444 | - * | |
| 445 | - * Validates all the variables. | |
| 446 | - * | |
| 447 | - * @access private | |
| 448 | - */ | |
| 449 | - function _mcryptSetup() | |
| 450 | - { | |
| 451 | - if (!$this->changed) { | |
| 452 | - return; | |
| 453 | - } | |
| 454 | - | |
| 455 | 182 | if (!$this->explicit_key_length) { |
| 456 | - // this just copied from Crypt_Rijndael::_setup() | |
| 457 | - $length = strlen($this->key) >> 2; | |
| 458 | - if ($length > 8) { | |
| 459 | - $length = 8; | |
| 460 | - } else if ($length < 4) { | |
| 461 | - $length = 4; | |
| 183 | + $length = strlen($key); | |
| 184 | + switch (true) { | |
| 185 | + case $length <= 16: | |
| 186 | + $this->key_length = 16; | |
| 187 | + break; | |
| 188 | + case $length <= 24: | |
| 189 | + $this->key_length = 24; | |
| 190 | + break; | |
| 191 | + default: | |
| 192 | + $this->key_length = 32; | |
| 462 | 193 | } |
| 463 | - $this->Nk = $length; | |
| 464 | - $this->key_size = $length << 2; | |
| 194 | + $this->_setEngine(); | |
| 465 | 195 | } |
| 466 | - | |
| 467 | - switch ($this->Nk) { | |
| 468 | - case 4: // 128 | |
| 469 | - $this->key_size = 16; | |
| 470 | - break; | |
| 471 | - case 5: // 160 | |
| 472 | - case 6: // 192 | |
| 473 | - $this->key_size = 24; | |
| 474 | - break; | |
| 475 | - case 7: // 224 | |
| 476 | - case 8: // 256 | |
| 477 | - $this->key_size = 32; | |
| 478 | - } | |
| 479 | - | |
| 480 | - $this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, chr(0)); | |
| 481 | - $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($this->iv, 0, 16), 16, chr(0)); | |
| 482 | - | |
| 483 | - if (!isset($this->enmcrypt)) { | |
| 484 | - $mode = $this->mode; | |
| 485 | - //$mode = $this->mode == CRYPT_AES_MODE_CTR ? MCRYPT_MODE_ECB : $this->mode; | |
| 486 | - | |
| 487 | - $this->demcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, ''); | |
| 488 | - $this->enmcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, ''); | |
| 489 | - } // else should mcrypt_generic_deinit be called? | |
| 490 | - | |
| 491 | - mcrypt_generic_init($this->demcrypt, $this->key, $this->iv); | |
| 492 | - mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv); | |
| 493 | - | |
| 494 | - $this->changed = false; | |
| 495 | 196 | } |
| 496 | - | |
| 497 | - /** | |
| 498 | - * Encrypts a block | |
| 499 | - * | |
| 500 | - * Optimized over Crypt_Rijndael's implementation by means of loop unrolling. | |
| 501 | - * | |
| 502 | - * @see Crypt_Rijndael::_encryptBlock() | |
| 503 | - * @access private | |
| 504 | - * @param String $in | |
| 505 | - * @return String | |
| 506 | - */ | |
| 507 | - function _encryptBlock($in) | |
| 508 | - { | |
| 509 | - $state = unpack('N*word', $in); | |
| 510 | - | |
| 511 | - $Nr = $this->Nr; | |
| 512 | - $w = $this->w; | |
| 513 | - $t0 = $this->t0; | |
| 514 | - $t1 = $this->t1; | |
| 515 | - $t2 = $this->t2; | |
| 516 | - $t3 = $this->t3; | |
| 517 | - | |
| 518 | - // addRoundKey and reindex $state | |
| 519 | - $state = array( | |
| 520 | - $state['word1'] ^ $w[0][0], | |
| 521 | - $state['word2'] ^ $w[0][1], | |
| 522 | - $state['word3'] ^ $w[0][2], | |
| 523 | - $state['word4'] ^ $w[0][3] | |
| 524 | - ); | |
| 525 | - | |
| 526 | - // shiftRows + subWord + mixColumns + addRoundKey | |
| 527 | - // we could loop unroll this and use if statements to do more rounds as necessary, but, in my tests, that yields | |
| 528 | - // only a marginal improvement. since that also, imho, hinders the readability of the code, i've opted not to do it. | |
| 529 | - for ($round = 1; $round < $this->Nr; $round++) { | |
| 530 | - $state = array( | |
| 531 | - $t0[$state[0] & 0xFF000000] ^ $t1[$state[1] & 0x00FF0000] ^ $t2[$state[2] & 0x0000FF00] ^ $t3[$state[3] & 0x000000FF] ^ $w[$round][0], | |
| 532 | - $t0[$state[1] & 0xFF000000] ^ $t1[$state[2] & 0x00FF0000] ^ $t2[$state[3] & 0x0000FF00] ^ $t3[$state[0] & 0x000000FF] ^ $w[$round][1], | |
| 533 | - $t0[$state[2] & 0xFF000000] ^ $t1[$state[3] & 0x00FF0000] ^ $t2[$state[0] & 0x0000FF00] ^ $t3[$state[1] & 0x000000FF] ^ $w[$round][2], | |
| 534 | - $t0[$state[3] & 0xFF000000] ^ $t1[$state[0] & 0x00FF0000] ^ $t2[$state[1] & 0x0000FF00] ^ $t3[$state[2] & 0x000000FF] ^ $w[$round][3] | |
| 535 | - ); | |
| 536 | - | |
| 537 | - } | |
| 538 | - | |
| 539 | - // subWord | |
| 540 | - $state = array( | |
| 541 | - $this->_subWord($state[0]), | |
| 542 | - $this->_subWord($state[1]), | |
| 543 | - $this->_subWord($state[2]), | |
| 544 | - $this->_subWord($state[3]) | |
| 545 | - ); | |
| 546 | - | |
| 547 | - // shiftRows + addRoundKey | |
| 548 | - $state = array( | |
| 549 | - ($state[0] & 0xFF000000) ^ ($state[1] & 0x00FF0000) ^ ($state[2] & 0x0000FF00) ^ ($state[3] & 0x000000FF) ^ $this->w[$this->Nr][0], | |
| 550 | - ($state[1] & 0xFF000000) ^ ($state[2] & 0x00FF0000) ^ ($state[3] & 0x0000FF00) ^ ($state[0] & 0x000000FF) ^ $this->w[$this->Nr][1], | |
| 551 | - ($state[2] & 0xFF000000) ^ ($state[3] & 0x00FF0000) ^ ($state[0] & 0x0000FF00) ^ ($state[1] & 0x000000FF) ^ $this->w[$this->Nr][2], | |
| 552 | - ($state[3] & 0xFF000000) ^ ($state[0] & 0x00FF0000) ^ ($state[1] & 0x0000FF00) ^ ($state[2] & 0x000000FF) ^ $this->w[$this->Nr][3] | |
| 553 | - ); | |
| 554 | - | |
| 555 | - return pack('N*', $state[0], $state[1], $state[2], $state[3]); | |
| 556 | - } | |
| 557 | - | |
| 558 | - /** | |
| 559 | - * Decrypts a block | |
| 560 | - * | |
| 561 | - * Optimized over Crypt_Rijndael's implementation by means of loop unrolling. | |
| 562 | - * | |
| 563 | - * @see Crypt_Rijndael::_decryptBlock() | |
| 564 | - * @access private | |
| 565 | - * @param String $in | |
| 566 | - * @return String | |
| 567 | - */ | |
| 568 | - function _decryptBlock($in) | |
| 569 | - { | |
| 570 | - $state = unpack('N*word', $in); | |
| 571 | - | |
| 572 | - $Nr = $this->Nr; | |
| 573 | - $dw = $this->dw; | |
| 574 | - $dt0 = $this->dt0; | |
| 575 | - $dt1 = $this->dt1; | |
| 576 | - $dt2 = $this->dt2; | |
| 577 | - $dt3 = $this->dt3; | |
| 578 | - | |
| 579 | - // addRoundKey and reindex $state | |
| 580 | - $state = array( | |
| 581 | - $state['word1'] ^ $dw[$this->Nr][0], | |
| 582 | - $state['word2'] ^ $dw[$this->Nr][1], | |
| 583 | - $state['word3'] ^ $dw[$this->Nr][2], | |
| 584 | - $state['word4'] ^ $dw[$this->Nr][3] | |
| 585 | - ); | |
| 586 | - | |
| 587 | - | |
| 588 | - // invShiftRows + invSubBytes + invMixColumns + addRoundKey | |
| 589 | - for ($round = $this->Nr - 1; $round > 0; $round--) { | |
| 590 | - $state = array( | |
| 591 | - $dt0[$state[0] & 0xFF000000] ^ $dt1[$state[3] & 0x00FF0000] ^ $dt2[$state[2] & 0x0000FF00] ^ $dt3[$state[1] & 0x000000FF] ^ $dw[$round][0], | |
| 592 | - $dt0[$state[1] & 0xFF000000] ^ $dt1[$state[0] & 0x00FF0000] ^ $dt2[$state[3] & 0x0000FF00] ^ $dt3[$state[2] & 0x000000FF] ^ $dw[$round][1], | |
| 593 | - $dt0[$state[2] & 0xFF000000] ^ $dt1[$state[1] & 0x00FF0000] ^ $dt2[$state[0] & 0x0000FF00] ^ $dt3[$state[3] & 0x000000FF] ^ $dw[$round][2], | |
| 594 | - $dt0[$state[3] & 0xFF000000] ^ $dt1[$state[2] & 0x00FF0000] ^ $dt2[$state[1] & 0x0000FF00] ^ $dt3[$state[0] & 0x000000FF] ^ $dw[$round][3] | |
| 595 | - ); | |
| 596 | - } | |
| 597 | - | |
| 598 | - // invShiftRows + invSubWord + addRoundKey | |
| 599 | - $state = array( | |
| 600 | - $this->_invSubWord(($state[0] & 0xFF000000) ^ ($state[3] & 0x00FF0000) ^ ($state[2] & 0x0000FF00) ^ ($state[1] & 0x000000FF)) ^ $dw[0][0], | |
| 601 | - $this->_invSubWord(($state[1] & 0xFF000000) ^ ($state[0] & 0x00FF0000) ^ ($state[3] & 0x0000FF00) ^ ($state[2] & 0x000000FF)) ^ $dw[0][1], | |
| 602 | - $this->_invSubWord(($state[2] & 0xFF000000) ^ ($state[1] & 0x00FF0000) ^ ($state[0] & 0x0000FF00) ^ ($state[3] & 0x000000FF)) ^ $dw[0][2], | |
| 603 | - $this->_invSubWord(($state[3] & 0xFF000000) ^ ($state[2] & 0x00FF0000) ^ ($state[1] & 0x0000FF00) ^ ($state[0] & 0x000000FF)) ^ $dw[0][3] | |
| 604 | - ); | |
| 605 | - | |
| 606 | - return pack('N*', $state[0], $state[1], $state[2], $state[3]); | |
| 607 | - } | |
| 608 | 197 | } |
| 609 | - | |
| 610 | -// vim: ts=4:sw=4:et: | |
| 611 | -// vim6: fdl=1: | |