10 var $Nb=4;//Número de columnas en el state (siempre 4) var $Nk=4;//Longitud de la clave 128b=>4 var $state=array(array()); var $shifts_r=array(array(0, 1, 2, 3),array(3, 0, 1, 2),array(2, 3, 0, 1),array(1, 2, 3, 0)); var $shifts_l=array(array(0, 1, 2, 3),array(1, 2, 3, 0),array(2, 3, 0, 1),array(3, 0, 1, 2)); var $debug=false; var $toHex=false; ////////////////////////////////////////////////////////////////////////////// // FUNCIONES INTERNAS ///////////////////////////////////////////////////////////////////////////// /** * Realiza una XOR entre S-box y la clave i-esima rk. * * @param rk Array de caracteres (4x4) con la clave i-esima */ private function KeyAddition($rk) { //Para cada ronda hacemos una XOR entre Sbox[i][j] y rk[round][i][j]. for($i = 0; $i < 4; $i++) for($j = 0; $j < $this->Nb; $j++) $this->state[$i][$j] ^= $rk[$i][$j]; } /** * Realiza las funciones SubBytes() y ShiftRow() como se define en fips-198 * */ private function ByteSubShiftRow(){ $tmp= array(array()); for($i = 0; $i < 4; $i++) for($j = 0; $j < $this->Nb; $j++) $tmp[$i][$this->shifts_r[$i][$j]]= $this->S[$this->state[$i][$j]]; $this->state=$tmp; } /** * Realiza las funciones MixColumn() y KeyAddition() como se define en fips-198. * * @param rk Array de caracteres (4x4) con la clave i-esima */ private function MixColumnKeyAddition($rk){ $b= array(array()); for($j = 0; $j < 4; $j++) for($i = 0; $i < $this->Nb; $i++){ $b[$i][$j] = $this->T2[$this->state[$i][$j]] ^ $this->T3[$this->state[($i + 1) % 4][$j]] ^ $this->state[($i + 2) % 4][$j] ^ $this->state[($i + 3) % 4][$j]; $b[$i][$j]^=$rk[$i][$j]; } $this->state = $b; } /** * Realiza la funcion inversa de MixColumn() * */ private function InvMixColumn() { $b= array(array()); for($j = 0; $j < 4; $j++) for($i = 0; $i < $this->Nb; $i++) $b[$i][$j] = $this->T14[$this->state[$i][$j]] ^ $this->T11[$this->state[($i + 1) % 4][$j]] ^ $this->T13[$this->state[($i + 2) % 4][$j]] ^ $this->T9[$this->state[($i + 3) % 4][$j]]; $this->state = $b; } /** * Realiza la funcion inversa de SubBytes() y ShiftRow(). * */ private function InvShiftRowInvByteSub(){ $tmp= array(array()); for($i = 0; $i < 4; $i++) for($j = 0; $j < $this->Nb; $j++) $tmp[$i][$this->shifts_l[$i][$j]]= $this->Si[$this->state[$i][$j]]; $this->state=$tmp; } ///////////////////////////////////////////////////////////////////////// // Funciones de cifrado ///////////////////////////////////////////////////////////////////////// /** * Constructor de la clase * * @param hex Si es verdadero devuelve los valores en hexadecimal * @param debug Si es verdadero muestra información de debug */ function __construct($hex=false, $debug=false){ $this->debug=$debug; $this->toHex=$hex; } /** * Crea la matriz de claves de cifrado. * * @param key Clave de cifrado longitud igual a 16 caracteres. * @return Matriz de claves para cifrar/descifrar. */ public function makeKey($hash){ $rconpocharer = 0; $tk=array(array());; $rk=array(array(array())); for($j = 0; $j < $this->Nk; $j++) for($i = 0; $i < 4; $i++) $tk[$i][$j] = ord($hash{$j*4+$i})>256 ? ord($hash{$j*4+$i})%256 : ord($hash{$j*4+$i}); $t = 0; for($j = 0; ($j < $this->Nk) && ($t < ($this->Nr+1)*$this->Nb); $j++, $t++) for($i = 0; $i < 4; $i++) $rk[$t / $this->Nb][$i][$t % $this->Nb] = $tk[$i][$j]; while ($t < ($this->Nr+1)*$this->Nb) { for($i = 0; $i < 4; $i++) $tk[$i][0] ^= $this->S[$tk[($i+1)%4][$this->Nk-1]]; $tk[0][0] ^= $this->rcon[$rconpocharer++]; for($j = 1; $j < $this->Nk; $j++) for($i = 0; $i < 4; $i++){ $tk[$i][$j] ^= $tk[$i][$j-1]; } for($j = 0; ($j < $this->Nk) && ($t < ($this->Nr+1)*$this->Nb); $j++, $t++) for($i = 0; $i < 4; $i++) { $rk[$t / $this->Nb][$i][$t % $this->Nb] = $tk[$i][$j]; } } return $rk; } /** * Realiza del cifrado de 1 bloque de datos (128 bits). * * @param in Datos a cifrar (longitud 128 bits). * @param keyin Array de claves de cifrado (generadas con makeKey()) * @return La cadena de datos cifrada. */ public function blockEncrypt($in, $key){ for ($i=0; $i<4; $i++){ for ($j=0; $j<$this->Nb; $j++){ $this->state[$j][$i]=ord($in{$i*4+$j}); } } $this->showInt("Cifrado:
State Inicial"); $this->KeyAddition($key[0]); $this->showInt("Ronda 0 :: KeyAddition"); for($r = 1; $r < $this->Nr; $r++) { $this->ByteSubShiftRow(); $this->showInt("Ronda $r :: ByteSubShiftRow"); $this->MixColumnKeyAddition($key[$r]); $this->showInt("Ronda $r :: MixColumnKeyAddition"); } $this->ByteSubShiftRow(); $this->showInt("Ronda final :: ByteSubShiftRow"); $this->KeyAddition($key[$this->Nr]); $this->showInt("Ronda final :: KeyAddition ==> Resultado"); $out=""; for($i=0; $i<4; $i++) for ($j=0; $j<4; $j++) $out.=chr($this->state[$j][$i]); if($this->toHex){ $out=$this->toHexString($out); } return $out; } /** * Realiza el descifrado de 1 bloque de datos (128 bits). * * @param in Datos a descifrar (longitud 128 bits). * @param keyin Array de claves de cifrado (generadas con makeKey()) * @return La cadena de datos descifrada. */ public function blockDecrypt($in, $key) { for ($i=0; $i<4; $i++){ for ($j=0; $j<$this->Nb; $j++){ $this->state[$j][$i]=ord($in{$i*4+$j}); } } $this->showInt("Descifrado:
State Inicial"); $this->KeyAddition($key[$this->Nr]); $this->showInt("Ronda 0 :: KeyAddition"); for($r = $this->Nr-1; $r > 0; $r--) { $this->InvShiftRowInvByteSub(); $this->showInt("Ronda ". ($this->Nr - $r)." :: InvShiftRowInvByteSub"); $this->KeyAddition($key[$r]); $this->showInt("Ronda ".($this->Nr - $r)." :: KeyAddition"); $this->InvMixColumn(); $this->showInt("Ronda ".($this->Nr - $r)." :: InvMiColumn"); } $this->InvShiftRowInvByteSub(); $this->showInt("Ronda final :: InvShiftRowInvByteSub"); $this->KeyAddition($key[0]); $this->showInt("Ronda final :: KeyAddition ==> Resultado"); $out=""; for($i=0; $i<4; $i++) for ($j=0; $j<4; $j++) $out.=chr($this->state[$j][$i]); if($this->toHex){ $out=$this->toHexString($out); } return $out; } //////////////////////////////////////////////////////////////////////// //Funcion de test //////////////////////////////////////////////////////////////////////// /** * Realiza un auto-test. * * */ public function self_test(){ $hash=""; $in=""; for ($i = 0; $i < 16; $i++){ $hash .= chr($i); } $in .= chr(0x00); $in .= chr(0x11); $in .= chr(0x22); $in .= chr(0x33); $in .= chr(0x44); $in .= chr(0x55); $in .= chr(0x66); $in .= chr(0x77); $in .= chr(0x88); $in .= chr(0x99); $in .= chr(0xaa); $in .= chr(0xbb); $in .= chr(0xcc); $in .= chr(0xdd); $in .= chr(0xee); $in .= chr(0xff); echo("===============================
"); echo("KEYSIZE= 128 bits
"); echo("KEY= 0x".$this->toHexString($hash)."
"); echo("Plaintext= 0x".$this->toHexString($in)."
"); $key = $this->makeKey($hash); $ct = $this->blockEncrypt($in, $key); echo("Ciphertext= 0x".$this->toHexString($ct)."
"); $cpt = $this->blockDecrypt($ct, $key); echo ("Descifrado= 0x".$this->toHexString($cpt)."
"); if(!strcmp($cpt,$in)){ if(!$this->debug){ $start=microtime(true); for($i=0; $i<1024; $i++){ $cpt = $this->blockEncrypt($ct, $key); } $end=(microtime(true)-$start)*1000; echo("Tiempo cifrado 16 KB (1024 bloques): ".$end." ms
"); } echo("Cifrado de 128 bits correcto
"); } else echo("Ha fallado el cifrado de 128 bits"); } /////////////////////////////////////////////////////////////////////// //Funciones auxiliares ////////////////////////////////////////////////////////////////////// private function toHexString ($sa) { $buf=""; for ($i=0; $idebug){ echo($texto.": "); for($i=0; $i<4; $i++){ for($j=0; $j<4; $j++){ echo(dechex($this->state[$j][$i])." "); } } echo ("
"); } } } ?>