java 破解凯撒密码

跟参数输出范例一样就行。得用他给的变量名。其它就是凯撒密码的形式,变成不需要key就行破译,根据图片里的频率(那个表格就是给出的频率)

img

img


package com.zhengtao;

/*
 * @Description :
 * @CreateTime : 2022-02-25 15:36
 */
public class Demo {

    /**
     * 这个 是 明文?
     */
    public static final double[] ENGLISH = {
            0.0855, 0.0160, 0.0316, 0.0387, 0.1210, 0.0218, 0.0209, 0.0496, 0.0733,
            0.0022, 0.0081, 0.0421, 0.0253, 0.0717, 0.0747, 0.0207, 0.0010, 0.0633,
            0.0673, 0.0894, 0.0268, 0.0106, 0.0183, 0.0019, 0.0172, 0.0011
    };

    /*
     * @Description: 这个 main 方法用来破解 凯撒密码
     * 首先了解,什么是凯撒密码,凯撒加密(Caesar Code)是一种简单的消息编码方式:它根据字母表将消息中的每个字母移动常量位k。
     * 举个例子如果k等于3,则在编码后的消息中,每个字母都会向前移动3位:a会被替换为d;b会被替换成e;
     * 依此类推。字母表末尾将回卷到字母表开头。于是,w会被替换为z, x会被替换为a。在解码消息的时候,每个字母会反方向移动同样的位数。
     * 那么 如何破解 凯撒密码,已经很简单明了了,
     * @Date: 2022-02-25 16:00
     * @param args
     * @Return: void
    */
    public static void main(String[] args) {
        // 这里应该是从命令行读取的,我这里,不方便 从命令行读取,我直接写死了,题主 这里自己处理一下
        String ciphertext = "asjfkljasklfjlkasjdklfjklaskldjfasfdd";
        // 从题目中看, EngLish  应该是,最终比对的明文
        // 手动实现 解密凯撒密码
        String temp = "";
        int count = 1;
        while(true){
            temp = "";
            for (int i = 0; i < ciphertext.length(); i++) {
                // 确保 输入的字母 是 字母
                if ((ciphertext.charAt(i) > 'a' && ciphertext.charAt(i) < 'z') || (ciphertext.charAt(i) > 'A' && ciphertext.charAt(i) < 'Z')){
                    char ch = (char) (ciphertext.charAt(i) + count);
                    // 凯撒编码
                    if (ch > 106 && ch < 97){
                        ch = (char) (ch - 26);
                    }
                    if (ch > 122){
                        int l = ch - 97;
                        ch = (char) (ch - 26);
                    }
                    temp = ch + temp;
                }
            }
            count++;
            System.out.println("开始执行 -> " + temp);
            if (chiSquared(frequency(temp), ENGLISH) == 0){
                break;
            }
            if (count == 26){
                temp = "";
                break;
            }
        }
        if (temp.equals("")){
            System.out.println("输入与明文不对应");
        }else {
            System.out.println("破解成功 -> " + temp);
        }
    }


    /*
     * @Description: 返回 String 中 每个字母出现的次数
     * @Date: 2022-02-25 15:37
     * @param str
     * @Return: int[]
    */
    public static int[] count(String str){
        int[] res = new int[26];
        char[] chars = str.toCharArray();
        for (char ch : chars) {
            // 小写字母
            if(ch - 65 >= 0 && ch - 65 <=25){
                res[ch - 65]++;
            }
            // 大写字母
            if (ch - 97 >= 0 && ch - 97 <= 25){
                res[ch - 97]++;
            }
        }
        return res;
    }



    public static double[] frequency(String str){
        double[] res = new double[26];
        // 每个字母出现的频率
        int[] count = count(str);
        // 给定字符串的长度
        int length = str.length();
        for (int i = 0; i < count.length; i++) {
            res[i] = count[i] / length;
        }
        return res;
    }

    /**
     * @Description: 求出来 两个数组到底有多接近   如果两个数组,一模一样,则返回结果 为 0, 匹配度越高,则返回值 越小
     * @Date: 2022-02-25 15:53
     * @param freq
     * @param english
     * @Return: double
    */
    public static double chiSquared(double[] freq, double[] english){
        if (freq.length != english.length){
            return -1;
        }
        double res = 0.0;
        double[] temp = new double[26];
        // 求出 a - z的匹配度
        for (int i = 0; i < freq.length; i++) {
            temp[i] = (freq[i] - english[i]) * (freq[i] - english[i]) / english[i];
        }
        // 根据公式,将结果求和
        for (double v : temp) {
            res += v;
        }
        return res;
    }
}

看不太清楚