package cn.tellyouwhat;
import java.util.*;
public class Decryption {
private static final String CIPHER = "OCWYIKOOONIWUGPMXWKTZD" + "WGTSSAYJZWYEMDLBNQAAAVSUWDVBRFLAUPLOOUBFGQHGCSCMGZL" + "ATOEDCSDEIDPBHTMUOVPIEKIFPIMFNOAMVLPQFXEJSMXMPGKCCAY" + "KWFZPYUAVTELWHRHMWKBBNGTGUVTEFJLODFEFKVPXSGRSORVGTAJ" + "BSAUHZRZALKWUOWHGEDEFNSWMRCIWCPAAAVOGPDNFPKTDBALSISU" + "RLNPSJYEATCUCEESOHHDARKHWOTIKBROQRDFMZGHGUCEBVGWCDQXG" + "PBGQWLPBDAYLOOQDMUHBDQGMYWEUIK"; private static final double[] FREQUENCIES = {8.167, 1.492, 2.782, 4.253, 12.702, 2.228, 2.015, 6.094, 6.966, 0.153, 0.772, 4.025, 2.406, 6.749, 7.507, 1.929, 0.095, 5.987, 6.327, 9.056, 2.758, 0.978, 2.360, 0.150, 1.974, 0.074};
private static void move(char[] cipher) { for (int j = 0; j < 26; j++) { int counter = 0; for (int i = 0; i < cipher.length; i++) { if (cipher[i] == cipher[(i + j) % cipher.length]) { counter++; } } System.out.println("第" + j + "次挪动," + counter + "个重合"); } }
public static String decrypt(String cipher) { StringBuilder key = new StringBuilder(); char[] charArray = cipher.toCharArray();
move(charArray);
Scanner scanner = new Scanner(System.in); System.out.print("Please input the most likely keyLength based on the tips above: "); int keyLength; try { keyLength = scanner.nextInt(); } catch (InputMismatchException e) { throw new RuntimeException("你只能输入一个整数"); }
List<char[]> groups = divideIntoGroups(charArray, keyLength);
for (char[] group : groups) { Map<Character, Integer> count = countAnalysis(group); char aKey = findKey(count); key.append(aKey); } System.out.println("可能的k密钥是:" + key.toString()); return decryptWithKey(cipher, key.toString()); }
private static String decryptWithKey(String cipher, String key) { char[] cipherArray = cipher.toCharArray(); char[] keyArray = key.toCharArray(); StringBuilder plaintext = new StringBuilder(314); for (int i = 0; i < cipherArray.length; i++) { char originChar = (char) ( (((cipherArray[i] - 65) - (keyArray[i % 6] - 65)) + 26) % 26 + 65); plaintext.append(originChar); } return plaintext.toString(); }
private static char findKey(Map<Character, Integer> count) { double maxProb = Double.MIN_VALUE; int bestI = 0; for (int i = 0; i < 26; i++) { double currentProb = 0; for (int j = 0; j < 26; j++) { currentProb += FREQUENCIES[j] * count.get((char) (65 + (j + i) % 26)); } if (currentProb > maxProb) { maxProb = currentProb; bestI = i; } } return (char) (bestI + 65); }
private static Map<Character, Integer> countAnalysis(char[] charArr) { Map<Character, Integer> map = new LinkedHashMap<>(); for (int i = 65; i <= 90; i++) { char target = (char) i; int counter = 0; for (char ch : charArr) { if (ch == target) { counter++; } } map.put(target, counter); } return map; }
private static List<char[]> divideIntoGroups(char[] charArray, int keyLength) { ArrayList<char[]> list = new ArrayList<>(); for (int i = 0; i < keyLength; i++) { int j = i; StringBuilder sb = new StringBuilder(); while (j < charArray.length) { sb.append(charArray[j]); j += keyLength; } list.add(sb.toString().toCharArray()); } return list; }
public static void main(String[] args) { System.out.println(decrypt(CIPHER.toUpperCase())); } }
|