purpose: Substitution Cipher Cracker
version: v1.0
creator: Dr MindHacker [Cory Michael Boston]
contact: drmindhaxor VIA yahoo D0T com
error_reporting(0); define("TRUE", 1); define("FALSE", 0); define("MAX", 32); define("WORDS", 4096); define("VALID", 1); define("INVALID", 0); define("OPEN", 1); define("CLOSED", 0); define("KEEP", 0); define("DUP", 1); define("SKIP", 2); define("BIG", 0); define("SMALL", 1); define("REPEATS", 0); define("UNIQUES", 1); define("EXHAUSTED", 0); define("TOO_FEW", 1); define("SUFFICIENT", 2); define ("NO_DECODES", 1); $cword[][] = ""; $pword[][] = ""; $force = 0; global $lists; global $lens; $cpairs[] = ""; global $syms; global $seq; global $lang; global $lex; $lex = BIG; /************************************************ extract the cipher word sequence pattern for later analysis ************************************************/ function ExtractPatterns() { global $syms; global $cpairs; global $cword; global $lens; global $seq; for($x = 0; $x < $syms; $x++) { $seq[$x] = $x; $length = ($lens[$x] - 1); for($outer = 0; $outer < $length; $outer++) { for($inner = ($outer + 1); $inner < $lens[$x]; $inner++) { if($cword[$x][$outer] == $cword[$x][$inner]) { $cpairs[$x]++; } } } } } /************************************************ reset flag to USE ************************************************/ function InitKernel() { $x = 0; for($x = 0; $x < WORDS; $x++) { $flag[$x] = KEEP; } } /************************************************ re-order for optimization or if a cipher word is found with no pattern match ************************************************/ function SwapWords($x, $y) { $temp = 0; $buf[MAX]; global $cpairs; global $seq; global $cword; global $lens; global $flag; $temp = $cpairs[$x]; $cpairs[$x] = $cpairs[$y]; $cpairs[$y] = $temp; $temp = $seq[$x]; $seq[$x] = $seq[$y]; $seq[$y] = $temp; $buf = $cword[$x]; $cword[$x] = $cword[$y]; $cword[$y] = $buf; $temp = $lens[$x]; $lens[$x] = $lens[$y]; $lens[$y] = $temp; $temp = $flag[$x]; $flag[$x] = $flag[$y]; $flag[$y] = $temp; } /************************************************ shift words - move words one position to the left ************************************************/ function ShiftWords() { $x = 0; global $words; global $cpairs; global $seq; global $lens; global $flag; global $cword; $y = ($words - 1); $tpairs = $cpairs[0]; $tseq = $seq[0]; $tlens = $lens[0]; $tflag = $flag[0]; $tword = ""; $tword = $cword[0]; for($x = 0; $x < $y; $x++) { $cpairs[$x] = $cpairs[$x + 1]; $seq[$x] = $seq[$x + 1]; $lens[$x] = $lens[$x + 1]; $flag[$x] = $flag[$x + 1]; $cword[$x] = $cword[$x + 1]; } $cpairs[$y] = $tpairs; $seq[$y] = $tseq; $lens[$y] = $tlens; $flag[$y] = $tflag; $cword[$y] = $tword; } /************************************************ re-sequence the cipher text by length in order to create the most incosistent results at the beginning of the consistency checks, thus reducing the total number of comparisons ************************************************/ function Resequence() { $x = 0; $y = 0; global $syms; global $lens; global $flag; for($x = 0; $x < ($syms - 1); $x++) { for($y = ($x + 1); $y < $syms; $y++) { if(($lens[$x] < $lens[$y]) && ($flag[$y] == KEEP)) { SwapWords($x, $y); } } } } /************************************************ check to see if any cipher words have been flagged to be skipped and push to end of cipher word list - cipher words are flagged to be skipped if their cipher pattern generates no clear patterns or if the word caused an inconsistency block during the consistency checks (i.e., word missing from dictionary) ************************************************/ function SkipCheck() { $x = 0; global $syms; global $flag; $end = ($syms - 1); for($x = 0; $x < $end; $x++) { if($flag[$x] != KEEP) { while($flag[$end] != KEEP) { $end--; } if($end > $x) { SwapWords($x, $end); } } } } /************************************************ check to see if there is a word list that fits this pattern ************************************************/ function CheckPattern($x) { $flag[$x] = KEEP; global $lists; global $flag; if(file_exists($lists[$x]) == FALSE) { $flag[$x] = SKIP; } return $flag[$x]; } /************************************************ store appropriate dictionary lists for each cipher word according to its pattern ************************************************/ function StoreLists($x) { global $lists; global $cpairs; global $lens; global $lex; global $lang; $buf[32]; $lists[$x] = "dict/"; switch($lang) { case "English": $lists[$x] .= "eng/"; break; case "German": $lists[$x] .= "ger/"; break; case "French": $lists[$x] .= "fre/"; break; case "Spanish": $lists[$x] .= "spa/"; $lex = BIG; break; case "Italian": $lists[$x] .= "ita/"; $lex = BIG; break; case "Swedish": $lists[$x] .= "swe/"; $lex = BIG; break; case "Dutch": $lists[$x] .= "dut/"; $lex = BIG; break; case "Portugeuse": $lists[$x] .= "por/"; break; } if($lex == BIG) { $lists[$x] .= "big/"; } else { $lists[$x] .= "small/"; } $lists[$x] .= $lens[$x]; if($cpairs[$x] > 0) { $lists[$x] .= "P"; $lists[$x] .= $cpairs[$x]; } else { $lists[$x] .= "N"; } $lists[$x] .= ".TXT"; return CheckPattern($x); } /************************************************ parses words of cipher text ************************************************/ function GetStats() { global $syms; global $cword; global $lens; global $lex; global $lang; $alphas = "abcdefghijklmnopqrstuvwxyz"; $lang = $_POST['LANG']; $force = $_POST['DICT']; $log = fopen("inlog.txt", "a"); fprintf($log, "%s\n%s\n\n", $lang, $_POST['CIPHER']); fclose($log); $cword = preg_split("/[\s]+/", $_POST['CIPHER']); $syms = count($cword); for($x = 0; $x < $syms; $x++) { $cword[$x] = preg_replace ('/([0-9]+)|!|@|#|%|&|-|_|=|,|:|;|<|>|`|~|"|\/|\'|\||\.|\[|\]|\{|\}|\+|\(|\)|\*|\^|\$|\?|\\\/i', '', $cword[$x]); $lens[$x] = strlen($cword[$x]); $cword[$x] = strtolower($cword[$x]); } if(($syms == 1) && ($lens[0] > 20)) { //echo 'Ciphertext must contain word divisions!'; exit(0); } if(($syms < 20) && ($force[0] != 'L')) { $lex = SMALL; } } /************************************************ check to see if word from dictionary list matches the pattern of the cipher word ************************************************/ function FindPattern($sym, $pword) { $x = 0; $y = 0; global $lens; global $syms; global $pword; global $cword; $len = ($lens[$sym] - 1); for($x = 0; $x < $len; $x++) { for($y = ($x + 1); $y < $lens[$sym]; $y++) { if((($pword[$sym][$x] == $pword[$sym][$y]) && ($cword[$sym][$x] == $cword[$sym][$y])) || (($cword[$sym][$x] != $cword[$sym][$y]) && ($pword[$sym][$x] != $pword[$sym][$y]))) { continue; } else { return SKIP; } } } return KEEP; } /************************************************ compare the consistency of cipher-to-plain and plain-to-cipher patterns - compares cipher-to plain first then plain-to-cipher, if the two 550 words do not have cipher letters in common it checks to see if they do have plain letters in common to rule out as invalid ************************************************/ function XComparePatterns($src, $trg) { global $cword; global $pword; global $lens; for($src = 0; $src < $trg; $src++) { for($x = 0; $x < $lens[$src]; $x++) { for($y = 0; $y < $lens[$trg]; $y++) { if(($cword[$src][$x] == $cword[$trg][$y]) xor ($pword[$src][$x] == $pword[$trg][$y])) { return INVALID; } } } } return VALID; } /************************************************ partially decrypt skipped word by going thru each letter of each cipher word and if it is common with letter in cipher word flagged as SKIP | DUP then assign the corresponding clear word letter to that position - only goes through enough times for each letter of cipher cipher word flagged as SKIP | DUP ************************************************/ function PartialDecrypt($y) { $sym = 0; $letter = 0; $flagged = 0; $matching = TRUE; $matches = 0; global $cword; global $pword; global $lens; global $words; $pword[$y] = strtoupper($cword[$y]); $sym = 0; while($matching == TRUE) { if($cword[$y][$flagged] == $cword[$sym][$letter]) { $pword[$y][$flagged] = $pword[$sym][$letter]; $flagged++; $matches++; } if(++$letter == $lens[$sym]) { $letter = 0; $sym++; if($sym == $words) { if($matches > 0) { $matches = 0; } else { $flagged++; } $sym = 0; } } if($flagged > $lens[$y]) { $matching = 0; } } //echo $pword[$y], ' '; } /************************************************ write decodes and partially decrypt any words flagged as skipped [words that had no pattern matches in lexicon] ************************************************/ function WriteDecodes() { $x = 0; $y = 0; $z = 0; global $decodes; global $syms; global $seq; global $flag; global $pword; $decodes++; //echo "[$decodes] "; for($x = 0; $x < $syms; $x++) { for($y = 0; $y < $syms; $y++) { if($x == $seq[$y]) { switch($flag[$y]) { case KEEP: //echo $pword[$y], ' '; break; default: PartialDecrypt($y); break; } $z++; if($z == 20) { //echo '\n'; $z = 0; } } } } } /************************************************** open prev **************************************************/ function OpenPrev(&$trg, &$list, &$stat, &$pos) { fclose($list); $stat[$trg] = CLOSED; $pos[$trg] = 0; return --$trg; } /************************************************** open next **************************************************/ function OpenNext(&$trg, &$list, &$stat, &$pos) { $pos[$trg] = ftell($list); fclose($list); $stat[$trg] = CLOSED; return ++$trg; } /************************************************** deep analysis opens each word list [of lexical words matching the patterns of each cipher-word] and performs cross-consistency-checks [compare cipher-to-clear and clear-to-cipher decodes] forward and backwards through the lists until all possible translations are exhausted. **************************************************/ function ComparePatterns() { $pos[] = ( 0 ); $stat[] = CLOSED; $src = 0; $trg = 1; $comparing = TRUE; $searching = TRUE; global $cword; global $pword; global $lens; global $lists; global $cpairs; global $words; $master = fopen($lists[$src], "r"); while($comparing == TRUE) { $pword[$src] = fgets($master); if(feof($master)) { fclose($master); $comparing = FALSE; continue; } rtrim($pword[$src]); if(($cpairs[$src] > 0) && (FindPattern($src, $pword) == SKIP)) { continue; } $trg = 1; $stat[$trg] = CLOSED; $searching = TRUE; while($searching == TRUE) { if($stat[$trg] == CLOSED) { $list = fopen($lists[$trg], "r"); $stat[$trg] = OPEN; fseek($list, $pos[$trg], SEEK_SET); } $pword[$trg] = fgets($list); rtrim($pword[$trg]); if(feof($list)) { $trg = OpenPrev(&$trg, &$list, &$stat, &$pos); if($trg == $src) { $searching = FALSE; } continue; } else { if(($cpairs[$trg] > 0) && (FindPattern($trg, $pword) == SKIP)) { continue; } else { if(XComparePatterns($src, $trg) == VALID) { if($trg < ($words - 1)) { $trg = OpenNext(&$trg, &$list, &$stat, &$pos); } else { WriteDecodes(); } } } } } } return 0; } /************************************************ only one word in cipher, just insert plain word matches into edit ************************************************/ function InsertList() { global $pword; global $lens; global $cpairs; global $lists; $inserting = TRUE; $in = fopen($lists[0], "r"); if($in) { while($inserting) { $pword[0] = fgets($in); if(feof($in)) { $inserting = FALSE; } else { rtrim($pword[0]); if(($cpairs[0]) && (FindPattern(0, $pword[0]) == SKIP)) { continue; } else { WriteDecodes(); } } } fclose($in); } else { //echo "Could not open $lists[0][0]"; exit(0); } } /************************************************ figure out which words are the only ones necessary to account for all cipher symbols in the cipher text - this will minimize the number of words we have to actually crypt- analyze ************************************************/ function CheckSymbols() { $alphabet[] = 0; $xsymbols[][] = 0; $x = 0; $y = 0; $dups = 0; $symbol = 0; global $syms; global $cword; global $lens; global $flag; global $words; for($x = 0; $x < $syms; $x++) { if($flag[$x] != SKIP) { for($y = 0; $y < $lens[$x]; $y++) { $symbol = $cword[$x][$y]; if($alphabet[$symbol] == 0) { $alphabet[$symbol] = 1; $xsymbols[UNIQUES][$x]++; } else { $xsymbols[REPEATS][$x]++; } } if($xsymbols[UNIQUES][$x] == 0) { $flag[$x] = DUP; $words--; $dups++; } } } return $dups; } /************************************************ optimize ************************************************/ function Optimize() { $x = 0; $skips = 0; $result = 0; $tries = 0; $dups = 0; $start = 0; global $syms; global $flag; global $words; $optimizing = TRUE; while($optimizing == TRUE) { $skips = 0; $dups = CheckSymbols(); if(($dups) || ($words == 1)) { SkipCheck(); Resequence(); } for($x = 0; $x < $words; $x++) { if(StoreLists($x) == SKIP) { $skips++; $skipped++; } } if($skipped == $syms) { return EXHAUSTED; } if($skips > 0) { $start = $words; $words -= $skips; for($x = $start; $x < $syms; $x++) { if($flag[$x] == DUP) { $flag[$x] = KEEP; $words++; } } } else { $optimizing = FALSE; } } if($words == 1) { return TOO_FEW; } return SUFFICIENT; } /************************************************ gather information about ciphertext for analysis ************************************************/ function AnalyzeCipherText() { global $decodes; global $flag; global $words; global $syms; $words = $syms; Resequence(); if(Optimize() == EXHAUSTED) { return EXHAUSTED; } else if($words == 1) { InsertList(); if(!$decodes) { if($flag[1] == SKIP) { return EXHAUSTED; } else { $flag[1] = KEEP; $flag[0] = DUP; StoreLists(1); SwapWords(0,1); InsertList(); if(!$decodes) { return EXHAUSTED; } } } return TOO_FEW; } return SUFFICIENT; } /************************************************ attack monoalphabetic substitution cipher ************************************************/ function CrackCipher() { $result = TOO_FEW; global $lex; global $decodes; global $flag; global $words; global $syms; if(($syms == 1) || (($syms < 3) &&($lens[1] == 0))) // debug this shit!!! { $result = StoreLists(0); if($result == SKIP) // { echo "No words match that pattern!"; } else { InsertList(); if(!$decodes) // { echo "No words match that pattern!"; } } } else { $result = AnalyzeCipherText(); if($result == SUFFICIENT) { $x = 0; $analyzing = TRUE; $attempts = 0; $start; $start = time(); while($analyzing == TRUE) { if(ComparePatterns() == NO_DECODES) { ; } if(($decodes < 1) && ($lex == SMALL)) { $lex = BIG; AnalyzeCipherText(); continue; } if($decodes > 0) { $analyzing = FALSE; continue; } else { if($attempts == $words) { if($flag[0] != SKIP) { for($x = 1;$x < $words; $x++) { $flag[$x] = SKIP; } InsertList(); } $analyzing = 0; } else { if($attempts != 0) { $words++; } $flag[0] = SKIP; $flag[$words - 1] = KEEP; ShiftWords(); for($x = 0; $x < $words; $x++) { StoreLists($x); } $words--; $attempts++; } } } } else { return $result; } $finish = time(); $elapsed = $finish - $start; //echo 'Words: ', $syms'; //echo 'Decodes: ', $decodes'; //echo 'Time: ', $elapsed'; return $result; } } GetStats(); InitKernel(); ExtractPatterns(); CrackCipher();