hill_cpta.php 5.21 KiB
<?php
define ("ALLOWED_TIME", 600);
define ("NB_CHALLENGES", 5);
define ("NB_ALLOWED_PT", 32);
@session_start();
header("Content-Type: text/html; charset=utf-8");
/************************/
/*     FUNCTIONS        */
/************************/
// returns the determinant of a 3*3 matrix
function det33($matrix)
	if (count($matrix) != 3 or count($matrix[0]) != 3 or count($matrix[1]) != 3 or count($matrix[2]) != 3)
		return False;
	return $matrix[0][0] * ($matrix[1][1]*$matrix[2][2] - $matrix[1][2]*$matrix[2][1])
		+  $matrix[0][1] * ($matrix[1][2]*$matrix[2][0] - $matrix[1][0]*$matrix[2][2])
		+  $matrix[0][2] * ($matrix[1][0]*$matrix[2][1] - $matrix[1][1]*$matrix[2][0]) ;
// returns a random matrix (3*3, integer values in range 1..25)
function get_matrix()
	$matrix = array();
	for ($i = 0; $i < 3; $i++)
		$vect = array();
		for ($j = 0; $j < 3; $j++)
			$vect[] = rand(1, 25);
		$matrix[] = $vect;
	return $matrix;
// returns a matrix invertible modulo 26
function get_key_matrix()
	while (True)
		$matrix = get_matrix();
		$det = det33($matrix);
		if ($det % 2 != 0 and $det % 13 != 0)
			return $matrix;
// returns a random 3-letter text
function get_random_trigraph()
	$text = "";
	for ($i = 0; $i < 3; $i++)
		$text.= chr(rand(0, 25) + 0x41);
	return $text;
function get_permutation()
	$perm = range(0, 25);
	shuffle($perm);
	return $perm;
function hill($keymatrix, $permutation, $inputtext)
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
$blocsize = count($keymatrix); if (strlen($inputtext) != $blocsize) return False; // compute the inverse permutation $inverseperm = range(0, 25); for ($i = 0; $i < 26; $i++) $inverseperm[$permutation[$i]] = $i; // conversion (letters -> numbers) $inputvector = array(); for ($i = 0; $i < $blocsize; $i++) { $letter = $inputtext[$i]; if ($letter < 'A' or $letter > 'Z') return False; $inputvector[] = $permutation[ ord($letter)-ord('A')]; } // multiply the vector $outputvector = array(); for ($i = 0; $i < $blocsize; $i++) { $sum = 0; for ($j = 0; $j < $blocsize; $j++) $sum += $keymatrix[$i][$j] * ($permutation[ord($inputtext[$j]) - 0x41]); $outputvector[] = $sum % 26; } // conversion (numbers -> letters) $outputtext = ""; for ($i = 0; $i < $blocsize; $i++) $outputtext.= chr($inverseperm[$outputvector[$i]] + 0x41); return $outputtext; } // small static test function test() { $perm = array(3, 22, 7, 25, 2, 11, 13, 4, 20, 12, 16, 14, 9, 21, 19, 6, 18, 0, 23, 8, 1, 24, 5, 10, 17, 15); $mat = array(array(15, 22, 23), array(18, 1, 22), array(20, 6, 25)); return (hill($mat, $perm, "ABC") == "LBA" and hill($mat, $perm, "DEF") == "BQC" and hill($mat, $perm, "GHI") == "ZEH"); } // clean the session variables and die function die_clean($message) { echo $message; $_SESSION['VORTEXCPTA_STARTED'] = False; //unset($_SESSION['VORTEXCPTA_STARTED']); unset($_SESSION['VORTEXCPTA_TIME']); unset($_SESSION['VORTEXCPTA_MATRIX']); unset($_SESSION['VORTEXCPTA_PERM']); die(); } /************************/ /* CHALLENGE */ /************************/ $VARNAMES = array("VORTEXCPTA_TIME", "VORTEXCPTA_MATRIX", "VORTEXCPTA_PERM", "VORTEXCPTA_CHALL"); // a new problem is requested if (isset($_GET["cpta"])) { // check the variable format $regex_cpta = '/^[A-Z]{3}(_[A-Z]{3}){0,'. strval(NB_ALLOWED_PT-1).'}$/';
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
if (!preg_match( $regex_cpta, $_GET['cpta'])) { die_clean("Bad input format.\n"); } else { $plaintexts = explode('_', $_GET['cpta']); $matrix = get_key_matrix(); $perm = get_permutation(); foreach ($plaintexts as $plain) { $cipher = hill($matrix, $perm, $plain); echo "$plain -> $cipher <br />\n"; } $chall = array(); for ($i = 1; $i <= NB_CHALLENGES; $i++) { $trig = get_random_trigraph(); echo "Challenge #$i: $trig <br />\n"; $chall[] = $trig; } $_SESSION['VORTEXCPTA_CHALL'] = $chall; $_SESSION['VORTEXCPTA_MATRIX'] = $matrix; $_SESSION['VORTEXCPTA_PERM'] = $perm; $_SESSION['VORTEXCPTA_STARTED'] = True; $_SESSION['VORTEXCPTA_TIME'] = time(); } } // 2nd call: check the solution else if (isset($_GET['solution'])) { if (!isset($_SESSION['VORTEXCPTA_STARTED']) or $_SESSION['VORTEXCPTA_STARTED'] != True) die_clean("The challenge isn't initialized.\n"); // check that all variables are there foreach ($VARNAMES as $varname) if (!isset($_SESSION[$varname])) die_clean("Bug: variable $varname is not initialized.\n"); $time = $_SESSION['VORTEXCPTA_TIME']; if (time() - $time > ALLOWED_TIME) die_clean("Too late!\n"); // check input format $regex_solution = '/^[A-Z]{3}(_[A-Z]{3}){'. strval(NB_CHALLENGES-1).'}$/'; if (!preg_match($regex_solution, $_GET["solution"])) die_clean("Bad input format.\n"); $matrix = $_SESSION['VORTEXCPTA_MATRIX']; $perm = $_SESSION['VORTEXCPTA_PERM']; $chall = $_SESSION['VORTEXCPTA_CHALL']; $answers = explode( '_', $_GET['solution'] ); // check the proposed solution for ($i = 0; $i < NB_CHALLENGES; $i++) { $answercrypt = hill($matrix, $perm, $answers[$i]); if ($answercrypt != $chall[$i]) { die_clean("Wrong answer: ".$answers[$i]." -> $answercrypt != ".$chall[$i]."\n"); } } $flag = "..."; // No, it's not "...". You really have to solve the chall. echo "Congratulations! The flag is $flag <br />\n"; die_clean(""); }