36 changed files with 86 additions and 16556 deletions
@ -1,479 +0,0 @@
|
||||
<?php |
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
||||
|
||||
/** |
||||
* Pure-PHP implementation of AES. |
||||
* |
||||
* Uses mcrypt, if available, and an internal implementation, otherwise. |
||||
* |
||||
* PHP versions 4 and 5 |
||||
* |
||||
* If {@link Crypt_AES::setKeyLength() setKeyLength()} isn't called, it'll be calculated from |
||||
* {@link Crypt_AES::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's 136-bits |
||||
* it'll be null-padded to 160-bits and 160 bits will be the key length until {@link Crypt_Rijndael::setKey() setKey()} |
||||
* is called, again, at which point, it'll be recalculated. |
||||
* |
||||
* Since Crypt_AES extends Crypt_Rijndael, some functions are available to be called that, in the context of AES, don't |
||||
* make a whole lot of sense. {@link Crypt_AES::setBlockLength() setBlockLength()}, for instance. Calling that function, |
||||
* however possible, won't do anything (AES has a fixed block length whereas Rijndael has a variable one). |
||||
* |
||||
* Here's a short example of how to use this library: |
||||
* <code> |
||||
* <?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)); |
||||
* ?> |
||||
* </code> |
||||
* |
||||
* LICENSE: This library is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU Lesser General Public |
||||
* License as published by the Free Software Foundation; either |
||||
* version 2.1 of the License, or (at your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
* Lesser General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public |
||||
* License along with this library; if not, write to the Free Software |
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
||||
* MA 02111-1307 USA |
||||
* |
||||
* @category Crypt |
||||
* @package Crypt_AES |
||||
* @author Jim Wigginton <terrafrost@php.net> |
||||
* @copyright MMVIII Jim Wigginton |
||||
* @license http://www.gnu.org/licenses/lgpl.txt |
||||
* @version $Id: AES.php,v 1.7 2010/02/09 06:10:25 terrafrost Exp $ |
||||
* @link http://phpseclib.sourceforge.net |
||||
*/ |
||||
|
||||
/** |
||||
* Include Crypt_Rijndael |
||||
*/ |
||||
require_once 'Rijndael.php'; |
||||
|
||||
/**#@+ |
||||
* @access public |
||||
* @see Crypt_AES::encrypt() |
||||
* @see Crypt_AES::decrypt() |
||||
*/ |
||||
/** |
||||
* Encrypt / decrypt using the Counter mode. |
||||
* |
||||
* Set to -1 since that's what Crypt/Random.php uses to index the CTR mode. |
||||
* |
||||
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 |
||||
*/ |
||||
define('CRYPT_AES_MODE_CTR', -1); |
||||
/** |
||||
* Encrypt / decrypt using the Electronic Code Book mode. |
||||
* |
||||
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29 |
||||
*/ |
||||
define('CRYPT_AES_MODE_ECB', 1); |
||||
/** |
||||
* Encrypt / decrypt using the Code Book Chaining mode. |
||||
* |
||||
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 |
||||
*/ |
||||
define('CRYPT_AES_MODE_CBC', 2); |
||||
/**#@-*/ |
||||
|
||||
/**#@+ |
||||
* @access private |
||||
* @see Crypt_AES::Crypt_AES() |
||||
*/ |
||||
/** |
||||
* Toggles the internal implementation |
||||
*/ |
||||
define('CRYPT_AES_MODE_INTERNAL', 1); |
||||
/** |
||||
* Toggles the mcrypt implementation |
||||
*/ |
||||
define('CRYPT_AES_MODE_MCRYPT', 2); |
||||
/**#@-*/ |
||||
|
||||
/** |
||||
* Pure-PHP implementation of AES. |
||||
* |
||||
* @author Jim Wigginton <terrafrost@php.net> |
||||
* @version 0.1.0 |
||||
* @access public |
||||
* @package Crypt_AES |
||||
*/ |
||||
class Crypt_AES extends Crypt_Rijndael { |
||||
/** |
||||
* mcrypt resource for encryption |
||||
* |
||||
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once. |
||||
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. |
||||
* |
||||
* @see Crypt_AES::encrypt() |
||||
* @var String |
||||
* @access private |
||||
*/ |
||||
var $enmcrypt; |
||||
|
||||
/** |
||||
* mcrypt resource for decryption |
||||
* |
||||
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once. |
||||
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. |
||||
* |
||||
* @see Crypt_AES::decrypt() |
||||
* @var String |
||||
* @access private |
||||
*/ |
||||
var $demcrypt; |
||||
|
||||
/** |
||||
* Default Constructor. |
||||
* |
||||
* Determines whether or not the mcrypt extension should be used. $mode should only, at present, be |
||||
* CRYPT_AES_MODE_ECB or CRYPT_AES_MODE_CBC. If not explictly set, CRYPT_AES_MODE_CBC will be used. |
||||
* |
||||
* @param optional Integer $mode |
||||
* @return Crypt_AES |
||||
* @access public |
||||
*/ |
||||
function Crypt_AES($mode = CRYPT_AES_MODE_CBC) |
||||
{ |
||||
if ( !defined('CRYPT_AES_MODE') ) { |
||||
switch (true) { |
||||
case extension_loaded('mcrypt'): |
||||
// i'd check to see if aes was supported, by doing in_array('des', mcrypt_list_algorithms('')), |
||||
// but since that can be changed after the object has been created, there doesn't seem to be |
||||
// a lot of point... |
||||
define('CRYPT_AES_MODE', CRYPT_AES_MODE_MCRYPT); |
||||
break; |
||||
default: |
||||
define('CRYPT_AES_MODE', CRYPT_AES_MODE_INTERNAL); |
||||
} |
||||
} |
||||
|
||||
switch ( CRYPT_AES_MODE ) { |
||||
case CRYPT_AES_MODE_MCRYPT: |
||||
switch ($mode) { |
||||
case CRYPT_AES_MODE_ECB: |
||||
$this->mode = MCRYPT_MODE_ECB; |
||||
break; |
||||
case CRYPT_AES_MODE_CTR: |
||||
// ctr doesn't have a constant associated with it even though it appears to be fairly widely |
||||
// supported. in lieu of knowing just how widely supported it is, i've, for now, opted not to |
||||
// include a compatibility layer. the layer has been implemented but, for now, is commented out. |
||||
$this->mode = 'ctr'; |
||||
//$this->mode = in_array('ctr', mcrypt_list_modes()) ? 'ctr' : CRYPT_AES_MODE_CTR; |
||||
break; |
||||
case CRYPT_AES_MODE_CBC: |
||||
default: |
||||
$this->mode = MCRYPT_MODE_CBC; |
||||
} |
||||
|
||||
break; |
||||
default: |
||||
switch ($mode) { |
||||
case CRYPT_AES_MODE_ECB: |
||||
$this->mode = CRYPT_RIJNDAEL_MODE_ECB; |
||||
break; |
||||
case CRYPT_AES_MODE_CTR: |
||||
$this->mode = CRYPT_RIJNDAEL_MODE_CTR; |
||||
break; |
||||
case CRYPT_AES_MODE_CBC: |
||||
default: |
||||
$this->mode = CRYPT_RIJNDAEL_MODE_CBC; |
||||
} |
||||
} |
||||
|
||||
if (CRYPT_AES_MODE == CRYPT_AES_MODE_INTERNAL) { |
||||
parent::Crypt_Rijndael($this->mode); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Dummy function |
||||
* |
||||
* Since Crypt_AES extends Crypt_Rijndael, this function is, technically, available, but it doesn't do anything. |
||||
* |
||||
* @access public |
||||
* @param Integer $length |
||||
*/ |
||||
function setBlockLength($length) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
/** |
||||
* Encrypts a message. |
||||
* |
||||
* $plaintext will be padded with up to 16 additional bytes. Other AES implementations may or may not pad in the |
||||
* same manner. Other common approaches to padding and the reasons why it's necessary are discussed in the following |
||||
* URL: |
||||
* |
||||
* {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html} |
||||
* |
||||
* An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does. |
||||
* strlen($plaintext) will still need to be a multiple of 16, however, arbitrary values can be added to make it that |
||||
* length. |
||||
* |
||||
* @see Crypt_AES::decrypt() |
||||
* @access public |
||||
* @param String $plaintext |
||||
*/ |
||||
function encrypt($plaintext) |
||||
{ |
||||
if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) { |
||||
$this->_mcryptSetup(); |
||||
/* |
||||
if ($this->mode == CRYPT_AES_MODE_CTR) { |
||||
$iv = $this->encryptIV; |
||||
$xor = mcrypt_generic($this->enmcrypt, $this->_generate_xor(strlen($plaintext), $iv)); |
||||
$ciphertext = $plaintext ^ $xor; |
||||
if ($this->continuousBuffer) { |
||||
$this->encryptIV = $iv; |
||||
} |
||||
return $ciphertext; |
||||
} |
||||
*/ |
||||
|
||||
if ($this->mode != 'ctr') { |
||||
$plaintext = $this->_pad($plaintext); |
||||
} |
||||
|
||||
$ciphertext = mcrypt_generic($this->enmcrypt, $plaintext); |
||||
|
||||
if (!$this->continuousBuffer) { |
||||
mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv); |
||||
} |
||||
|
||||
return $ciphertext; |
||||
} |
||||
|
||||
return parent::encrypt($plaintext); |
||||
} |
||||
|
||||
/** |
||||
* Decrypts a message. |
||||
* |
||||
* If strlen($ciphertext) is not a multiple of 16, null bytes will be added to the end of the string until it is. |
||||
* |
||||
* @see Crypt_AES::encrypt() |
||||
* @access public |
||||
* @param String $ciphertext |
||||
*/ |
||||
function decrypt($ciphertext) |
||||
{ |
||||
if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) { |
||||
$this->_mcryptSetup(); |
||||
/* |
||||
if ($this->mode == CRYPT_AES_MODE_CTR) { |
||||
$iv = $this->decryptIV; |
||||
$xor = mcrypt_generic($this->enmcrypt, $this->_generate_xor(strlen($ciphertext), $iv)); |
||||
$plaintext = $ciphertext ^ $xor; |
||||
if ($this->continuousBuffer) { |
||||
$this->decryptIV = $iv; |
||||
} |
||||
return $plaintext; |
||||
} |
||||
*/ |
||||
|
||||
if ($this->mode != 'ctr') { |
||||
// we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic : |
||||
// "The data is padded with "\0" to make sure the length of the data is n * blocksize." |
||||
$ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 15) & 0xFFFFFFF0, chr(0)); |
||||
} |
||||
|
||||
$plaintext = mdecrypt_generic($this->demcrypt, $ciphertext); |
||||
|
||||
if (!$this->continuousBuffer) { |
||||
mcrypt_generic_init($this->demcrypt, $this->key, $this->iv); |
||||
} |
||||
|
||||
return $this->mode != 'ctr' ? $this->_unpad($plaintext) : $plaintext; |
||||
} |
||||
|
||||
return parent::decrypt($ciphertext); |
||||
} |
||||
|
||||
/** |
||||
* Setup mcrypt |
||||
* |
||||
* Validates all the variables. |
||||
* |
||||
* @access private |
||||
*/ |
||||
function _mcryptSetup() |
||||
{ |
||||
if (!$this->changed) { |
||||
return; |
||||
} |
||||
|
||||
if (!$this->explicit_key_length) { |
||||
// this just copied from Crypt_Rijndael::_setup() |
||||
$length = strlen($this->key) >> 2; |
||||
if ($length > 8) { |
||||
$length = 8; |
||||
} else if ($length < 4) { |
||||
$length = 4; |
||||
} |
||||
$this->Nk = $length; |
||||
$this->key_size = $length << 2; |
||||
} |
||||
|
||||
switch ($this->Nk) { |
||||
case 4: // 128 |
||||
$this->key_size = 16; |
||||
break; |
||||
case 5: // 160 |
||||
case 6: // 192 |
||||
$this->key_size = 24; |
||||
break; |
||||
case 7: // 224 |
||||
case 8: // 256 |
||||
$this->key_size = 32; |
||||
} |
||||
|
||||
$this->key = substr($this->key, 0, $this->key_size); |
||||
$this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($this->iv, 0, 16), 16, chr(0)); |
||||
|
||||
if (!isset($this->enmcrypt)) { |
||||
$mode = $this->mode; |
||||
//$mode = $this->mode == CRYPT_AES_MODE_CTR ? MCRYPT_MODE_ECB : $this->mode; |
||||
|
||||
$this->demcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, ''); |
||||
$this->enmcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, ''); |
||||
} // else should mcrypt_generic_deinit be called? |
||||
|
||||
mcrypt_generic_init($this->demcrypt, $this->key, $this->iv); |
||||
mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv); |
||||
|
||||
$this->changed = false; |
||||
} |
||||
|
||||
/** |
||||
* Encrypts a block |
||||
* |
||||
* Optimized over Crypt_Rijndael's implementation by means of loop unrolling. |
||||
* |
||||
* @see Crypt_Rijndael::_encryptBlock() |
||||
* @access private |
||||
* @param String $in |
||||
* @return String |
||||
*/ |
||||
function _encryptBlock($in) |
||||
{ |
||||
$state = unpack('N*word', $in); |
||||
|
||||
$Nr = $this->Nr; |
||||
$w = $this->w; |
||||
$t0 = $this->t0; |
||||
$t1 = $this->t1; |
||||
$t2 = $this->t2; |
||||
$t3 = $this->t3; |
||||
|
||||
// addRoundKey and reindex $state |
||||
$state = array( |
||||
$state['word1'] ^ $w[0][0], |
||||
$state['word2'] ^ $w[0][1], |
||||
$state['word3'] ^ $w[0][2], |
||||
$state['word4'] ^ $w[0][3] |
||||
); |
||||
|
||||
// shiftRows + subWord + mixColumns + addRoundKey |
||||
// we could loop unroll this and use if statements to do more rounds as necessary, but, in my tests, that yields |
||||
// only a marginal improvement. since that also, imho, hinders the readability of the code, i've opted not to do it. |
||||
for ($round = 1; $round < $this->Nr; $round++) { |
||||
$state = array( |
||||
$t0[$state[0] & 0xFF000000] ^ $t1[$state[1] & 0x00FF0000] ^ $t2[$state[2] & 0x0000FF00] ^ $t3[$state[3] & 0x000000FF] ^ $w[$round][0], |
||||
$t0[$state[1] & 0xFF000000] ^ $t1[$state[2] & 0x00FF0000] ^ $t2[$state[3] & 0x0000FF00] ^ $t3[$state[0] & 0x000000FF] ^ $w[$round][1], |
||||
$t0[$state[2] & 0xFF000000] ^ $t1[$state[3] & 0x00FF0000] ^ $t2[$state[0] & 0x0000FF00] ^ $t3[$state[1] & 0x000000FF] ^ $w[$round][2], |
||||
$t0[$state[3] & 0xFF000000] ^ $t1[$state[0] & 0x00FF0000] ^ $t2[$state[1] & 0x0000FF00] ^ $t3[$state[2] & 0x000000FF] ^ $w[$round][3] |
||||
); |
||||
|
||||
} |
||||
|
||||
// subWord |
||||
$state = array( |
||||
$this->_subWord($state[0]), |
||||
$this->_subWord($state[1]), |
||||
$this->_subWord($state[2]), |
||||
$this->_subWord($state[3]) |
||||
); |
||||
|
||||
// shiftRows + addRoundKey |
||||
$state = array( |
||||
($state[0] & 0xFF000000) ^ ($state[1] & 0x00FF0000) ^ ($state[2] & 0x0000FF00) ^ ($state[3] & 0x000000FF) ^ $this->w[$this->Nr][0], |
||||
($state[1] & 0xFF000000) ^ ($state[2] & 0x00FF0000) ^ ($state[3] & 0x0000FF00) ^ ($state[0] & 0x000000FF) ^ $this->w[$this->Nr][1], |
||||
($state[2] & 0xFF000000) ^ ($state[3] & 0x00FF0000) ^ ($state[0] & 0x0000FF00) ^ ($state[1] & 0x000000FF) ^ $this->w[$this->Nr][2], |
||||
($state[3] & 0xFF000000) ^ ($state[0] & 0x00FF0000) ^ ($state[1] & 0x0000FF00) ^ ($state[2] & 0x000000FF) ^ $this->w[$this->Nr][3] |
||||
); |
||||
|
||||
return pack('N*', $state[0], $state[1], $state[2], $state[3]); |
||||
} |
||||
|
||||
/** |
||||
* Decrypts a block |
||||
* |
||||
* Optimized over Crypt_Rijndael's implementation by means of loop unrolling. |
||||
* |
||||
* @see Crypt_Rijndael::_decryptBlock() |
||||
* @access private |
||||
* @param String $in |
||||
* @return String |
||||
*/ |
||||
function _decryptBlock($in) |
||||
{ |
||||
$state = unpack('N*word', $in); |
||||
|
||||
$Nr = $this->Nr; |
||||
$dw = $this->dw; |
||||
$dt0 = $this->dt0; |
||||
$dt1 = $this->dt1; |
||||
$dt2 = $this->dt2; |
||||
$dt3 = $this->dt3; |
||||
|
||||
// addRoundKey and reindex $state |
||||
$state = array( |
||||
$state['word1'] ^ $dw[$this->Nr][0], |
||||
$state['word2'] ^ $dw[$this->Nr][1], |
||||
$state['word3'] ^ $dw[$this->Nr][2], |
||||
$state['word4'] ^ $dw[$this->Nr][3] |
||||
); |
||||
|
||||
|
||||
// invShiftRows + invSubBytes + invMixColumns + addRoundKey |
||||
for ($round = $this->Nr - 1; $round > 0; $round--) { |
||||
$state = array( |
||||
$dt0[$state[0] & 0xFF000000] ^ $dt1[$state[3] & 0x00FF0000] ^ $dt2[$state[2] & 0x0000FF00] ^ $dt3[$state[1] & 0x000000FF] ^ $dw[$round][0], |
||||
$dt0[$state[1] & 0xFF000000] ^ $dt1[$state[0] & 0x00FF0000] ^ $dt2[$state[3] & 0x0000FF00] ^ $dt3[$state[2] & 0x000000FF] ^ $dw[$round][1], |
||||
$dt0[$state[2] & 0xFF000000] ^ $dt1[$state[1] & 0x00FF0000] ^ $dt2[$state[0] & 0x0000FF00] ^ $dt3[$state[3] & 0x000000FF] ^ $dw[$round][2], |
||||
$dt0[$state[3] & 0xFF000000] ^ $dt1[$state[2] & 0x00FF0000] ^ $dt2[$state[1] & 0x0000FF00] ^ $dt3[$state[0] & 0x000000FF] ^ $dw[$round][3] |
||||
); |
||||
} |
||||
|
||||
// invShiftRows + invSubWord + addRoundKey |
||||
$state = array( |
||||
$this->_invSubWord(($state[0] & 0xFF000000) ^ ($state[3] & 0x00FF0000) ^ ($state[2] & 0x0000FF00) ^ ($state[1] & 0x000000FF)) ^ $dw[0][0], |
||||
$this->_invSubWord(($state[1] & 0xFF000000) ^ ($state[0] & 0x00FF0000) ^ ($state[3] & 0x0000FF00) ^ ($state[2] & 0x000000FF)) ^ $dw[0][1], |
||||
$this->_invSubWord(($state[2] & 0xFF000000) ^ ($state[1] & 0x00FF0000) ^ ($state[0] & 0x0000FF00) ^ ($state[3] & 0x000000FF)) ^ $dw[0][2], |
||||
$this->_invSubWord(($state[3] & 0xFF000000) ^ ($state[2] & 0x00FF0000) ^ ($state[1] & 0x0000FF00) ^ ($state[0] & 0x000000FF)) ^ $dw[0][3] |
||||
); |
||||
|
||||
return pack('N*', $state[0], $state[1], $state[2], $state[3]); |
||||
} |
||||
} |
||||
|
||||
// vim: ts=4:sw=4:et: |
||||
// vim6: fdl=1: |
@ -1,945 +0,0 @@
|
||||
<?php |
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
||||
|
||||
/** |
||||
* Pure-PHP implementation of DES. |
||||
* |
||||
* Uses mcrypt, if available, and an internal implementation, otherwise. |
||||
* |
||||
* PHP versions 4 and 5 |
||||
* |
||||
* Useful resources are as follows: |
||||
* |
||||
* - {@link http://en.wikipedia.org/wiki/DES_supplementary_material Wikipedia: DES supplementary material} |
||||
* - {@link http://www.itl.nist.gov/fipspubs/fip46-2.htm FIPS 46-2 - (DES), Data Encryption Standard} |
||||
* - {@link http://www.cs.eku.edu/faculty/styer/460/Encrypt/JS-DES.html JavaScript DES Example} |
||||
* |
||||
* Here's a short example of how to use this library: |
||||
* <code> |
||||
* <?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)); |
||||
* ?> |
||||
* </code> |
||||
* |
||||
* LICENSE: This library is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU Lesser General Public |
||||
* License as published by the Free Software Foundation; either |
||||
* version 2.1 of the License, or (at your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
* Lesser General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public |
||||
* License along with this library; if not, write to the Free Software |
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
||||
* MA 02111-1307 USA |
||||
* |
||||
* @category Crypt |
||||
* @package Crypt_DES |
||||
* @author Jim Wigginton <terrafrost@php.net> |
||||
* @copyright MMVII Jim Wigginton |
||||
* @license http://www.gnu.org/licenses/lgpl.txt |
||||
* @version $Id: DES.php,v 1.12 2010/02/09 06:10:26 terrafrost Exp $ |
||||
* @link http://phpseclib.sourceforge.net |
||||
*/ |
||||
|
||||
/**#@+ |
||||
* @access private |
||||
* @see Crypt_DES::_prepareKey() |
||||
* @see Crypt_DES::_processBlock() |
||||
*/ |
||||
/** |
||||
* Contains array_reverse($keys[CRYPT_DES_DECRYPT]) |
||||
*/ |
||||
define('CRYPT_DES_ENCRYPT', 0); |
||||
/** |
||||
* Contains array_reverse($keys[CRYPT_DES_ENCRYPT]) |
||||
*/ |
||||
define('CRYPT_DES_DECRYPT', 1); |
||||
/**#@-*/ |
||||
|
||||
/**#@+ |
||||
* @access public |
||||
* @see Crypt_DES::encrypt() |
||||
* @see Crypt_DES::decrypt() |
||||
*/ |
||||
/** |
||||
* Encrypt / decrypt using the Counter mode. |
||||
* |
||||
* Set to -1 since that's what Crypt/Random.php uses to index the CTR mode. |
||||
* |
||||
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 |
||||
*/ |
||||
define('CRYPT_DES_MODE_CTR', -1); |
||||
/** |
||||
* Encrypt / decrypt using the Electronic Code Book mode. |
||||
* |
||||
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29 |
||||
*/ |
||||
define('CRYPT_DES_MODE_ECB', 1); |
||||
/** |
||||
* Encrypt / decrypt using the Code Book Chaining mode. |
||||
* |
||||
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 |
||||
*/ |
||||
define('CRYPT_DES_MODE_CBC', 2); |
||||
/**#@-*/ |
||||
|
||||
/**#@+ |
||||
* @access private |
||||
* @see Crypt_DES::Crypt_DES() |
||||
*/ |
||||
/** |
||||
* Toggles the internal implementation |
||||
*/ |
||||
define('CRYPT_DES_MODE_INTERNAL', 1); |
||||
/** |
||||
* Toggles the mcrypt implementation |
||||
*/ |
||||
define('CRYPT_DES_MODE_MCRYPT', 2); |
||||
/**#@-*/ |
||||
|
||||
/** |
||||
* Pure-PHP implementation of DES. |
||||
* |
||||
* @author Jim Wigginton <terrafrost@php.net> |
||||
* @version 0.1.0 |
||||
* @access public |
||||
* @package Crypt_DES |
||||
*/ |
||||
class Crypt_DES { |
||||
/** |
||||
* The Key Schedule |
||||
* |
||||
* @see Crypt_DES::setKey() |
||||
* @var Array |
||||
* @access private |
||||
*/ |
||||
var $keys = "\0\0\0\0\0\0\0\0"; |
||||
|
||||
/** |
||||
* The Encryption Mode |
||||
* |
||||
* @see Crypt_DES::Crypt_DES() |
||||
* @var Integer |
||||
* @access private |
||||
*/ |
||||
var $mode; |
||||
|
||||
/** |
||||
* Continuous Buffer status |
||||
* |
||||
* @see Crypt_DES::enableContinuousBuffer() |
||||
* @var Boolean |
||||
* @access private |
||||
*/ |
||||
var $continuousBuffer = false; |
||||
|
||||
/** |
||||
* Padding status |
||||
* |
||||
* @see Crypt_DES::enablePadding() |
||||
* @var Boolean |
||||
* @access private |
||||
*/ |
||||
var $padding = true; |
||||
|
||||
/** |
||||
* The Initialization Vector |
||||
* |
||||
* @see Crypt_DES::setIV() |
||||
* @var String |
||||
* @access private |
||||
*/ |
||||
var $iv = "\0\0\0\0\0\0\0\0"; |
||||
|
||||
/** |
||||
* A "sliding" Initialization Vector |
||||
* |
||||
* @see Crypt_DES::enableContinuousBuffer() |
||||
* @var String |
||||
* @access private |
||||
*/ |
||||
var $encryptIV = "\0\0\0\0\0\0\0\0"; |
||||
|
||||
/** |
||||
* A "sliding" Initialization Vector |
||||
* |
||||
* @see Crypt_DES::enableContinuousBuffer() |
||||
* @var String |
||||
* @access private |
||||
*/ |
||||
var $decryptIV = "\0\0\0\0\0\0\0\0"; |
||||
|
||||
/** |
||||
* mcrypt resource for encryption |
||||
* |
||||
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once. |
||||
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. |
||||
* |
||||
* @see Crypt_AES::encrypt() |
||||
* @var String |
||||
* @access private |
||||
*/ |
||||
var $enmcrypt; |
||||
|
||||
/** |
||||
* mcrypt resource for decryption |
||||
* |
||||
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once. |
||||
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. |
||||
* |
||||
* @see Crypt_AES::decrypt() |
||||
* @var String |
||||
* @access private |
||||
*/ |
||||
var $demcrypt; |
||||
|
||||
/** |
||||
* Does the (en|de)mcrypt resource need to be (re)initialized? |
||||
* |
||||
* @see setKey() |
||||
* @see setIV() |
||||
* @var Boolean |
||||
* @access private |
||||
*/ |
||||
var $changed = true; |
||||
|
||||
/** |
||||
* Default Constructor. |
||||
* |
||||
* Determines whether or not the mcrypt extension should be used. $mode should only, at present, be |
||||
* CRYPT_DES_MODE_ECB or CRYPT_DES_MODE_CBC. If not explictly set, CRYPT_DES_MODE_CBC will be used. |
||||
* |
||||
* @param optional Integer $mode |
||||
* @return Crypt_DES |
||||
* @access public |
||||
*/ |
||||
function Crypt_DES($mode = CRYPT_MODE_DES_CBC) |
||||
{ |
||||
if ( !defined('CRYPT_DES_MODE') ) { |
||||
switch (true) { |
||||
case extension_loaded('mcrypt'): |
||||
// i'd check to see if des was supported, by doing in_array('des', mcrypt_list_algorithms('')), |
||||
// but since that can be changed after the object has been created, there doesn't seem to be |
||||
// a lot of point... |
||||
define('CRYPT_DES_MODE', CRYPT_DES_MODE_MCRYPT); |
||||
break; |
||||
default: |
||||
define('CRYPT_DES_MODE', CRYPT_DES_MODE_INTERNAL); |
||||
} |
||||
} |
||||
|
||||
switch ( CRYPT_DES_MODE ) { |
||||
case CRYPT_DES_MODE_MCRYPT: |
||||
switch ($mode) { |
||||
case CRYPT_DES_MODE_ECB: |
||||
$this->mode = MCRYPT_MODE_ECB; |
||||
break; |
||||
case CRYPT_DES_MODE_CTR: |
||||
$this->mode = 'ctr'; |
||||
//$this->mode = in_array('ctr', mcrypt_list_modes()) ? 'ctr' : CRYPT_DES_MODE_CTR; |
||||
break; |
||||
case CRYPT_DES_MODE_CBC: |
||||
default: |
||||
$this->mode = MCRYPT_MODE_CBC; |
||||
} |
||||
|
||||
break; |
||||
default: |
||||
switch ($mode) { |
||||
case CRYPT_DES_MODE_ECB: |
||||
case CRYPT_DES_MODE_CTR: |
||||
case CRYPT_DES_MODE_CBC: |
||||
$this->mode = $mode; |
||||
break; |
||||
default: |
||||
$this->mode = CRYPT_DES_MODE_CBC; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Sets the key. |
||||
* |
||||
* Keys can be of any length. DES, itself, uses 64-bit keys (eg. strlen($key) == 8), however, we |
||||
* only use the first eight, if $key has more then eight characters in it, and pad $key with the |
||||
* null byte if it is less then eight characters long. |
||||
* |
||||
* DES also requires that every eighth bit be a parity bit, however, we'll ignore that. |
||||
* |
||||
* If the key is not explicitly set, it'll be assumed to be all zero's. |
||||
* |
||||
* @access public |
||||
* @param String $key |
||||
*/ |
||||
function setKey($key) |
||||
{ |
||||
$this->keys = ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) ? substr($key, 0, 8) : $this->_prepareKey($key); |
||||
$this->changed = true; |
||||
} |
||||
|
||||
/** |
||||
* Sets the initialization vector. (optional) |
||||
* |
||||
* SetIV is not required when CRYPT_DES_MODE_ECB is being used. If not explictly set, it'll be assumed |
||||
* to be all zero's. |
||||
* |
||||
* @access public |
||||
* @param String $iv |
||||
*/ |
||||
function setIV($iv) |
||||
{ |
||||
$this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, 8), 8, chr(0)); |
||||
$this->changed = true; |
||||
} |
||||
|
||||
/** |
||||
* Generate CTR XOR encryption key |
||||
* |
||||
* Encrypt the output of this and XOR it against the ciphertext / plaintext to get the |
||||
* plaintext / ciphertext in CTR mode. |
||||
* |
||||
* @see Crypt_DES::decrypt() |
||||
* @see Crypt_DES::encrypt() |
||||
* @access public |
||||
* @param Integer $length |
||||
* @param String $iv |
||||
*/ |
||||
function _generate_xor($length, &$iv) |
||||
{ |
||||
$xor = ''; |
||||
$num_blocks = ($length + 7) >> 3; |
||||
for ($i = 0; $i < $num_blocks; $i++) { |
||||
$xor.= $iv; |
||||
for ($j = 4; $j <= 8; $j+=4) { |
||||
$temp = substr($iv, -$j, 4); |
||||
switch ($temp) { |
||||
case "\xFF\xFF\xFF\xFF": |
||||
$iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4); |
||||
break; |
||||
case "\x7F\xFF\xFF\xFF": |
||||
$iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4); |
||||
break 2; |
||||
default: |
||||
extract(unpack('Ncount', $temp)); |
||||
$iv = substr_replace($iv, pack('N', $count + 1), -$j, 4); |
||||
break 2; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return $xor; |
||||
} |
||||
|
||||
/** |
||||
* Encrypts a message. |
||||
* |
||||
* $plaintext will be padded with up to 8 additional bytes. Other DES implementations may or may not pad in the |
||||
* same manner. Other common approaches to padding and the reasons why it's necessary are discussed in the following |
||||
* URL: |
||||
* |
||||
* {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html} |
||||
* |
||||
* An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does. |
||||
* strlen($plaintext) will still need to be a multiple of 8, however, arbitrary values can be added to make it that |
||||
* length. |
||||
* |
||||
* @see Crypt_DES::decrypt() |
||||
* @access public |
||||
* @param String $plaintext |
||||
*/ |
||||
function encrypt($plaintext) |
||||
{ |
||||
if ($this->mode != CRYPT_DES_MODE_CTR && $this->mode != 'ctr') { |
||||
$plaintext = $this->_pad($plaintext); |
||||
} |
||||
|
||||
if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) { |
||||
if ($this->changed) { |
||||
if (!isset($this->enmcrypt)) { |
||||
$this->enmcrypt = mcrypt_module_open(MCRYPT_DES, '', $this->mode, ''); |
||||
} |
||||
mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV); |
||||
$this->changed = false; |
||||
} |
||||
|
||||
$ciphertext = mcrypt_generic($this->enmcrypt, $plaintext); |
||||
|
||||
if (!$this->continuousBuffer) { |
||||
mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV); |
||||
} |
||||
|
||||
return $ciphertext; |
||||
} |
||||
|
||||
if (!is_array($this->keys)) { |
||||
$this->keys = $this->_prepareKey("\0\0\0\0\0\0\0\0"); |
||||
} |
||||
|
||||
$ciphertext = ''; |
||||
switch ($this->mode) { |
||||
case CRYPT_DES_MODE_ECB: |
||||
for ($i = 0; $i < strlen($plaintext); $i+=8) { |
||||
$ciphertext.= $this->_processBlock(substr($plaintext, $i, 8), CRYPT_DES_ENCRYPT); |
||||
} |
||||
break; |
||||
case CRYPT_DES_MODE_CBC: |
||||
$xor = $this->encryptIV; |
||||
for ($i = 0; $i < strlen($plaintext); $i+=8) { |
||||
$block = substr($plaintext, $i, 8); |
||||
$block = $this->_processBlock($block ^ $xor, CRYPT_DES_ENCRYPT); |
||||
$xor = $block; |
||||
$ciphertext.= $block; |
||||
} |
||||
if ($this->continuousBuffer) { |
||||
$this->encryptIV = $xor; |
||||
} |
||||
break; |
||||
case CRYPT_DES_MODE_CTR: |
||||
$xor = $this->encryptIV; |
||||
for ($i = 0; $i < strlen($plaintext); $i+=8) { |
||||
$block = substr($plaintext, $i, 8); |
||||
$key = $this->_processBlock($this->_generate_xor(8, $xor), CRYPT_DES_ENCRYPT); |
||||
$ciphertext.= $block ^ $key; |
||||
} |
||||
if ($this->continuousBuffer) { |
||||
$this->encryptIV = $xor; |
||||
} |
||||
} |
||||
|
||||
return $ciphertext; |
||||
} |
||||
|
||||
/** |
||||
* Decrypts a message. |
||||
* |
||||
* If strlen($ciphertext) is not a multiple of 8, null bytes will be added to the end of the string until it is. |
||||
* |
||||
* @see Crypt_DES::encrypt() |
||||
* @access public |
||||
* @param String $ciphertext |
||||
*/ |
||||
function decrypt($ciphertext) |
||||
{ |
||||
if ($this->mode != CRYPT_DES_MODE_CTR && $this->mode != 'ctr') { |
||||
// we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic : |
||||
// "The data is padded with "\0" to make sure the length of the data is n * blocksize." |
||||
$ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, chr(0)); |
||||
} |
||||
|
||||
if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) { |
||||
if ($this->changed) { |
||||
if (!isset($this->demcrypt)) { |
||||
$this->demcrypt = mcrypt_module_open(MCRYPT_DES, '', $this->mode, ''); |
||||
} |
||||
mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV); |
||||
$this->changed = false; |
||||
} |
||||
|
||||
$plaintext = mdecrypt_generic($this->demcrypt, $ciphertext); |
||||
|
||||
if (!$this->continuousBuffer) { |
||||
mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV); |
||||
} |
||||
|
||||
return $this->mode != 'ctr' ? $this->_unpad($plaintext) : $plaintext; |
||||
} |
||||
|
||||
if (!is_array($this->keys)) { |
||||
$this->keys = $this->_prepareKey("\0\0\0\0\0\0\0\0"); |
||||
} |
||||
|
||||
$plaintext = ''; |
||||
switch ($this->mode) { |
||||
case CRYPT_DES_MODE_ECB: |
||||
for ($i = 0; $i < strlen($ciphertext); $i+=8) { |
||||
$plaintext.= $this->_processBlock(substr($ciphertext, $i, 8), CRYPT_DES_DECRYPT); |
||||
} |
||||
break; |
||||
case CRYPT_DES_MODE_CBC: |
||||
$xor = $this->decryptIV; |
||||
for ($i = 0; $i < strlen($ciphertext); $i+=8) { |
||||
$block = substr($ciphertext, $i, 8); |
||||
$plaintext.= $this->_processBlock($block, CRYPT_DES_DECRYPT) ^ $xor; |
||||
$xor = $block; |
||||
} |
||||
if ($this->continuousBuffer) { |
||||
$this->decryptIV = $xor; |
||||
} |
||||
break; |
||||
case CRYPT_DES_MODE_CTR: |
||||
$xor = $this->decryptIV; |
||||
for ($i = 0; $i < strlen($ciphertext); $i+=8) { |
||||
$block = substr($ciphertext, $i, 8); |
||||
$key = $this->_processBlock($this->_generate_xor(8, $xor), CRYPT_DES_ENCRYPT); |
||||
$plaintext.= $block ^ $key; |
||||
} |
||||
if ($this->continuousBuffer) { |
||||
$this->decryptIV = $xor; |
||||
} |
||||
} |
||||
|
||||
return $this->mode != CRYPT_DES_MODE_CTR ? $this->_unpad($plaintext) : $plaintext; |
||||
} |
||||
|
||||
/** |
||||
* Treat consecutive "packets" as if they are a continuous buffer. |
||||
* |
||||
* Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets |
||||
* will yield different outputs: |
||||
* |
||||
* <code> |
||||
* echo $des->encrypt(substr($plaintext, 0, 8)); |
||||
* echo $des->encrypt(substr($plaintext, 8, 8)); |
||||
* </code> |
||||
* <code> |
||||
* echo $des->encrypt($plaintext); |
||||
* </code> |
||||
* |
||||
* The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates |
||||
* another, as demonstrated with the following: |
||||
* |
||||
* <code> |
||||
* $des->encrypt(substr($plaintext, 0, 8)); |
||||
* echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8))); |
||||
* </code> |
||||
* <code> |
||||
* echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8))); |
||||
* </code> |
||||
* |
||||
* 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. |
||||
* |
||||
* @see Crypt_DES::disableContinuousBuffer() |
||||
* @access public |
||||
*/ |
||||
function enableContinuousBuffer() |
||||
{ |
||||
$this->continuousBuffer = true; |
||||
} |
||||
|
||||
/** |
||||
* Treat consecutive packets as if they are a discontinuous buffer. |
||||
* |
||||
* The default behavior. |
||||
* |
||||
* @see Crypt_DES::enableContinuousBuffer() |
||||
* @access public |
||||
*/ |
||||
function disableContinuousBuffer() |
||||
{ |
||||
$this->continuousBuffer = false; |
||||
$this->encryptIV = $this->iv; |
||||
$this->decryptIV = $this->iv; |
||||
} |
||||
|
||||
/** |
||||
* Pad "packets". |
||||
* |
||||
* DES works by encrypting eight bytes at a time. If you ever need to encrypt or decrypt something that's not |
||||
* a multiple of eight, it becomes necessary to pad the input so that it's length is a multiple of eight. |
||||
* |
||||
* Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH1, |
||||
* where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping |
||||
* away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is |
||||
* transmitted separately) |
||||
* |
||||
* @see Crypt_DES::disablePadding() |
||||
* @access public |
||||
*/ |
||||
function enablePadding() |
||||
{ |
||||
$this->padding = true; |
||||
} |
||||
|
||||
/** |
||||
* Do not pad packets. |
||||
* |
||||
* @see Crypt_DES::enablePadding() |
||||
* @access public |
||||
*/ |
||||
function disablePadding() |
||||
{ |
||||
$this->padding = false; |
||||
} |
||||
|
||||
/** |
||||
* Pads a string |
||||
* |
||||
* Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize (8). |
||||
* 8 - (strlen($text) & 7) bytes are added, each of which is equal to chr(8 - (strlen($text) & 7) |
||||
* |
||||
* If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless |
||||
* and padding will, hence forth, be enabled. |
||||
* |
||||
* @see Crypt_DES::_unpad() |
||||
* @access private |
||||
*/ |
||||
function _pad($text) |
||||
{ |
||||
$length = strlen($text); |
||||
|
||||
if (!$this->padding) { |
||||
if (($length & 7) == 0) { |
||||
return $text; |
||||
} else { |
||||
user_error("The plaintext's length ($length) is not a multiple of the block size (8)", E_USER_NOTICE); |
||||
$this->padding = true; |
||||
} |
||||
} |
||||
|
||||
$pad = 8 - ($length & 7); |
||||
return str_pad($text, $length + $pad, chr($pad)); |
||||
} |
||||
|
||||
/** |
||||
* Unpads a string |
||||
* |
||||
* If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong |
||||
* and false will be returned. |
||||
* |
||||
* @see Crypt_DES::_pad() |
||||
* @access private |
||||
*/ |
||||
function _unpad($text) |
||||
{ |
||||
if (!$this->padding) { |
||||
return $text; |
||||
} |
||||
|
||||
$length = ord($text[strlen($text) - 1]); |
||||
|
||||
if (!$length || $length > 8) { |
||||
return false; |
||||
} |
||||
|
||||
return substr($text, 0, -$length); |
||||
} |
||||
|
||||
/** |
||||
* Encrypts or decrypts a 64-bit block |
||||
* |
||||
* $mode should be either CRYPT_DES_ENCRYPT or CRYPT_DES_DECRYPT. See |
||||
* {@link http://en.wikipedia.org/wiki/Image:Feistel.png Feistel.png} to get a general |
||||
* idea of what this function does. |
||||
* |
||||
* @access private |
||||
* @param String $block |
||||
* @param Integer $mode |
||||
* @return String |
||||
*/ |
||||
function _processBlock($block, $mode) |
||||
{ |
||||
// s-boxes. in the official DES docs, they're described as being matrices that |
||||
// one accesses by using the first and last bits to determine the row and the |
||||
// middle four bits to determine the column. in this implementation, they've |
||||
// been converted to vectors |
||||
static $sbox = array( |
||||
array( |
||||
14, 0, 4, 15, 13, 7, 1, 4, 2, 14, 15, 2, 11, 13, 8, 1, |
||||
3, 10 ,10, 6, 6, 12, 12, 11, 5, 9, 9, 5, 0, 3, 7, 8, |
||||
4, 15, 1, 12, 14, 8, 8, 2, 13, 4, 6, 9, 2, 1, 11, 7, |
||||
15, 5, 12, 11, 9, 3, 7, 14, 3, 10, 10, 0, 5, 6, 0, 13 |
||||
), |
||||
array( |
||||
15, 3, 1, 13, 8, 4, 14, 7, 6, 15, 11, 2, 3, 8, 4, 14, |
||||
9, 12, 7, 0, 2, 1, 13, 10, 12, 6, 0, 9, 5, 11, 10, 5, |
||||
0, 13, 14, 8, 7, 10, 11, 1, 10, 3, 4, 15, 13, 4, 1, 2, |
||||
5, 11, 8, 6, 12, 7, 6, 12, 9, 0, 3, 5, 2, 14, 15, 9 |
||||
), |
||||
array( |
||||
10, 13, 0, 7, 9, 0, 14, 9, 6, 3, 3, 4, 15, 6, 5, 10, |
||||
1, 2, 13, 8, 12, 5, 7, 14, 11, 12, 4, 11, 2, 15, 8, 1, |
||||
13, 1, 6, 10, 4, 13, 9, 0, 8, 6, 15, 9, 3, 8, 0, 7, |
||||
11, 4, 1, 15, 2, 14, 12, 3, 5, 11, 10, 5, 14, 2, 7, 12 |
||||
), |
||||
array( |
||||
7, 13, 13, 8, 14, 11, 3, 5, 0, 6, 6, 15, 9, 0, 10, 3, |
||||
1, 4, 2, 7, 8, 2, 5, 12, 11, 1, 12, 10, 4, 14, 15, 9, |
||||
10, 3, 6, 15, 9, 0, 0, 6, 12, 10, 11, 1, 7, 13, 13, 8, |
||||