#include #include #include #include #include using namespace std; int input(void); int index_coincidence(void); int remove_factors(int); void analyse(int); int frequency_analyse(int,char[]); int chi_squared(int,float[]); void decode(int,int,char[]); /*************************************/ /* Various Global variables it was */ /* useful to declare. Kept to a min. */ /* for tidiness's sake */ /*************************************/ int size=26; float final_check,chi_tollerance,ic_tollerance; char* code= new char[size]; float* index = NULL; int* kwlengths = NULL; char* decoded_slice = NULL; int main() { char i; int total; /***********************************/ /* Infinite loop at the 'top' of */ /* code - can be broken by user */ /* input after each decoding */ /* */ /* main function then calls */ /* succcesive functions to perform */ /* the decryption, first finding */ /* keyword length, and then */ /* performing frequency analysis */ /***********************************/ for(;;) { size=input(); cout<<"Enter acceptance level for plaintext (chi-squared) (90): "; cin>>chi_tollerance; cout<<"Enter tolerance for index of coincidence (5.2) :"; cin>>ic_tollerance; total=index_coincidence(); total=remove_factors(total); analyse(total); cout<>i; i=toupper(i); while(i!='Y' && i!='N') { cout<<"Unrecognised input - try again :"; cin>>i; i=toupper(i); } if(i=='N') { break; } } return 0; } /***************************************/ /* This function will read in the code */ /* from a text file into a dynamically */ /* allocated array (dynamic arrays */ /* used throughout for same reasons), */ /* so as to be as */ /* flexible as possible. */ /* All inputed code is also converted */ /* to uppercase for consistency, and */ /* a check is made to ensure the */ /* character is a letter */ /* To determine the number of */ /* characters, the next character to */ /* be read in is always checked for */ /* the end of file flag. If present, */ /* file input stops. */ /* */ /* The function returns the number of */ /* characters to the main function for */ /* use elswhere in the program */ /***************************************/ int input(void) { char filename[50]; int tally=0,i=0,j=0; int check; char input; ifstream fin; cout<<"Enter name of code file: "; cin>>filename; fin.open(filename); while(fin.good() ==false) { cout<<"File not found. Try again"<>filename; fin.open(filename); } while(fin.eof()==false) { input=fin.get(); input=toupper(input); check=static_cast( input ); if(check>=65 && check <=90) { code[i]=input; i++; if(i>=size) { size*=2; char* temp = new char [size]; for(j=0;j5ish */ /* a set of possible keylengths can be */ /* obtained. */ /****************************************/ int index_coincidence(void) { int total=0; int i,j,b=0; index = new float[size/2]; for(i=0;i<(size/2);i++) { index[i]=0; } for(i=1;i<(size/2);i++) { for(j=0;j<(size-i);j++) { if(code[j]==code[j+i]) index[i]++; } } for(i=0;i<(size/2);i++) { index[i]=(index[i]/size)*100; } for(i=0;i<(size/2);i++) { if(index[i]>ic_tollerance) { total++; } } kwlengths=new int[total]; for(i=0;i<(size/2);i++) { if(index[i]>ic_tollerance) { kwlengths[b]=i; b++; } } return(total); } /*********************************************/ /* Many of the keylengths calculated in the */ /* previous function will have been */ /* multiples of each other. This is to be */ /* expected - if the keyword is 'KING', then */ /* the extra numbers correspond to keys */ /* 'KINGKINGKING.....' - valid but */ /* unneccesary */ /*********************************************/ int remove_factors(int total) { int i,j,tally=0,number,b=0; int* temp=NULL; for(i=0;i(shift); for(a=k;a(code[i]); x=x-65; frequency[x]++; } shift=chi_squared(size,frequency); return(shift); } /***********************************************/ /* Here is the core of the frequency analysis */ /* - the chi squared statistic is used to */ /* find the shift of any text passed, by */ /* it to the array containing standard english */ /* frequencies (for this reason, at the moment.*/ /* the program will only decode english */ /* plaintext */ /***********************************************/ int chi_squared(int size,float tally[]) { float english_frequency[26]={8.15,1.37,2.21,4.58,12.51, 1.86,2.36,6.85,6.97,0.14, 1.07,4.37,1.96,6.52,7.58, 1.40,0.19,5.02,6.05,9.93, 3.22,0.78,2.49,0.13,2.11, 0.07}; int i,j; float chi_values[26]; float x; int shift,tmp,index=0; cout.precision(3); for(i=0;i<26;i++) { chi_values[i]=0; english_frequency[i]=(english_frequency[i]/100)*size; } for(i=0;i<26;i++) { for(j=0;j<26;j++) { x=pow( (tally[(j+i)%26]-english_frequency[j%26] ), 2 ); chi_values[i]+= x/(english_frequency[j%27]); } } final_check = chi_values[0]; shift = index; for (tmp = index; tmp <26; tmp++) { if (chi_values[tmp] < chi_values[shift]) shift = tmp; } return(shift); } /*****************************************************/ /* Deceptively simple, this function does the actual */ /* decoding, taking as input the text to be decoded */ /* and the amount by which it has been shifted. */ /* It only deals with uppercase, which is why any */ /* inputed code is first transformed to uppercase */ /* in the input function (lowercase could have been */ /* used, but whichever, consistency was needed! */ /*****************************************************/ void decode(int shift,int size,char code[]) { int i,tmp; for(i=0;i(code[i])-64; if((tmp-shift)>0) tmp=(tmp-shift); else tmp=26+(tmp-shift); tmp+=64; decoded_slice[i]=static_cast(tmp); } }