<?php
//ini_set('include_path', '/afs/umbc.edu/admin/www/umbc/lib/php.old' . PATH_SEPARATOR . ini_get('include_path'));

//PHP AES Thingy

//Constants
$Nb = 4;
$Nr = 10;
$Rcon = array(
			"00000000",
			"01000000",
			"02000000",
			"04000000",
			"08000000",
			"10000000",
			"20000000",
			"40000000",
			"80000000",
			"1b000000",
			"36000000",
		);

$sbox = array(
  		array("63", "7c", "77", "7b", "f2", "6b", "6f", "c5", "30", "01", "67", "2b", "fe", "d7", "ab", "76"),
		array("ca", "82", "c9", "7d", "fa", "59", "47", "f0", "ad", "d4", "a2", "af", "9c", "a4", "72", "c0"),
		array("b7", "fd", "93", "26", "36", "3f", "f7", "cc", "34", "a5", "e5", "f1", "71", "d8", "31", "15"),
		array("04", "c7", "23", "c3", "18", "96", "05", "9a", "07", "12", "80", "e2", "eb", "27", "b2", "75"),
		array("09", "83", "2c", "1a", "1b", "6e", "5a", "a0", "52", "3b", "d6", "b3", "29", "e3", "2f", "84"),
		array("53", "d1", "00", "ed", "20", "fc", "b1", "5b", "6a", "cb", "be", "39", "4a", "4c", "58", "cf"),
		array("d0", "ef", "aa", "fb", "43", "4d", "33", "85", "45", "f9", "02", "7f", "50", "3c", "9f", "a8"),
 		array("51", "a3", "40", "8f", "92", "9d", "38", "f5", "bc", "b6", "da", "21", "10", "ff", "f3", "d2"),
		array("cd", "0c", "13", "ec", "5f", "97", "44", "17", "c4", "a7", "7e", "3d", "64", "5d", "19", "73"),
		array("60", "81", "4f", "dc", "22", "2a", "90", "88", "46", "ee", "b8", "14", "de", "5e", "0b", "db"),
		array("e0", "32", "3a", "0a", "49", "06", "24", "5c", "c2", "d3", "ac", "62", "91", "95", "e4", "79"),
		array("e7", "c8", "37", "6d", "8d", "d5", "4e", "a9", "6c", "56", "f4", "ea", "65", "7a", "ae", "08"),
		array("ba", "78", "25", "2e", "1c", "a6", "b4", "c6", "e8", "dd", "74", "1f", "4b", "bd", "8b", "8a"),
		array("70", "3e", "b5", "66", "48", "03", "f6", "0e", "61", "35", "57", "b9", "86", "c1", "1d", "9e"),
		array("e1", "f8", "98", "11", "69", "d9", "8e", "94", "9b", "1e", "87", "e9", "ce", "55", "28", "df"),
		array("8c", "a1", "89", "0d", "bf", "e6", "42", "68", "41", "99", "2d", "0f", "b0", "54", "bb", "16")
	);


function KeyExpansion($key)
{
	global $Nb, $Nr, $Rcon;
	$Nk = 4;

	$w = array("", "", "", "");
	//Assumes Nk == 4 (128 bit key)
	for ($i = 0; $i < $Nk; $i++)
	{
		$w[$i] = substr($key, 8*$i, 8);
	}

	for ($i = $Nk; $i < $Nb * ($Nr + 1); $i++)
	{
		$tmp = $w[$i-1];
		//echo " Temp: " . $tmp;
		if ($i % $Nk == 0)
		{
			//temp = SubWord(RotWord(temp)) xor Rcon[i/Nk]
			$tmp = dechex(hexdec(SubWord(RotWord($tmp))) ^ hexdec($Rcon[floor($i/$Nk)]));
			//echo " Rcon: " . $Rcon[floor($i/$Nk)] . " Xor: $tmp";
		}
		else if ($Nk > 6 && $i % $Nk == 4)
		{
			$tmp = SubWord($tmp);
		}
		$w[$i] = dechex(hexdec($w[$i-$Nk]) ^ hexdec($tmp));
		//echo " w[i-Nk]: " . $w[$i-$Nk] . " w[i]: $w[$i] <br />";
	}

	return $w;
}

function SubWord($val)
{
	global $sbox;
	$res = "";
	for ($i = 0; $i < strlen($val); $i+=2)
	{
		$res .= $sbox[hexdec($val[$i])][hexdec($val[$i+1])]; 
	}
	//echo " SubWord: $res"; 
	return $res;
}

function RotWord($val)
{
	$res = substr($val, 2, 6);
	$res .= substr($val, 0, 2);
	//echo " RotWord: $res";
	return $res;
}

function AddRoundKey($state, $w, $j)
{
	global $Nb;

	$res = array();
	for ($i = 0; $i < count($state); $i++)
	{
		for ($k = 0; $k < count($state[$i]); $k++)
		{
			$cmp[$k] = dechex(hexdec(substr($w[$j*$Nb+$k], $i*2, 2)) ^ hexdec($state[$i][$k]));
			if (strlen($cmp[$k]) < 2) $cmp[$k] = "0" . $cmp[$k];
		}
		$res[] = $cmp; 
	}

	echo "AddRoundKey: " . print_r($res);
	return $res;
}

