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 ("
");
}
}
}
?>