import java.util.*; import java.io.*; import java.lang.*; public class Cryptoanalysis2 { public static void main(String[] args) { Manager manager = new Manager(8); manager.read("rnj.txt", "sample.txt"); manager.run(); } } class Manager{ private double bias = 1; private String codefile; private int limit = 200; public int genNum =0; public int popSize = 30; public Genome[] mainpop = new Genome[popSize]; private Tri master, code; public Manager(int g) { limit = g; initial(); } public void initial() { for(int index=0; index < popSize; index++) { mainpop[index] = new Genome(); } } public void read(String masterfile, String cipherfile) { codefile = cipherfile; master = new Tri(masterfile); code = new Tri(cipherfile); bias = master.maxRate / code.maxRate; } public void run() { GA current = null; // while(genNum < limit) //{ GA test = new GA(mainpop, popSize, genNum, master, code, bias); test.fitness(); test.createNewPop(); current = test; genNum++; //} current.translate(codefile); } } class GA{ public Random generator = new Random(); private int popSize; double[] fitness; public Util utility = new Util(); public Genome top; private Genome[] population; public int generation; private Tri master, code; private double bias; public GA(Genome[] p, int size, int g, Tri m, Tri c, double b) { population = p; this.popSize = size; generation = g; master = m; code = c; bias = b; } public void print() { for(int x =0; x < popSize; x++) { if(population[x] != null) { population[x].print(); System.out.println(); } } } public void createNewPop() { /* The selection process starts from randomly selecting a number in the range of 0-1 and randomly selecting a pair of Genomes from the current population. Look up the fitness value of each genome. If the value exceed the random number, the genome is selected to be a parent of new offspring, or else it is thrown away and the process will select another genome.*/ Genome[] tempPop = new Genome[popSize]; Genome parentA,parentB; int selectedNum1,selectedNum2; Offspring offspring1 = new Offspring(); Offspring offspring2 = new Offspring(); //reproduce half time of population (in this case = 15) for(int index=0; index < popSize; index++) { double point = (Math.abs(generator.nextInt()) % (30 - 0)) + (int)Math.ceil(0); selectedNum1 = (Math.abs(generator.nextInt()) % (30 - 0)) ; selectedNum2 = (Math.abs(generator.nextInt()) % (30 - 0)) ; while(findRank(population[selectedNum1]) > point) { selectedNum1 = (Math.abs(generator.nextInt()) % (30 - 0));// select again bad rank } parentA = population[selectedNum1]; while((findRank(population[selectedNum2])> point)||(selectedNum2 == selectedNum1)) { selectedNum2 = (Math.abs(generator.nextInt()) % (30 - 0));// select again bad rank } parentB = population[selectedNum2]; crossOver(parentA, parentB, offspring1, offspring2); //Mutate every 5 generations if((generation % 5) == 0) { offspring1.mutation(); offspring2.mutation(); } /* parentA.print(); System.out.println(); parentB.print(); System.out.println(); offspring1.print(); System.out.println(); offspring2.print(); System.out.println(); */ tempPop[index] = offspring1; tempPop[index++] = offspring2; } //copy genomes for(int index=0; index < popSize; index++) { population[index] = tempPop[index]; } } public void crossOver(Genome x, Genome y, Offspring a, Offspring b) { int cop = (Math.abs(generator.nextInt()) % (13 - 0)) + (int)Math.ceil(0); for (int j =0; j <= cop; j++) { ((Genome) a).set[j] = x.set[j]; ((Genome) b).set[j] = y.set[j]; } for(int i= 0; i < y.set.length; i++) { int number = y.set[i]; int cop1 = cop; for(int index = 0; index < cop1; index++) { if(number != a.set[index]) { cop1++; a.set[cop1] = number; } } } for(int i=0; i < x.set.length; i++) { int number = x.set[i]; int cop2 = cop; for(int index = 0; index < cop2; index++) { if(number != b.set[index]) { cop2++; b.set[cop2] = number; } } } } public void fitness() { fitness = new double[popSize]; top = population[0]; for(int index=0; index < popSize; index++) { Genome current = population[index]; current.gap = match(current); if (current.gap < top.gap) top = current; //return gap of each genome. the bigger its gap the worst its performance. } //insertion sort and save in fitness array. for(int l=0; l < popSize; l++) { fitness[l] = population[l].gap; } for(int p=0; p < popSize; p++) { double key = fitness[p]; int j; //shirt the larger gap to the right for(j = p; (j > 0) && (key < fitness[j-1]); j--) fitness[j] = fitness[j-1]; fitness[j] = key; } /* for( int x=0; x< popSize; x++) System.out.println(fitness[x]);*/ System.out.println("This genome has the highest fitness."); top.print(); System.out.println(); } public int findRank(Genome x) { int rank; int index =0; while(fitness[index] != x.gap) { index++; } rank = index; return rank; } public double match(Genome x) { double totalGap = 0; int digit1 =26,digit2 =26,digit3= 26; for (int a=0; a < 26; a++) { for (int b=0; b < 26; b++) { for (int c=0; c < 26; c++) { if (code.Trigram[a][b][c]!= 0) { double currValue = (double) (code.Trigram[a][b][c] * bias) ;//frequency //search for(int d=0; d< 26; d++) { if (x.set[d] == a) digit1 = d; if (x.set[d] == b) digit2 = d; if (x.set[d] == c) digit3 = d; } double value = compare(digit1, digit2, digit3); double gap = Math.abs(value - currValue); totalGap = totalGap + gap; //System.out.println("totalgap: "+ totalGap); //System.out.println(getChar(a) + "-" + getChar(b) +"-" + getChar(c) + ": " +Trigram[a][b][c]); } } } } return totalGap; } public double compare(int i, int j, int k) { double v = (double) master.Trigram[i][j][k]; return v; } public void translate(String x) { String codefile = x; StringBuffer text = new StringBuffer(); System.out.println("Here is the evolved code file."); try { FileReader fr = new FileReader (codefile); BufferedReader infile = new BufferedReader(fr); String line = infile.readLine(); while (line != null) { for(int d=0; d < line.length(); d++) { line = line.toLowerCase(); char current = line.charAt(d); int value = utility.changeChar(current); if (value < 26) { char mychar = utility.getChar(top.set[value]); text.append(mychar); } else text.append(line.charAt(d)); } line = infile.readLine(); } infile.close(); System.out.print(text.toString()); System.out.println(); } catch (FileNotFoundException exception) { System.out.println("The file " + codefile + " was not found"); } catch (IOException exception) { System.out.println(exception); } } } class Genome { public int[] set; public double gap = 0; Random generator = new Random(); public Genome() { set = new int[26]; //next = null; randomGenes(); } public void print() { for (int i =0; i< set.length; i++) { //System.out.print(getChar(set[i]) + " "); System.out.print((set[i]) + " "); } } private void randomGenes() { int rangebeg = 0; int rangeend = 25; int [] temp = new int[set.length]; for (int ra = 0; ra < temp.length; ra++) { temp[ra] = (int)(Math.floor(Math.random() *((rangeend - rangebeg)+1)) + (int)Math.ceil(rangebeg)); //for uniqueness for (int rb =0; rb < ra; rb++) { while (temp[ra] == temp[rb]) { //use different method to make sure that even seed is the same, numbers are not indentical. temp[ra] = (Math.abs(generator.nextInt()) % ((rangeend - rangebeg)+1)) + (int)Math.ceil(rangebeg); rb= 0; } } } for (int i = 0; i < set.length; i++) { set[i] = temp[i]; } } public char getChar(int x) { char newchar = (char) (x + 'A'); return newchar; } public int swapGeneChar(int x) { int a = set[x]; return a; } } class Offspring extends Genome{ public int[] set; public double gap = 0; Random generator = new Random(); public Offspring() { set= new int[26]; } public void mutation() { int rand1 = (Math.abs(generator.nextInt()) % (25+1 - 0)) + (int)Math.ceil(0); int rand2 = (Math.abs(generator.nextInt()) % (25+1 - 0)) + (int)Math.ceil(0); while (rand1 == rand2) rand2 = (Math.abs(generator.nextInt()) % (25+1 - 0)) + (int)Math.ceil(0); int temp = set[rand1]; set[rand1] = set[rand2]; set[rand2] = temp; } public char getChar(int x) { char newchar = (char) (x + 'A'); return newchar; } } class Tri{ public String file; public int[][][] Trigram = new int[26][26][26]; public int Int2=0,Int1=0,Int=0; public int Total=0; //counts # of alphabetic chars in file public int max=0; //highest=largest single trigram count public double maxRate = 0; public Util utility = new Util(); public Tri(String filename){ file = filename; //initialize trigram array for (int A=0; A < 26; A++) { for (int B=0; B < 26; B++) { for (int C=0; C < 26; C++) Trigram[A][B][C]=0; } } //read file System.out.println("Processing " + file + " ..."); try { FileReader fr = new FileReader (file); BufferedReader infile = new BufferedReader(fr); int readint = infile.read(); while (readint != -1) { char input = (char) readint; Character temp = new Character(input); char read = temp.toLowerCase(input); //System.out.println(read + " " + changeChar(read)); Int = utility.changeChar(read); if((Int >= 0) && (Int < 26)) { Total++; if( Total > 2 ) { Trigram[Int2][Int1][Int] = Trigram[Int2][Int1][Int] + 1; if(Trigram[Int2][Int1][Int] > max) max = Trigram[Int2][Int1][Int]; } Int2 = Int1; Int1 = Int; } readint = infile.read(); } infile.close(); } catch (FileNotFoundException exception) { System.out.println("The file " + file + " was not found"); } catch (IOException exception) { System.out.println(exception); } System.out.println("Total alphabetic characters: " + Total); System.out.println("Max number of trigrams: " + max); maxRate = (double) max/Total; //print trigram array /*for (int a=0; a < 26; a++) { for (int b=0; b < 26; b++) { for (int c=0; c < 26; c++) System.out.println(getChar(a) + "-" + getChar(b) +"-" + getChar(c) + ": " +Trigram[a][b][c]); } }*/ } } class Util{ public Util(){}; public int changeChar(char c){ switch(c) { case 'a': return 0; case 'b': return 1; case 'c': return 2; case 'd': return 3; case 'e': return 4; case 'f': return 5; case 'g': return 6; case 'h': return 7; case 'i': return 8; case 'j': return 9; case 'k': return 10; case 'l': return 11; case 'm': return 12; case 'n': return 13; case 'o': return 14; case 'p': return 15; case 'q': return 16; case 'r': return 17; case 's': return 18; case 't': return 19; case 'u': return 20; case 'v': return 21; case 'w': return 22; case 'x': return 23; case 'y': return 24; case 'z': return 25; case ' ': case '.': case ',': case '!': case '?': case ';': case ':': case '*': case '=': case '+': case '-': case '/': return 26; default: return 26; } } public char getChar(int i){ char value; if ( i == 0) value ='a'; else if ( i == 1) value ='b'; else if ( i == 2) value ='c'; else if ( i == 3) value ='d'; else if ( i == 4) value ='e'; else if ( i == 5) value ='f'; else if ( i == 6) value ='g'; else if ( i == 7) value ='h'; else if ( i == 8) value ='i'; else if ( i == 9) value ='j'; else if ( i == 10) value ='k'; else if ( i == 11) value ='l'; else if ( i == 12) value ='m'; else if ( i == 13) value ='n'; else if ( i == 14) value ='o'; else if ( i == 15) value ='p'; else if ( i == 16) value ='q'; else if ( i == 17) value ='r'; else if ( i == 18) value ='s'; else if ( i == 19) value ='t'; else if ( i == 20) value ='u'; else if ( i == 21) value ='v'; else if ( i == 22) value ='w'; else if ( i == 23) value ='x'; else if ( i == 24) value ='y'; else if ( i == 25) value ='z'; else value = '!'; return value; } }