Nk = strlen($z)/4;
$this->Nr = $this->Nk + self::$Nb + 2;
if ($this->Nk != 4 && $this->Nk != 6 && $this->Nk != 8)
die("Der eingestellte ImportKey ist nicht 32 Zeichen lang. Bitte passen Sie diesen an. zurueck");
//die("Key is " . ($this->Nk*32) . " bits long. *not* 128, 192, or 256.");
$this->Nr = $this->Nk+self::$Nb+2;
$this->w = array(); // Nb*(Nr+1) 32-bit words
$this->s = array(array()); // 2-D array of Nb colums and 4 rows
$this->KeyExpansion($z); // places expanded key in w
}
/** Encrypts an aribtrary length String.
* @params plaintext string
* @returns ciphertext string
* Whenever possible you should stream your plaintext through the
* encryptBlock() function directly, as the amount of time required
* to encrypt is linear to the size of the ciphertext.
**/
public function encrypt($x) {
$t = ""; // 16-byte block
$y = ""; // returned cipher text;
// put a 16-byte block into t
$xsize = strlen($x);
for ($i=0; $i<$xsize; $i+=16) {
for ($j=0; $j<16; $j++) {
if (($i+$j)<$xsize) {
$t[$j] = $x[$i+$j];
}
else
$t[$j] = chr(0);
}
$y .= $this->encryptBlock($t);
}
return $y;
}
/** Decrypts an aribtrary length String.
* @params ciphertext string
* @returns plaintext string
* Whenever possible you should stream your ciphertext through the
* decryptBlock() function directly, as the amount of time required
* to decrypt is linear to the size of the ciphertext.
**/
public function decrypt($y) {
$t = ""; // 16-byte block
$x = ""; // returned plain text;
// put a 16-byte block into t
$ysize = strlen($y);
for ($i=0; $i<$ysize; $i+=16) {
for ($j=0; $j<16; $j++) {
if (($i+$j)<$ysize)
$t[$j] = $y[$i+$j];
else
$t[$j] = chr(0);
}
$x .= $this->decryptBlock($t);
}
return $x;
}
/** Encrypts the 16-byte plain text.
* @params 16-byte plaintext string
* @returns 16-byte ciphertext string
**/
public function encryptBlock($x) {
$y = ""; // 16-byte string
// place input x into the initial state matrix in column order
for ($i=0; $i<4*self::$Nb; $i++) {
// we want integerger division for the second index
$this->s[$i%4][($i-$i%self::$Nb)/self::$Nb] = ord($x[$i]);
}
// add round key
$this->addRoundKey(0);
for ($i=1; $i<$this->Nr; $i++) {
// substitute bytes
$this->subBytes();
// shift rows
$this->shiftRows();
// mix columns
$this->mixColumns();
// add round key
$this->addRoundKey($i);
}
// substitute bytes
$this->subBytes();
// shift rows
$this->shiftRows();
// add round key
$this->addRoundKey($i);
// place state matrix s into y in column order
for ($i=0; $i<4*self::$Nb; $i++)
$y .= chr($this->s[$i%4][($i-$i%self::$Nb)/self::$Nb]);
return $y;
}
/** Decrypts the 16-byte cipher text.
* @params 16-byte ciphertext string
* @returns 16-byte plaintext string
**/
public function decryptBlock($y) {
$x = ""; // 16-byte string
// place input y into the initial state matrix in column order
for ($i=0; $i<4*self::$Nb; $i++)
$this->s[$i%4][($i-$i%self::$Nb)/self::$Nb] = ord($y[$i]);
// add round key
$this->addRoundKey($this->Nr);
for ($i=$this->Nr-1; $i>0; $i--) {
// inverse shift rows
$this->invShiftRows();
// inverse sub bytes
$this->invSubBytes();
// add round key
$this->addRoundKey($i);
// inverse mix columns
$this->invMixColumns();
}
// inverse shift rows
$this->invShiftRows();
// inverse sub bytes
$this->invSubBytes();
// add round key
$this->addRoundKey($i);
// place state matrix s into x in column order
for ($i=0; $i<4*self::$Nb; $i++) {
// Used to remove filled null characters.
$x .= ($this->s[$i%4][($i-$i%self::$Nb)/self::$Nb] == chr(0) ? "" : chr($this->s[$i%4][($i-$i%self::$Nb)/self::$Nb]));
}
return $x;
}
public function __destruct() {
unset($this->w);
unset($this->s);
}
/** makes a big key out of a small one
* @returns void
**/
private function KeyExpansion($z) {
// Rcon is the round constant
static $Rcon = array(
0x00000000,
0x01000000,
0x02000000,
0x04000000,
0x08000000,
0x10000000,
0x20000000,
0x40000000,
0x80000000,
0x1b000000,
0x36000000,
0x6c000000,
0xd8000000,
0xab000000,
0x4d000000,
0x9a000000,
0x2f000000
);
$temp = 0; // temporary 32-bit word
// the first Nk words of w are the cipher key z
for ($i=0; $i<$this->Nk; $i++) {
$this->w[$i] = 0;
// fill an entire word of expanded key w
// by pushing 4 bytes into the w[i] word
$this->w[$i] = ord($z[4*$i]); // add a byte in
$this->w[$i] <<= 8; // make room for the next byte
$this->w[$i] += ord($z[4*$i+1]);
$this->w[$i] <<= 8;
$this->w[$i] += ord($z[4*$i+2]);
$this->w[$i] <<= 8;
$this->w[$i] += ord($z[4*$i+3]);
}
for (; $iNr+1); $i++) {
$temp = $this->w[$i-1];
if ($i%$this->Nk == 0)
$temp = $this->subWord($this->rotWord($temp)) ^ $Rcon[$i/$this->Nk];
else if ($this->Nk > 6 && $i%$this->Nk == 4)
$temp = $this->subWord($temp);
$this->w[$i] = $this->w[$i-$this->Nk] ^ $temp;
self::make32BitWord($this->w[$i]);
}
}
/** adds the key schedule for a round to a state matrix.
* @returns void
**/
private function addRoundKey($round) {
$temp = "";
for ($i=0; $i<4; $i++) {
for ($j=0; $jw[$round*self::$Nb+$j] >> (3-$i)*8;
// Cast temp from a 32-bit word into an 8-bit byte.
$temp %= 256;
// Can't do unsigned shifts, so we need to make this temp positive
$temp = ($temp < 0 ? (256 + $temp) : $temp);
$this->s[$i][$j] ^= $temp; // xor temp with the byte at location (i,j) of the state
}
}
}
/** unmixes each column of a state matrix.
* @returns void
**/
private function invMixColumns() {
$s0 = $s1 = $s2 = $s3= '';
// There are Nb columns
for ($i=0; $is[0][$i]; $s1 = $this->s[1][$i]; $s2 = $this->s[2][$i]; $s3 = $this->s[3][$i];
$this->s[0][$i] = $this->mult(0x0e, $s0) ^ $this->mult(0x0b, $s1) ^ $this->mult(0x0d, $s2) ^ $this->mult(0x09, $s3);
$this->s[1][$i] = $this->mult(0x09, $s0) ^ $this->mult(0x0e, $s1) ^ $this->mult(0x0b, $s2) ^ $this->mult(0x0d, $s3);
$this->s[2][$i] = $this->mult(0x0d, $s0) ^ $this->mult(0x09, $s1) ^ $this->mult(0x0e, $s2) ^ $this->mult(0x0b, $s3);
$this->s[3][$i] = $this->mult(0x0b, $s0) ^ $this->mult(0x0d, $s1) ^ $this->mult(0x09, $s2) ^ $this->mult(0x0e, $s3);
}
}
/** applies an inverse cyclic shift to the last 3 rows of a state matrix.
* @returns void
**/
private function invShiftRows() {
$temp = "";
for ($i=1; $i<4; $i++) {
for ($j=0; $js[$i][$j];
for ($j=0; $js[$i][$j] = $temp[$j];
}
}
/** applies inverse S-Box substitution to each byte of a state matrix.
* @returns void
**/
private function invSubBytes() {
for ($i=0; $i<4; $i++)
for ($j=0; $js[$i][$j] = self::$invSBox[$this->s[$i][$j]];
}
/** mixes each column of a state matrix.
* @returns void
**/
private function mixColumns() {
$s0 = $s1 = $s2 = $s3= '';
// There are Nb columns
for ($i=0; $is[0][$i]; $s1 = $this->s[1][$i]; $s2 = $this->s[2][$i]; $s3 = $this->s[3][$i];
$this->s[0][$i] = $this->mult(0x02, $s0) ^ $this->mult(0x03, $s1) ^ $this->mult(0x01, $s2) ^ $this->mult(0x01, $s3);
$this->s[1][$i] = $this->mult(0x01, $s0) ^ $this->mult(0x02, $s1) ^ $this->mult(0x03, $s2) ^ $this->mult(0x01, $s3);
$this->s[2][$i] = $this->mult(0x01, $s0) ^ $this->mult(0x01, $s1) ^ $this->mult(0x02, $s2) ^ $this->mult(0x03, $s3);
$this->s[3][$i] = $this->mult(0x03, $s0) ^ $this->mult(0x01, $s1) ^ $this->mult(0x01, $s2) ^ $this->mult(0x02, $s3);
}
}
/** applies a cyclic shift to the last 3 rows of a state matrix.
* @returns void
**/
private function shiftRows() {
$temp = "";
for ($i=1; $i<4; $i++) {
for ($j=0; $js[$i][($j+$i)%self::$Nb];
for ($j=0; $js[$i][$j] = $temp[$j];
}
}
/** applies S-Box substitution to each byte of a state matrix.
* @returns void
**/
private function subBytes() {
for ($i=0; $i<4; $i++) {
for ($j=0; $js[$i][$j] = self::$sBox[$this->s[$i][$j]];
}
}
/** multiplies two polynomials a(x), b(x) in GF(2^8) modulo the irreducible polynomial m(x) = x^8+x^4+x^3+x+1
* @returns 8-bit value
**/
private static function mult($a, $b) {
$sum = self::$ltable[$a] + self::$ltable[$b];
$sum %= 255;
// Get the antilog
$sum = self::$atable[$sum];
return ($a == 0 ? 0 : ($b == 0 ? 0 : $sum));
}
/** applies a cyclic permutation to a 4-byte word.
* @returns 32-bit int
**/
private static function rotWord($w) {
$temp = $w >> 24; // put the first 8-bits into temp
$w <<= 8; // make room for temp to fill the lower end of the word
self::make32BitWord($w);
// Can't do unsigned shifts, so we need to make this temp positive
$temp = ($temp < 0 ? (256 + $temp) : $temp);
$w += $temp;
return $w;
}
/** applies S-box substitution to each byte of a 4-byte word.
* @returns 32-bit int
**/
private static function subWord($w) {
$temp = 0;
// loop through 4 bytes of a word
for ($i=0; $i<4; $i++) {
$temp = $w >> 24; // put the first 8-bits into temp
// Can't do unsigned shifts, so we need to make this temp positive
$temp = ($temp < 0 ? (256 + $temp) : $temp);
$w <<= 8; // make room for the substituted byte in w;
self::make32BitWord($w);
$w += self::$sBox[$temp]; // add the substituted byte back
}
self::make32BitWord($w);
return $w;
}
/** reduces a 64-bit word to a 32-bit word
* @returns void
**/
private static function make32BitWord(&$w) {
// Reduce this 64-bit word to 32-bits on 64-bit machines
$w &= 0x00000000FFFFFFFF;
}
}