diff --git a/.classpath b/.classpath
new file mode 100644
index 0000000..fb565a5
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/.project b/.project
new file mode 100644
index 0000000..2828f27
--- /dev/null
+++ b/.project
@@ -0,0 +1,17 @@
+
+
+ Vigenere_Cipher_Decoder
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..7341ab1
--- /dev/null
+++ b/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,11 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.7
diff --git a/bin/com/abushawish/VigenereMain.class b/bin/com/abushawish/VigenereMain.class
new file mode 100644
index 0000000..bc8832e
Binary files /dev/null and b/bin/com/abushawish/VigenereMain.class differ
diff --git a/src/com/abushawish/VigenereMain.java b/src/com/abushawish/VigenereMain.java
new file mode 100644
index 0000000..d203dcf
--- /dev/null
+++ b/src/com/abushawish/VigenereMain.java
@@ -0,0 +1,294 @@
+package com.abushawish;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.Queue;
+
+//Mohammed Abushawish
+//100857775
+
+public class VigenereMain {
+
+ public static void main(String[] args) {
+
+ String cipherText = "jauew evpe mddbcwyy fhvf ycyw af kap cezqr rgtalde oe mss"
+ + " qsdm thfzo yqt wnchswd tyty hsw xekmpf ltodvyr o tl iaj twgz xauew "
+ + "evll fhv leiaapei tywxsxs jnnv lk fhv lssph teel lbo vgcbl hscw gnruws "
+ + "eg xerky hsw eemxy qzeyaewxsyle bp apocl mfkxc afut tyhfusl enfpmowd "
+ + "petelfpv fhrm evp kqvvg ncxemnufpbek ooleo wy wrfvve pp jqdlvpr eg m "
+ + "szgrzp emxzf yoxwxy whff wwss xhzr eoa lvzd plv fhzl ss dsud thyhlazeu mss "
+ + "pkeeemtow sncuxqu ajuntbazp gr aebxowaem nazsgwd hrw evzjauxawm rjmsgxo we "
+ + "oaucw ms dsre wkza smyae bytwmqntxd hsw niiwd oe xurjm zpuwotvw dwyuq ik lpsxwp "
+ + "tf mssx ltak mssj sxsf alr eoa lvzd pfl enfpmowd brfopr eg fhvf evll fhzl hod "
+ + "fat jh l ptjp s nbyu ngyrrwpg sw eazw tg lf arxty cq hdognwgtgz aew yce gr "
+ + "mrgtdfdmtzhy we sncuxqu dzaucw evpjqffkp pp jqgrkoso se a cxr hsw pijmtbrmusybyu "
+ + "xsdk fy xoy ae tyx soyv fhv bygejgmvge ktlt wybnv sw povl lzw zus dbdqsaqf kap "
+ + "ptjps ubo bzl gnuxcgeszd runrpxs sehhpldx s chyu hgddj ufh ezqy rvnsalqd ybd "
+ + "sihxaetewzf mnu twz ezq hlfmzpj mnzflzd kqt kh hccc fo cxlfy lte exh alpum sr "
+ + "ssljf ffnc zpye gfho hhg xexl moo oms zgdqcaneu hy hsw qnu plzw gr tyx mocf mbfop "
+ + "hsw eemxy qzeyaewxsyle aew tb masgvk wselqrj pssy ltep alr zfoe xhe we tk hvtch "
+ + "ltodvyr hsw ehvxa rpnqlfipr l yderm wwvazg whc hsae mrqta lfp owmpb lk fhvr woj az "
+ + "tyx qwpdp tyxj kzmxd rew gesdt sepoeazg whff wwss xhzr eoa lvzd plv rolk wsrk "
+ + "sofw ekz dqgj ulr lfp kvxa we mb ffk scfje oe xyr ywhei zcchazg kbcso gr ik "
+ + "gldzdqoe mzcv fa iempfpkf ie lychtmlc l ncxeutkxpg sw eazw evll fhv xoinsfifg zt "
+ + "ezq yfnyu hse mfkp wxharktyh ezmn rgjhsazg kalh ngglu up rzfq ffk evzkq wyh hscw"
+ + " mlixlrj ydong fd tl tagipbpv fhrm usdkue rgo pwmqbvew vlv noka hvpdbeu lzcy srtvk "
+ + "evp zmy ytcjpkf gzotbr turka mseoqee mssx la nzgp gemddp ifdaaqs rl dczf ms kapm hwde "
+ + "nxlbpv zaghwszf fofd evpe mwrr qfze fhvbc azlteil dojazg kalh sw ioleo alcq hzfdswx "
+ + "dejizbdanlv yzf ezqii xoinsfifg ss egak kapa fh unkh l zzxf wybnv ngglu hyzj tq "
+ + "rvtnvpv ny r elrowd fihx hsw taigpgd jaod tyr ezqrv dpde lted by gfut svvwidaan "
+ + "kalh ezq rvle cq lte wtca dgan whcuzl fhvbc siaetvgns ezq mplescq af napfp lte dbwy "
+ + "hwzt kh hod kaoe vwsljqd li th hse mzqpr pnqrp wlm tffo kap dtye mrls hsw qaiej "
+ + "oahxej ppfp faw ibasyazg rgo hsw srrld cq lte fknvljp wrl wwelqrvw hwez iiewqowde "
+ + "tyx lbtemlj alr lkeudxo od s yakmpf zx oolkds ezmt kapgp oaucw ms dzmrvw zie wcurewm "
+ + "zfq drr schwhei mss zjpei ppbe xarka evll mlc mss hazdwtwzd oqrv mz pp ualcxnhpv mnu "
+ + "uccfytt kh evp zmrexdg cgam whc hsw";
+ int maxPossibleKeyLength = 30;
+
+ String cipherTextEdited = cipherText.replaceAll("\\s", "").toUpperCase();
+
+ BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
+
+ System.out.print("Max length of the key (Indexs of Coincidences): " + maxPossibleKeyLength + "\n");
+
+ // Create sequences of cipher
+ createSequences(cipherTextEdited, maxPossibleKeyLength);
+
+ int keyLength;
+ while (true) {
+ System.out.print("\nEnter assumed key length using the above IoC (generally largest IoC): \n");
+ try {
+ keyLength = Integer.parseInt(reader.readLine());
+ if (keyLength > 0 && keyLength <= maxPossibleKeyLength) {
+ break;
+ } else {
+ System.out.println(
+ "Key length must be an integer greater than 0 and less than " + maxPossibleKeyLength + 1);
+ }
+ } catch (NumberFormatException e) {
+ System.out.println("Entered value must be an integer. Try again.");
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ String guessedKey = guessKeyWithLength(cipherTextEdited, keyLength);
+ String typedKey;
+
+ while (true) {
+ System.out.println("\nThe guessed key is: " + guessedKey
+ + ". Make sure that it makes sense (may need to make logical changes using above Chi values) type it to continue: ");
+ try {
+ typedKey = reader.readLine();
+ if (typedKey.toString().length() == guessedKey.length()) {
+ break;
+ } else {
+ System.out.println("Entered key length must be " + guessedKey.length());
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ String decrypted = decryptUsingKey(cipherTextEdited, typedKey);
+ decrypted = placeSpaces(cipherText, decrypted); // Add spaces
+
+ System.out.println("\nThe cipherText says: \n" + decrypted);
+ }
+
+ // Creates sequences for given cipherText up to max keylength
+ public static void createSequences(String cipherText, int maxLength) {
+
+ // The IOC for every key length
+ ArrayList iocForKeyLengths = new ArrayList();
+ // The various sequences
+ ArrayList sequences = new ArrayList();
+
+ // Start from the first letter and loop to each next letter according to
+ // possible key lengths adding each once to a sequence which is then
+ // added to a list
+ int startAt = 0;
+ for (int possKeyLength = 1; possKeyLength <= maxLength; possKeyLength++) {
+ String newSequence = "";
+ while (startAt < possKeyLength) {
+ for (int i = startAt; i < cipherText.length(); i += possKeyLength) {
+ newSequence += cipherText.charAt(i);
+
+ }
+ sequences.add(newSequence);
+ newSequence = "";
+ startAt++;
+ }
+ System.out.println(possKeyLength + " " + calculateIoC(sequences));
+ iocForKeyLengths.add(calculateIoC(sequences));
+ sequences.clear();
+ startAt = 0;
+ }
+ }
+
+ // Index of Coincidence for a set of sequences/strings
+ public static double calculateIoC(ArrayList sequences) {
+
+ ArrayList averages = new ArrayList();
+ for (int avgSeq = 0; avgSeq < sequences.size(); avgSeq++) {
+ int num = 0;
+ double sum = 0.0;
+ int[] values = new int[26];
+ for (int i = 0; i < 26; i++) {
+ values[i] = 0;
+ }
+
+ // Frequency of each letter in the sequence
+ int character;
+ for (int i = 0; i < sequences.get(avgSeq).length(); i++) {
+ character = sequences.get(avgSeq).charAt(i) - 65;
+ if (character >= 0 && character < 26) {
+ values[character]++;
+ num++;
+ }
+ }
+
+ for (int i = 0; i < 26; i++) {
+ character = values[i];
+ sum = sum + (character * (character - 1));
+ }
+
+ averages.add(sum / (num * (num - 1)));
+ }
+
+ // Calculate the average IoC for all sequences
+ double sum = 0;
+ for (Double avg : averages) {
+ sum += avg;
+ }
+
+ return sum / averages.size();
+ }
+
+ // Guess the key when given the max length of the key
+ public static String guessKeyWithLength(String cipherText, int maxLength) {
+
+ ArrayList sequences = new ArrayList();
+ String newSequence = "";
+ int startAt = 0;
+ while (startAt < maxLength) {
+ for (int i = startAt; i < cipherText.length(); i += maxLength) {
+ newSequence += cipherText.charAt(i);
+
+ }
+ sequences.add(newSequence);
+ newSequence = "";
+ startAt++;
+ }
+
+ String guessedKey = "";
+
+ for (int i = 0; i < maxLength; i++) {
+ System.out.println("\nPosition " + i + " of key: ");
+ System.out.println("Shift | Sequence | Chi Sum");
+ System.out.println("______________________________________________________________");
+
+ // The probable letters for each position
+ guessedKey += probLetterForIndex(maxLength, sequences.get(i).length(), sequences.get(i));
+ }
+
+ return guessedKey;
+ }
+
+ // Calculates the most probable letter for the each letter in key
+ private static char probLetterForIndex(int keyLength, int cipherLength, String substring) {
+
+ // The frequencies of the alphabet in the English language A to Z
+ double[] englishFreq = { 0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015, 0.06094, 0.06966,
+ 0.00153, 0.00772, 0.04025, 0.02406, 0.06749, 0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056,
+ 0.02758, 0.00978, 0.02360, 0.00150, 0.01974, 0.00074 };
+ ArrayList chiSums = new ArrayList();
+
+ // Essentially a caesar cipher on steroids, shift each letter starting
+ // from 0 all the way to 26, and calculate the chi sum
+ for (int shift = 0; shift < 26; shift++) {
+ double chiSum = 0;
+ int ASCIILetterA = 65;
+ int countLetterOcc = 0;
+ String shiftedMessage = "";
+
+ for (int i = 0; i < substring.length(); i++) {
+ int c = substring.charAt(i) - (shift % 26);
+ if (c < 'A') {
+ c = c + 26;
+ }
+ shiftedMessage = shiftedMessage + (char) c;
+ }
+
+ // Calculate the chi value for each letter of the alphabet
+ for (int i = 0; i < 26; i++) {
+
+ // How many times this letter occurs in the String
+ countLetterOcc = shiftedMessage.length()
+ - shiftedMessage.replace(String.valueOf(Character.toChars(ASCIILetterA + i)), "").length();
+
+ double x = countLetterOcc - ((cipherLength) * englishFreq[i]);
+
+ double numirator = Math.pow(x, 2);
+
+ chiSum += numirator / (cipherLength * englishFreq[i]); // Chill
+ // value
+ }
+ chiSums.add(chiSum);
+
+ System.out.println(shift + " " + shiftedMessage + " " + chiSum);
+
+ }
+
+ // Find the smallest chi value indicating most probable letter
+ int minLetterIndex = chiSums.indexOf(Collections.min(chiSums));
+ char minLetter = (char) ((minLetterIndex % 26) + 'A');
+
+ System.out.println("Prob letter: " + minLetter + " due to the chi value.");
+ System.out.println("_____________________________________________________________");
+
+ return minLetter;
+ }
+
+ // Decrypt the cipher using the known/guessed key
+ public static String decryptUsingKey(String cipherText, String key) {
+
+ String decrypted = "";
+ for (int i = 0, j = 0; i < cipherText.length(); i++) {
+ char c = cipherText.charAt(i);
+ if (c < 'A' || c > 'Z')
+ continue;
+ decrypted += (char) ((c - key.charAt(j) + 26) % 26 + 'A');
+ j = ++j % key.length();
+ }
+ return decrypted;
+ }
+
+ // Adds spaces to decrypted message because they were stripped from the
+ // cipherText
+ private static String placeSpaces(String cipherText, String decrypted) {
+
+ // FiFo for whitespaces
+ Queue locationOfSpace = new LinkedList();
+ for (int i = 0; i < cipherText.length(); i++) {
+ if (cipherText.charAt(i) == ' ') {
+ locationOfSpace.add(i);
+ }
+ }
+
+ System.out.println("num of spaces is " + locationOfSpace.size());
+
+ StringBuilder str = new StringBuilder(decrypted);
+
+ int numOfSpaces = locationOfSpace.size();
+ for (int i = 0; i < numOfSpaces; i++) {
+ int loc = locationOfSpace.remove();
+ str.insert(loc, " ");
+ System.out.println(i);
+ }
+ return str.toString();
+ }
+}