function partition($var, $size)
{
	$res = array();
	for ($i = 0; $i < strlen($var); $i += $size)
	{
		$res[$i/$size] = substr($var, $i, $size);
	}
	return $res;
}

function SubBytes($state)
{
	$res = array();
	foreach ($state as $s)
	{
		$res[] = partition(SubWord(implode("", $s)), 2);
	}
	echo "SubBytes: " . print_r($res);
	return $res;
}

function ShiftRows($state)
{
	for ($i = 0; $i < count($state); $i++)
	{
		for ($j = 0; $j < $i; $j++)
		{
			$tmp = array_shift($state[$i]);
			$state[$i][3] = $tmp;
		}
	}
	echo "ShiftRows: " . print_r($state);
	return $state;
}

/* Taken/Modified from wikipedia.org */
function gmix_column($r) {
        /* 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($c=0;$c<4;$c++) {
                $a[$c] = $r[$c];
                $h = $r[$c] & hexdec("80"); /* hi bit */
                $b[$c] = $r[$c] << 1;
                if($h == hexdec("80")) 
                        $b[$c] ^= hexdec("1b"); /* Rijndael's Galois field */
        }
        $r[0] = $b[0] ^ $a[3] ^ $a[2] ^ $b[1] ^ $a[1]; /* 2 * a0 + a3 + a2 + 3 * a1 */
        $r[1] = $b[1] ^ $a[0] ^ $a[3] ^ $b[2] ^ $a[2]; /* 2 * a1 + a0 + a3 + 3 * a2 */
        $r[2] = $b[2] ^ $a[1] ^ $a[0] ^ $b[3] ^ $a[3]; /* 2 * a2 + a1 + a0 + 3 * a3 */
        $r[3] = $b[3] ^ $a[2] ^ $a[1] ^ $b[0] ^ $a[0]; /* 2 * a3 + a2 + a1 + 3 * a0 */

	return $r;
}


function MixColumns($state)
{
	$mcmat = array(
			array( "02", "03", "01", "01"),
			array( "01", "02", "03", "01"),
			array( "01", "01", "02", "03"),
			array( "03", "01", "01", "02"));
	$res = array();
	for ($i = 0; $i < count($state); $i++)
	{
		$r[0]  = hexdec($state[0][$i]);
		$r[1]  = hexdec($state[1][$i]);
		$r[2]  = hexdec($state[2][$i]);
		$r[3]  = hexdec($state[3][$i]);
		$r = gmix_column($r);
		$res[0][$i] = dechex($r[0]);
		$res[1][$i] = dechex($r[1]);
		$res[2][$i] = dechex($r[2]);
		$res[3][$i] = dechex($r[3]);
	}

	//For some reason sometimes we get prepended 1's, clean those out.
	for ($i = 0; $i < count($res); $i++)
	{
		for ($j = 0; $j < count($res[$j]); $j++)
		{
			if (strlen($res[$i][$j]) == 3)
			{
				$res[$i][$j] = substr($res[$i][$j], 1, 2);
			}
		}
	}

	echo "MixColumns: " . print_r($res);
	return $res;
}

function AES($in, $key)
{
	global $Nr, $Nb;
	//Make the State into the array of strings..
	$state = array();
	for ($i = 0; $i < strlen($in)/8; $i++)
	{
		$state[$i][0] = substr($in, 0+$i*2, 2);
		$state[$i][1] = substr($in, 8+$i*2, 2);
		$state[$i][2] = substr($in, 16+$i*2, 2);
		$state[$i][3] = substr($in, 24+$i*2, 2);
	}
	
	echo "<pre> Current State " . print_r($state) . "m </pre>";

	$w = KeyExpansion($key);

	$state = AddRoundKey($state, $w, 0);

	for ($i = 0; $i < $Nr-1; $i++)
	{
		$state = SubBytes($state);
		$state = ShiftRows($state);
		$state = MixColumns($state);
		$state = AddRoundKey($state, $w, $i+1);
	}
	
	$state = SubBytes($state);
	$state = ShiftRows($state);
	$state = AddRoundKey($state, $w, $Nr);

	return $state;
}

 ?>
<html>
<body>
2b7e151628aed2a6abf7158809cf4f3c

<br />
3243f6a8885a308d313198a2e0370734
<br />
<a
href="http://userpages.umbc.edu/~carback1/aes.php?key=2b7e151628aed2a6abf7158809
cf4f3c&in=3243f6a8885a308d313198a2e0370734">http://userpages.umbc.edu/~carback1/
aes.php?key=2b7e151628aed2a6abf7158809cf4f3c&in=3243f6a8885a308d313198a2e0370734
</a><?php
if (isset($_REQUEST['key']) && isset($_REQUEST['in']))
{
	echo "<pre> Key Schedule (w) ";
	print_r(KeyExpansion($_REQUEST['key']));

	AES($_REQUEST['in'], $_REQUEST['key']);
	echo "</pre>";
	
}
?>
</body>
</html>
