#!/usr/bin/env php 0) { $padding = ' ' . $padding; } $message .= $padding; if ($encrypt) { echo "Starting encryption. Our square is:\n"; displaySquare($message, $closestSquare); echo "Expanding password... "; $password = keyExpansion($password); echo "New password: $password\n"; if ($doSubstitution) { echo "Applying password to each character...\n"; for ($i = 0; $i < strlen($message); $i++) { $passindex = $i % strlen($password); $passchar = $password[$passindex]; $newchar = chr((((ord($message[$i]) - 32) + (ord($passchar) - 32) + $i) % 95) + 32); echo "Char $i (" . $message[$i] . ', #' . (ord($message[$i]) - 32) . ") plus password char $passindex ($passchar, #" . (ord($passchar) - 32) . ") plus position $i results in $newchar (#" . (ord($newchar) - 32) . ")\n"; $message[$i] = $newchar; displaySquare($message, $closestSquare); } resetSpeed(); echo "Done applying character substitution. Now let's shift our square around!\n"; } else { echo "Skipping substitution as requested...\n"; } $sq = strToSq($message, $closestSquare); for ($i = 0; $i < strlen($password) - 1; $i += 2) { $passchars = $password[$i] . $password[$i + 1]; $passvalue = (ord($password[$i]) - 32) * 96 + ord($password[$i + 1]) - 32; $dir = $passvalue & bindec('000000000001'); $horizshift = $passvalue & bindec('000000000010') >> 1; $row = $passvalue & bindec('000001111100') >> 2; $amount = $passvalue & bindec('111110000000') >> 7; $amount += $i; $row %= $closestSquare; $dir = $dir > 0 ? 1 : -1; $horizshift = $horizshift > 0; $amount %= $closestSquare; $amount *= $dir; $rowcol = $horizshift ? 'row' : 'column'; echo "Password chars $i and " . ($i + 1) . " ($passchars) make #" . ($passvalue - 32) . " which give us $rowcol $row.\nWe will shift $amount times.\n"; if ($horizshift) { $original = $sq[$row]; for ($j = 0; $j < $closestSquare; $j++) { $index = ($j + $amount) % $closestSquare; if ($index < 0) { $index += $closestSquare; } $sq[$row][$j] = $original[$index]; } } else { $original = []; for ($j = 0; $j < $closestSquare; $j++) { $original[] = $sq[$j][$row]; } for ($j = 0; $j < $closestSquare; $j++) { $index = ($j + $amount) % $closestSquare; if ($index < 0) { $index += $closestSquare; } $sq[$j][$row] = $original[$index]; } } displaySquare2($sq); } echo "All done!\n"; echo "Result: "; for ($x = 0; $x < $closestSquare; $x++) { for ($y = 0; $y < $closestSquare; $y++) { echo $sq[$y][$x]; } } echo "\n"; } else { echo "Starting decryption. Our square is:\n"; $sq = strToSqRev($message, $closestSquare); displaySquare2($sq); $originalPassword = $password; // We need this later for substitution $password = keyExpansion($password); echo "Expanding password... new password: $password\n"; $actionqueue = []; for ($i = 0; $i < strlen($password) - 1; $i += 2) { $passchars = $password[$i] . $password[$i + 1]; $passvalue = (ord($password[$i]) - 32) * 96 + ord($password[$i + 1]) - 32; $dir = $passvalue & bindec('000000000001'); $horizshift = $passvalue & bindec('000000000010') >> 1; $row = $passvalue & bindec('000001111100') >> 2; $amount = $passvalue & bindec('111110000000') >> 7; $amount += $i; $row %= $closestSquare; $dir = $dir > 0 ? 1 : -1; $amount %= $closestSquare; $amount *= $dir; $actionqueue[] = [-$amount, $horizshift, $row, $dir, $passchars, $passvalue]; } $actionqueue = array_reverse($actionqueue); $i = 0; foreach ($actionqueue as $action) { $amount = $action[0]; $horizshift = $action[1]; $row = $action[2]; $dir = $action[3]; $passchars = $action[4]; $passvalue = $action[5]; $horizshift = $horizshift > 0 ? true : false; $rowcol = $horizshift ? 'row' : 'column'; echo "Password chars $i and " . ($i + 1) . " ($passchars) make #" . ($passvalue - 32) . " which give us $rowcol $row.\nWe will shift $amount times.\n"; $i++; if ($dir > 0) { $original = $sq[$row]; for ($j = 0; $j < $closestSquare; $j++) { $index = ($j + $amount) % $closestSquare; if ($index < 0) { $index += $closestSquare; } $sq[$row][$j] = $original[$index]; } } else { $original = []; for ($j = 0; $j < $closestSquare; $j++) { $original[] = $sq[$j][$row]; } for ($j = 0; $j < $closestSquare; $j++) { $index = ($j + $amount) % $closestSquare; if ($index < 0) { $index += $closestSquare; } $sq[$j][$row] = $original[$index]; } } displaySquare2($sq); } $message = ''; foreach ($sq as $y) { $message .= implode('', $y); } if ($doSubstitution) { resetSpeed(); echo "Done shifting things around. Now reversing character substitution...\n"; // Apply substitution for ($i = 0; $i < strlen($message); $i++) { $passindex = $i % strlen($password); $passchar = $password[$passindex]; $newchar = chr(mod(((ord($message[$i]) - 32) - (ord($passchar) - 32) - $i), 95) + 32); echo "Char $i (" . $message[$i] . ', #' . (ord($message[$i]) - 32) . ") minus password char $passindex ($passchar, #" . (ord($passchar) - 32) . ") minus position $i results in $newchar (#" . (ord($newchar) - 32) . ")\n"; $message[$i] = $newchar; displaySquare($message, $closestSquare); } } else { echo "Skipping substitution as requested\n"; } // Done! echo "Done! Result: $message\n"; echo "(Note that the last few characters are probably garbage.)\n"; } function mod($n, $m) { $n = $n % $m; if ($n > 0) return $n; return ($n + abs($m)) % $m; } // Same as strToSq() except this reverts the x and y axis function strToSqRev($str, $size) { $sq = []; for ($x = 0; $x < $size; $x++) { $tmpstr = substr($str, $x * $size, $size); for ($y = 0; $y < strlen($tmpstr); $y++) { if (!isset($sq[$y])) { $sq[$y] = []; } $sq[$y][$x] = $tmpstr[$y]; } } return $sq; } function strToSq($str, $size) { $sq = []; for ($y = 0; $y < $size; $y++) { $tmpstr = substr($str, $y * $size, $size); $sq[$y] = []; for ($x = 0; $x < strlen($tmpstr); $x++) { $sq[$y][$x] = $tmpstr[$x]; } } return $sq; } function displaySquare($message, $size) { global $speed, $speedslowfactor, $speedmin; $outstr = ''; for ($y = 0; $y < $size; $y++) { $str = substr($message, $y * $size, $size); for ($i = 0; $i < strlen($str); $i++) { $outstr .= $str[$i] . ' '; } $outstr .= "\n"; } echo $outstr . "\n"; usleep($speed * 1000); $speed = max($speedmin, $speed / $speedslowfactor); } function displaySquare2($sq) { global $speed, $speedslowfactor, $speedmin; $outstr = ''; foreach ($sq as $y) { foreach ($y as $x) { $outstr .= $x . ' '; } $outstr .= "\n"; } echo $outstr . "\n"; usleep($speed * 1000); $speed = max($speedmin, $speed / $speedslowfactor); } function keyExpansion($password) { $password .= $password; $originalPassword = $password; $i = ord($password[0]) + 1; while (strlen($originalPassword) > 1) { $password .= str_repeat($originalPassword . chr(($i % 95) + 32), strlen($originalPassword)); $originalPassword = substr($originalPassword, 1); $i++; } $a = 43690; for ($i = 0; $i < strlen($password) - 1; $i++) { $password[$i] = chr((((ord($password[$i]) ^ $a) + $i) % 95) + 32); if ($a == 43690) { $a = 21845; } else { $a = 43690; } } return $password; }