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();