Created
August 20, 2012 18:09
-
-
Save stephenh1988/3406260 to your computer and use it in GitHub Desktop.
PHP Implementation of AES-CBC
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* An implementation of the AES cipher (CBC mode). | |
* For reference http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf | |
* | |
* @author Stephen Harris ([email protected]) | |
* @license GPL | |
* | |
* Example usage: | |
* <code> | |
* <?php | |
* include('/aes.php'); | |
* $aes = new SH_AES_Cipher(); | |
* | |
* $key = '0011223344556677'; 128/192/256 bits | |
* $plaintext = 'The quick brown fox jumped over the lazy cat'; | |
* $iv =''; //Random (unpredictable!) IV 128 bits. | |
* | |
* $ciphertext = $aes->encrypt($plaintext,$key,$iv); | |
* $original =$aes->decrypt($ciphertext,$key,$iv); | |
* ?> | |
* </code> | |
*/ | |
class SH_AES_Cipher{ | |
/** | |
* Generated key schedule | |
*/ | |
private $key_schedule; | |
/** | |
* The size of the blocks (in bytes), in which to break up the plain/cipher text | |
*/ | |
private $block_size; | |
/** | |
* Set's up encryption constants (number of rounds, the key length in 32-bit words, blocksize) | |
*/ | |
function setup($key){ | |
$length = strlen($key); //Number of bytes | |
$key_bits = $length*8; | |
$this->num_k = $length >> 2; //Number of 32-bit words | |
$this->block_size =16; //Blocks are always 128-bites (16 bytes) | |
$this->num_b = 4; //Block length (in bits) divided by 32 | |
switch( $this->num_k ){ | |
case 4: | |
$this->rounds = 10; | |
break; | |
case 6: | |
$this->rounds = 12; | |
break; | |
case 8: | |
$this->rounds = 14; | |
break; | |
} | |
} | |
/** | |
* The encryption method | |
* @param $plaintext (string) - the text to be encrypted | |
* @param $key (string) - the key to be used. This should be 128/192/256 bits in size. This should be kept secret. | |
* @param $iv (string) - the initialisation vector. This should be 128/192/256 bits in size. This should be stored with the encrypted text for | |
* use in deciphering. This must be unpredictable! | |
*/ | |
function encrypt( $plaintext, $key, $iv,$mac_key){ | |
//Set up cipher | |
$this->setup($key); | |
//Pad plaintext so it fills block | |
$plaintext = $this->pad($plaintext); | |
//Create MAC | |
$plaintext .= hash_hmac('md5',$plaintext,$mac_key); | |
$ciphertext = ''; | |
//Split the plaintext into blocks | |
$blocks = str_split($plaintext, $this->block_size); | |
$key = array_values(unpack('C*', $key)); //Array of bytes | |
$this->key_expansion($key); | |
$xor = array_values(unpack('C*',$iv)); | |
foreach ($blocks as $block){ | |
$block = array_values(unpack('C*', $block)); | |
for($i=0; $i< count($block); $i++){ | |
$block[$i] = $xor[$i]^$block[$i]; | |
} | |
$block = $this->encryptBlock($block); | |
foreach($block as $byte ) | |
$ciphertext .=pack('C', $byte); | |
$xor = array_values($block); | |
} | |
//Append IV to the beginning of the cipher text | |
return $iv.$ciphertext; | |
} | |
/** | |
* The decryption method | |
* @param $ciphertext (string) - the text to be decrypted | |
* @param $key (string) - the key to be used. This should be the same that was used for encryption. | |
* @param $iv (string) - the initialisation vector. This should be the same that was used for encryption. | |
*/ | |
function decrypt( $ciphertext, $key, $mac_key){ | |
//Set up cipher | |
$this->setup($key); | |
$plaintext = ''; | |
$hmac = ''; | |
//Split the ciphertext into blocks | |
$blocks = str_split($ciphertext, $this->block_size); | |
//Extract IV from the beginning of the cipher text | |
$iv = array_shift($blocks); | |
$key = array_values(unpack('C*', $key)); //Array of bytes | |
$this->key_expansion($key); | |
$xor = array_values(unpack('C*',$iv)); | |
foreach ($blocks as $index => $block){ | |
$block = array_values(unpack('C*', $block)); //Array of bytes | |
$dec_block = array_values($this->decryptBlock($block)); | |
for($i=0; $i<count($dec_block); $i++){ | |
$byte = $xor[$i]^$dec_block[$i]; | |
if( $index < count($blocks)-2 ){ | |
$plaintext .= pack('C', $byte); | |
}else{ | |
$hmac .= pack('C', $byte); | |
} | |
} | |
$xor = $block; | |
} | |
//Detect tampering | |
if( $hmac != hash_hmac('md5',$plaintext,$mac_key) ){ | |
return false; | |
} | |
//Unpad | |
$plaintext = $this->unpad($plaintext); | |
return $plaintext; | |
} | |
/** | |
* Encrypts a block of text. | |
* @param $block (array) - array of bytes (block to be encrypted) | |
* @return $block (array) - array of bytes (block encrypted) | |
*/ | |
function encryptBlock( $block ){ | |
/* Initial state */ | |
$state = $this->initial_state($block); | |
/* Initial add round key */ | |
$state = $this->add_round_key(0,$state); | |
/* The rounds */ | |
for ($i=0; $i < $this->rounds; $i++){ | |
//Byte Sub (S-box) See Sec. 5.1.1 | |
for ($r = 0; $r < 4; $r++) { | |
for ($c= 0; $c < $this->num_b; $c++) { | |
$state[$r][$c] = $this->sub_byte($state[$r][$c]); | |
} | |
} | |
// Shift Row - See Sec. 5.1.2 | |
$temp=array(); | |
for ($r = 0; $r < 4; $r++) { | |
for ($c= 0; $c < $this->num_b; $c++) { | |
$temp[$r][$c] = $state[$r][ ($c+$r)%$this->num_b ]; | |
} | |
} | |
$state = $temp; | |
//Mix Column See Sec. 5.1.3 | |
if( $i != $this->rounds-1 ){ | |
for ($c= 0; $c < $this->num_b; $c++) { | |
$column =array(); | |
for ($r = 0; $r < 4; $r++) | |
$column[$r] = $state[$r][$c]; | |
$column = $this->mix_column($column); | |
for ($r = 0; $r < 4; $r++) | |
$state[$r][$c] = $column[$r]; | |
} | |
} | |
// Add Round Key | |
$state = $this->add_round_key($i+1,$state); | |
} | |
/* Flatten state and return*/ | |
return $this->flatten_state($state); | |
} | |
/** | |
* Decrypts a block of text. | |
* @param $block (array) - array of bytes (block to be decrypted) | |
* @return $block (array) - array of bytes (block decrypted) | |
*/ | |
function decryptBlock( $block ){ | |
/* Initial state */ | |
$state = $this->initial_state($block); | |
// Add Round Key | |
$state = $this->add_round_key($this->rounds,$state); | |
/* The rounds */ | |
for ($i=$this->rounds-1; $i >-1; $i--){ | |
// Inverse Shift Row | |
$temp=array(); | |
for ($r = 0; $r < 4; $r++) { | |
for ($c= 0; $c < $this->num_b; $c++) { | |
$temp[$r][$c] = $state[$r][ ($c+4-$r)%$this->num_b ]; | |
} | |
} | |
$state = $temp; | |
//Inverse Byte Sub (S-box) See Sec. 5.1.1 | |
for ($r = 0; $r < 4; $r++) { | |
for ($c= 0; $c < $this->num_b; $c++) { | |
$state[$r][$c] = $this->inverse_sub_byte($state[$r][$c]); | |
} | |
} | |
// Add Round Key | |
$state = $this->add_round_key($i,$state); | |
//Inverse Mix Column See Sec. 5.1.3 | |
if( $i !=0 ){ | |
for ($c= 0; $c < $this->num_b; $c++) { | |
$column =array(); | |
for ($r = 0; $r < 4; $r++) { | |
$column[$r] = $state[$r][$c]; | |
} | |
$column = $this->inverse_mix_column($column); | |
for ($r = 0; $r < 4; $r++) { | |
$state[$r][$c] = $column[$r]; | |
} | |
} | |
} | |
} | |
/* Flatten state and return*/ | |
return $this->flatten_state($state); | |
} | |
/** | |
* Used in encryptBlock and decryptBlock | |
* Initialises the state array using the recieved block | |
* @param (array) array of bytes for current block | |
* @return (array) initialised state | |
*/ | |
function initial_state($bytes){ | |
$state=array(); | |
for( $r=0; $r<4; $r++ ){ | |
for( $c= 0; $c < count($bytes)/4; $c++){ | |
$state[$r][$c] = $bytes[$r+4*$c]; | |
} | |
} | |
return $state; | |
} | |
/** | |
* Flattens the two dimensional state array into a one dimensional | |
* @param (array) current state | |
* @return (array) flattened state | |
*/ | |
function flatten_state($state){ | |
$flattened = array(); | |
for( $r=0; $r<4; $r++ ){ | |
for( $c= 0; $c < $this->num_b; $c++){ | |
$flattened[1+$r+4*$c] = $state[$c][$r]; | |
} | |
} | |
return $flattened; | |
} | |
/** | |
* Adds the key for a given round to the current state | |
* @param (array) current state | |
* @return (array) new state | |
*/ | |
function add_round_key($round, $state){ | |
for( $r=0; $r<4; $r++ ){ | |
for( $c= 0; $c < $this->num_b; $c++){ | |
$state[$r][$c] = $state[$r][$c] ^ $this->key_schedule[$c+4*($round)][$r]; | |
} | |
} | |
return $state; | |
} | |
/** | |
* Pads a text so that its length is a multiple of the block size. | |
* All content is padded. | |
* See http://tools.ietf.org/html/rfc5652#section-6.3 | |
* @param (string) text to be padded | |
* @return (string) padded text | |
*/ | |
function pad( $text='' ){ | |
$length = strlen($text); | |
$padding = $this->block_size - ($length % $this->block_size ); | |
$text = str_pad($text, $length + $padding, chr($padding) ); | |
return $text; | |
} | |
/** | |
* Unpads a text to restore it to its original length | |
* It only checks the last character. Padding is set to 16 if there is an error. | |
* @param (string) text to be unpadded | |
* @return (string) unpadded text | |
*/ | |
function unpad($text=''){ | |
$padded = (int) ord($text[strlen($text)-1]); | |
$padded = ($padded > 16 ? 16 : $padded); | |
return substr($text,0,strlen($text)-$padded); | |
} | |
/** | |
* Performs the mix_columns function. | |
* @param (array) a column (array of 4 bytes) | |
* @return (array) the column after the mix column matrix has been applied in GF. | |
*/ | |
function mix_column($col) { | |
$a = $col; | |
$b = array(); | |
$h=''; | |
/* The array 'a' is simply a copy of the input array 'r' | |
* The array 'b' is each element of the array 'a' multiplied by 2 in Rijndael's Galois field | |
* a[n] ^ b[n] is element n multiplied by 3 in Rijndael's Galois field */ | |
for($r=0;$r<4;$r++) { | |
$h = ($col[$r] >> 7); | |
$b[$r] = ($col[$r] << 1); | |
if($h) | |
$b[$r] ^= 0x11B; | |
} | |
$col[0] = $b[0] ^ $a[3] ^ $a[2] ^ $b[1] ^ $a[1]; /* 2 * a0 + a3 + a2 + 3 * a1 */ | |
$col[1] = $b[1] ^ $a[0] ^ $a[3] ^ $b[2] ^ $a[2]; /* 2 * a1 + a0 + a3 + 3 * a2 */ | |
$col[2] = $b[2] ^ $a[1] ^ $a[0] ^ $b[3] ^ $a[3]; /* 2 * a2 + a1 + a0 + 3 * a3 */ | |
$col[3] = $b[3] ^ $a[2] ^ $a[1] ^ $b[0] ^ $a[0]; /* 2 * a3 + a2 + a1 + 3 * a0 */ | |
return $col; | |
} | |
/** | |
* Performs the inverse mix_columns function. | |
* @param (array) a column (array of 4 bytes) | |
* @return (array) the column after the inverse mix column matrix has been applied in GF. | |
*/ | |
function inverse_mix_column($col){ | |
$gfx14 =array(0x00,0x0e,0x1c,0x12,0x38,0x36,0x24,0x2a,0x70,0x7e,0x6c,0x62,0x48,0x46,0x54,0x5a, | |
0xe0,0xee,0xfc,0xf2,0xd8,0xd6,0xc4,0xca,0x90,0x9e,0x8c,0x82,0xa8,0xa6,0xb4,0xba, | |
0xdb,0xd5,0xc7,0xc9,0xe3,0xed,0xff,0xf1,0xab,0xa5,0xb7,0xb9,0x93,0x9d,0x8f,0x81, | |
0x3b,0x35,0x27,0x29,0x03,0x0d,0x1f,0x11,0x4b,0x45,0x57,0x59,0x73,0x7d,0x6f,0x61, | |
0xad,0xa3,0xb1,0xbf,0x95,0x9b,0x89,0x87,0xdd,0xd3,0xc1,0xcf,0xe5,0xeb,0xf9,0xf7, | |
0x4d,0x43,0x51,0x5f,0x75,0x7b,0x69,0x67,0x3d,0x33,0x21,0x2f,0x05,0x0b,0x19,0x17, | |
0x76,0x78,0x6a,0x64,0x4e,0x40,0x52,0x5c,0x06,0x08,0x1a,0x14,0x3e,0x30,0x22,0x2c, | |
0x96,0x98,0x8a,0x84,0xae,0xa0,0xb2,0xbc,0xe6,0xe8,0xfa,0xf4,0xde,0xd0,0xc2,0xcc, | |
0x41,0x4f,0x5d,0x53,0x79,0x77,0x65,0x6b,0x31,0x3f,0x2d,0x23,0x09,0x07,0x15,0x1b, | |
0xa1,0xaf,0xbd,0xb3,0x99,0x97,0x85,0x8b,0xd1,0xdf,0xcd,0xc3,0xe9,0xe7,0xf5,0xfb, | |
0x9a,0x94,0x86,0x88,0xa2,0xac,0xbe,0xb0,0xea,0xe4,0xf6,0xf8,0xd2,0xdc,0xce,0xc0, | |
0x7a,0x74,0x66,0x68,0x42,0x4c,0x5e,0x50,0x0a,0x04,0x16,0x18,0x32,0x3c,0x2e,0x20, | |
0xec,0xe2,0xf0,0xfe,0xd4,0xda,0xc8,0xc6,0x9c,0x92,0x80,0x8e,0xa4,0xaa,0xb8,0xb6, | |
0x0c,0x02,0x10,0x1e,0x34,0x3a,0x28,0x26,0x7c,0x72,0x60,0x6e,0x44,0x4a,0x58,0x56, | |
0x37,0x39,0x2b,0x25,0x0f,0x01,0x13,0x1d,0x47,0x49,0x5b,0x55,0x7f,0x71,0x63,0x6d, | |
0xd7,0xd9,0xcb,0xc5,0xef,0xe1,0xf3,0xfd,0xa7,0xa9,0xbb,0xb5,0x9f,0x91,0x83,0x8d); | |
$gfx13 =array(0x00,0x0d,0x1a,0x17,0x34,0x39,0x2e,0x23,0x68,0x65,0x72,0x7f,0x5c,0x51,0x46,0x4b, | |
0xd0,0xdd,0xca,0xc7,0xe4,0xe9,0xfe,0xf3,0xb8,0xb5,0xa2,0xaf,0x8c,0x81,0x96,0x9b, | |
0xbb,0xb6,0xa1,0xac,0x8f,0x82,0x95,0x98,0xd3,0xde,0xc9,0xc4,0xe7,0xea,0xfd,0xf0, | |
0x6b,0x66,0x71,0x7c,0x5f,0x52,0x45,0x48,0x03,0x0e,0x19,0x14,0x37,0x3a,0x2d,0x20, | |
0x6d,0x60,0x77,0x7a,0x59,0x54,0x43,0x4e,0x05,0x08,0x1f,0x12,0x31,0x3c,0x2b,0x26, | |
0xbd,0xb0,0xa7,0xaa,0x89,0x84,0x93,0x9e,0xd5,0xd8,0xcf,0xc2,0xe1,0xec,0xfb,0xf6, | |
0xd6,0xdb,0xcc,0xc1,0xe2,0xef,0xf8,0xf5,0xbe,0xb3,0xa4,0xa9,0x8a,0x87,0x90,0x9d, | |
0x06,0x0b,0x1c,0x11,0x32,0x3f,0x28,0x25,0x6e,0x63,0x74,0x79,0x5a,0x57,0x40,0x4d, | |
0xda,0xd7,0xc0,0xcd,0xee,0xe3,0xf4,0xf9,0xb2,0xbf,0xa8,0xa5,0x86,0x8b,0x9c,0x91, | |
0x0a,0x07,0x10,0x1d,0x3e,0x33,0x24,0x29,0x62,0x6f,0x78,0x75,0x56,0x5b,0x4c,0x41, | |
0x61,0x6c,0x7b,0x76,0x55,0x58,0x4f,0x42,0x09,0x04,0x13,0x1e,0x3d,0x30,0x27,0x2a, | |
0xb1,0xbc,0xab,0xa6,0x85,0x88,0x9f,0x92,0xd9,0xd4,0xc3,0xce,0xed,0xe0,0xf7,0xfa, | |
0xb7,0xba,0xad,0xa0,0x83,0x8e,0x99,0x94,0xdf,0xd2,0xc5,0xc8,0xeb,0xe6,0xf1,0xfc, | |
0x67,0x6a,0x7d,0x70,0x53,0x5e,0x49,0x44,0x0f,0x02,0x15,0x18,0x3b,0x36,0x21,0x2c, | |
0x0c,0x01,0x16,0x1b,0x38,0x35,0x22,0x2f,0x64,0x69,0x7e,0x73,0x50,0x5d,0x4a,0x47, | |
0xdc,0xd1,0xc6,0xcb,0xe8,0xe5,0xf2,0xff,0xb4,0xb9,0xae,0xa3,0x80,0x8d,0x9a,0x97); | |
$gfx11=array(0x00,0x0b,0x16,0x1d,0x2c,0x27,0x3a,0x31,0x58,0x53,0x4e,0x45,0x74,0x7f,0x62,0x69, | |
0xb0,0xbb,0xa6,0xad,0x9c,0x97,0x8a,0x81,0xe8,0xe3,0xfe,0xf5,0xc4,0xcf,0xd2,0xd9, | |
0x7b,0x70,0x6d,0x66,0x57,0x5c,0x41,0x4a,0x23,0x28,0x35,0x3e,0x0f,0x04,0x19,0x12, | |
0xcb,0xc0,0xdd,0xd6,0xe7,0xec,0xf1,0xfa,0x93,0x98,0x85,0x8e,0xbf,0xb4,0xa9,0xa2, | |
0xf6,0xfd,0xe0,0xeb,0xda,0xd1,0xcc,0xc7,0xae,0xa5,0xb8,0xb3,0x82,0x89,0x94,0x9f, | |
0x46,0x4d,0x50,0x5b,0x6a,0x61,0x7c,0x77,0x1e,0x15,0x08,0x03,0x32,0x39,0x24,0x2f, | |
0x8d,0x86,0x9b,0x90,0xa1,0xaa,0xb7,0xbc,0xd5,0xde,0xc3,0xc8,0xf9,0xf2,0xef,0xe4, | |
0x3d,0x36,0x2b,0x20,0x11,0x1a,0x07,0x0c,0x65,0x6e,0x73,0x78,0x49,0x42,0x5f,0x54, | |
0xf7,0xfc,0xe1,0xea,0xdb,0xd0,0xcd,0xc6,0xaf,0xa4,0xb9,0xb2,0x83,0x88,0x95,0x9e, | |
0x47,0x4c,0x51,0x5a,0x6b,0x60,0x7d,0x76,0x1f,0x14,0x09,0x02,0x33,0x38,0x25,0x2e, | |
0x8c,0x87,0x9a,0x91,0xa0,0xab,0xb6,0xbd,0xd4,0xdf,0xc2,0xc9,0xf8,0xf3,0xee,0xe5, | |
0x3c,0x37,0x2a,0x21,0x10,0x1b,0x06,0x0d,0x64,0x6f,0x72,0x79,0x48,0x43,0x5e,0x55, | |
0x01,0x0a,0x17,0x1c,0x2d,0x26,0x3b,0x30,0x59,0x52,0x4f,0x44,0x75,0x7e,0x63,0x68, | |
0xb1,0xba,0xa7,0xac,0x9d,0x96,0x8b,0x80,0xe9,0xe2,0xff,0xf4,0xc5,0xce,0xd3,0xd8, | |
0x7a,0x71,0x6c,0x67,0x56,0x5d,0x40,0x4b,0x22,0x29,0x34,0x3f,0x0e,0x05,0x18,0x13, | |
0xca,0xc1,0xdc,0xd7,0xe6,0xed,0xf0,0xfb,0x92,0x99,0x84,0x8f,0xbe,0xb5,0xa8,0xa3); | |
$gfx9 =array(0x00,0x09,0x12,0x1b,0x24,0x2d,0x36,0x3f,0x48,0x41,0x5a,0x53,0x6c,0x65,0x7e,0x77, | |
0x90,0x99,0x82,0x8b,0xb4,0xbd,0xa6,0xaf,0xd8,0xd1,0xca,0xc3,0xfc,0xf5,0xee,0xe7, | |
0x3b,0x32,0x29,0x20,0x1f,0x16,0x0d,0x04,0x73,0x7a,0x61,0x68,0x57,0x5e,0x45,0x4c, | |
0xab,0xa2,0xb9,0xb0,0x8f,0x86,0x9d,0x94,0xe3,0xea,0xf1,0xf8,0xc7,0xce,0xd5,0xdc, | |
0x76,0x7f,0x64,0x6d,0x52,0x5b,0x40,0x49,0x3e,0x37,0x2c,0x25,0x1a,0x13,0x08,0x01, | |
0xe6,0xef,0xf4,0xfd,0xc2,0xcb,0xd0,0xd9,0xae,0xa7,0xbc,0xb5,0x8a,0x83,0x98,0x91, | |
0x4d,0x44,0x5f,0x56,0x69,0x60,0x7b,0x72,0x05,0x0c,0x17,0x1e,0x21,0x28,0x33,0x3a, | |
0xdd,0xd4,0xcf,0xc6,0xf9,0xf0,0xeb,0xe2,0x95,0x9c,0x87,0x8e,0xb1,0xb8,0xa3,0xaa, | |
0xec,0xe5,0xfe,0xf7,0xc8,0xc1,0xda,0xd3,0xa4,0xad,0xb6,0xbf,0x80,0x89,0x92,0x9b, | |
0x7c,0x75,0x6e,0x67,0x58,0x51,0x4a,0x43,0x34,0x3d,0x26,0x2f,0x10,0x19,0x02,0x0b, | |
0xd7,0xde,0xc5,0xcc,0xf3,0xfa,0xe1,0xe8,0x9f,0x96,0x8d,0x84,0xbb,0xb2,0xa9,0xa0, | |
0x47,0x4e,0x55,0x5c,0x63,0x6a,0x71,0x78,0x0f,0x06,0x1d,0x14,0x2b,0x22,0x39,0x30, | |
0x9a,0x93,0x88,0x81,0xbe,0xb7,0xac,0xa5,0xd2,0xdb,0xc0,0xc9,0xf6,0xff,0xe4,0xed, | |
0x0a,0x03,0x18,0x11,0x2e,0x27,0x3c,0x35,0x42,0x4b,0x50,0x59,0x66,0x6f,0x74,0x7d, | |
0xa1,0xa8,0xb3,0xba,0x85,0x8c,0x97,0x9e,0xe9,0xe0,0xfb,0xf2,0xcd,0xc4,0xdf,0xd6, | |
0x31,0x38,0x23,0x2a,0x15,0x1c,0x07,0x0e,0x79,0x70,0x6b,0x62,0x5d,0x54,0x4f,0x46); | |
$_col=array(); | |
$_col[0] = $gfx14[$col[0]] ^ $gfx11[$col[1]] ^ $gfx13[$col[2]]^ $gfx9[$col[3]]; | |
$_col[1] = $gfx9[$col[0]] ^ $gfx14[$col[1]] ^ $gfx11[$col[2]]^ $gfx13[$col[3]]; | |
$_col[2] = $gfx13[$col[0]] ^ $gfx9[$col[1]] ^ $gfx14[$col[2]]^ $gfx11[$col[3]]; | |
$_col[3] = $gfx11[$col[0]] ^ $gfx13[$col[1]] ^ $gfx9[$col[2]]^ $gfx14[$col[3]]; | |
return $_col; | |
} | |
/** | |
* Generates the key schedule from the given key. | |
* @param (string) key | |
*/ | |
function key_expansion( $key =''){ | |
$this->key_schedule=array(); | |
for($i=0; $i < $this->num_k; $i++){ | |
$this->key_schedule[$i] = array($key[4*$i],$key[4*$i+1],$key[4*$i+2],$key[4*$i+3]); | |
} | |
$i = $this->num_k; | |
while ($i < $this->num_b * ($this->rounds+1) ){ | |
$word = $this->key_schedule[$i-1]; | |
if ($i % $this->num_k == 0){ | |
$word = $this->sub_word($this->rot_word($word)); | |
$rcon = $this->rcon($i/$this->num_k); | |
for($j=0; $j<4; $j++){ | |
$word[$j] = $word[$j]^$rcon[$j]; | |
} | |
}elseif ($this->num_k > 6 && $i % $this->num_k == 4){ | |
$word = $this->sub_word($word); | |
} | |
for($j=0; $j<4; $j++){ | |
$word[$j] = $word[$j]^$this->key_schedule[$i-$this->num_k][$j]; | |
} | |
$this->key_schedule[$i] = $word; | |
$i++; | |
} | |
} | |
/** | |
* 'Rotates' a word (array of 4 bytes) so that the first byte is shifted to the end. | |
* @param (array) array of 4 bytes | |
* @return (array) array of 4 bytes | |
*/ | |
function rot_word($word){ | |
$first = array_shift($word); | |
$word[] = $first; | |
return $word; | |
} | |
/** | |
* The input word (array of 4 bytes) is replaced by a another word, where each byte has been replaced using the substitution box | |
* @param (array) array of 4 bytes | |
* @return (array) array of 4 bytes | |
*/ | |
function sub_word($word){ | |
for( $i=0; $i<4; $i++ ){ | |
$word[$i] = $this->sub_byte($word[$i]); | |
} | |
return $word; | |
} | |
function rcon($i){ | |
$rcon = array( | |
0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, | |
0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, | |
0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, | |
0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, | |
0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, | |
0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, | |
0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, | |
0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, | |
0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, | |
0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, | |
0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, | |
0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, | |
0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, | |
0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, | |
0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, | |
0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d | |
); | |
return array($rcon[$i],0,0,0); | |
//$w = str_pad(dechex($rcon[$i]), 2,0,STR_PAD_LEFT); | |
//return str_pad($w, 8,0); | |
} | |
/** | |
* Acts as look-up array of the AES s-box | |
* The input byte (as a hex) is replaced with a SubByte using an 8-bit substitution box | |
* @param (byte) input byte | |
* @return (byte) substitued byte | |
*/ | |
function sub_byte( $hex ){ | |
$sbox = array( | |
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, | |
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, | |
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, | |
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, | |
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, | |
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, | |
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, | |
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, | |
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, | |
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, | |
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, | |
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, | |
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, | |
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, | |
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, | |
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 | |
); | |
return $sbox[$hex]; | |
} | |
/** | |
* Acts as look-up array of the inverse of the AES s-box | |
* The input byte (as a hex) is replaced with a SubByte using an 8-bit (inverse) substitution box | |
* @param (byte) input byte | |
* @return (byte) substitued byte | |
*/ | |
function inverse_sub_byte( $hex ){ | |
$invsbox = array( | |
0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, | |
0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, | |
0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, | |
0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, | |
0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, | |
0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, | |
0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, | |
0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, | |
0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, | |
0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, | |
0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, | |
0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, | |
0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, | |
0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, | |
0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, | |
0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D | |
); | |
return $invsbox[$hex]; | |
} | |
} | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi, this is the best simple one-file pure PHP aes-cbc implementation!
I needed something on PHP, compatible to JS, but without openssl or mcrypt, and this piece worked great.
Thank you!
Several suggestions: