0
点赞
收藏
分享

微信扫一扫

Java加密算法—凯撒加密实现以及暴力破解

彭维盛 2022-02-16 阅读 62

目录

1、概念

凯撒密码最早由古罗马军事统帅盖乌斯·尤利乌斯·凯撒在军队中用来传递加密信息,故称凯撒密码。这是一种位移加密方式,只对26个字母进行位移替换加密,规则简单,容易破解,恺撒密码通常被作为其他更复杂的加密方法中的一个步骤。

将明文字母表向后移动1位,A变成了B,B变成了C……,Z变成了A。因为字母移动26位会回到原值,移动27位的结果和移动1位是一样,所以字母表最多可以移动25位。

2、加密实现

public class KaiserTest {
    public static void main(String[] args) {
        String text = "KaiserTest";
        System.out.println("凯撒加密前原文:" + text);
        // 测试移动3位,进行加密
        String encryptKaiser = encryptKaiser(text, 3);
        System.out.println("凯撒加密后密文:" + encryptKaiser);


    }

    /**
     * 使用凯撒加密方式加密数据
     *
     * @param original :原文
     * @param key      :位移数量
     * @return :加密后的数据
     */
    public static String encryptKaiser(String original, int key) {
        // 将字符串转为字符数组
        char[] chars = original.toCharArray();
        StringBuilder sb = new StringBuilder();
        for (char aChar : chars) {
            // 获取字符的ascii编码
            int asciiCode = aChar;
            // 偏移数据
            asciiCode += key;
            // 将偏移后的数据转为字符
            char result = (char) asciiCode;
            // 拼接数据
            sb.append(result);
        }
        return sb.toString();
    }
}

效果:
在这里插入图片描述

3、解密实现

public class KaiserTest {
    public static void main(String[] args) {
        String text = "KaiserTest";
        System.out.println("凯撒加密前原文:" + text);
        // 测试移动3位,进行加密
        String encryptKaiser = encryptKaiser(text, 3);
        System.out.println("凯撒加密后密文:" + encryptKaiser);
        // 解密操作
        String decryptKaiser = decryptKaiser(encryptKaiser, 3);
        System.out.println("凯撒解密后明文:" + decryptKaiser);
    }

	/**
     * 使用凯撒加密方式解密数据
     *
     * @param encryptedData :密文
     * @param key           :位移数量
     * @return : 源数据
     */
    public static String decryptKaiser(String encryptedData, int key) {
        // 将字符串转为字符数组
        char[] chars = encryptedData.toCharArray();
        StringBuilder sb = new StringBuilder();
        for (char aChar : chars) {
            // 获取字符的ASCII编码
            int asciiCode = aChar;
            // 偏移数据
            asciiCode -= key;
            // 将偏移后的数据转为字符
            char result = (char) asciiCode;
            // 拼接数据
            sb.append(result);
        }
        return sb.toString();
    }
    
    /**
     * 使用凯撒加密方式加密数据
     *
     * @param original :原文
     * @param key      :位移数量
     * @return :加密后的数据
     */
    public static String encryptKaiser(String original, int key) {
        // 将字符串转为字符数组
        char[] chars = original.toCharArray();
        StringBuilder sb = new StringBuilder();
        for (char aChar : chars) {
            // 获取字符的ascii编码
            int asciiCode = aChar;
            // 偏移数据
            asciiCode += key;
            // 将偏移后的数据转为字符
            char result = (char) asciiCode;
            // 拼接数据
            sb.append(result);
        }
        return sb.toString();
    }
}

效果:
在这里插入图片描述

4、频率分析法破解

使用凯撒加密对字母表进行加密时,采用的是位移方法,如果分析出了合理的位移值,那么就可以对密文进行破解,英文字母出现频率最高的分别是e、t、a……,然后检查要破解的密文,也将每个字母出现的频率整理出来,假设密文中出现频率最高的字母是c,那么明文可能是e,如果密码文中出现频率次高的但是e,那么明文可能是t,以此类推便就能解开加密信息的内容,这就是频率分析法。

字母出现批量对照表-来自百度百科:
在这里插入图片描述在这里插入图片描述
代码演示:

public class KaiserAnalysisTest {
    public static void main(String[] args) {

        // 字母频率排名
        char[] orderChar = {'e', 't', 'a', 'o', 'n', 'r', 'i', 's', 'h',
                'd', 'l', 'f', 'c', 'm', 'u', 'g', 'y', 'p', 'w', 'b',
                'v', 'k', 'j', 'x', 'q', 'z'};
        // 明文,用于最后进行对比
        String text = "Encrypt the alphabet using Caesar encryption";
        // 加密后密文,用于破解
        String secret = "Hqfu|sw#wkh#doskdehw#xvlqj#Fdhvdu#hqfu|swlrq";

        // 打印各字符出现数量
        List<Map.Entry<Character, Integer>> mapList = countChars(secret);

        // 匹配概率值
        out:
        for (char ch : orderChar) {
            for (Map.Entry<Character, Integer> entry : mapList) {
                System.out.println("猜测最大概率字符为:" + ch);
                Character key = entry.getKey();
                int keyNum = key - ch;
                System.out.println("猜测key为:" + key + ",与" + ch + "的ASCII相差:" + keyNum);
                // 根据偏移值解密
                String decryptData = decryptKaiser(secret, keyNum);
                System.out.println("解密后明文预计为:" + decryptData);
                boolean result = decryptData.equals(text);
                System.out.println("是否复合条件:" + result);
                if (result) {
                    break out;
                }
            }
        }
    }

    /**
     * 解密
     *
     * @param secret
     * @param key
     * @return
     */
    public static String decryptKaiser(String secret, int key) {
        // 1、将密文转换成字符数组
        char[] chars = secret.toCharArray();
        StringBuilder sb = new StringBuilder();
        for (char aChar : chars) {
            // 2、获取字符的ascii编码
            int asciiCode = aChar;
            // 3、偏移数据
            asciiCode += key;
            // 4、将偏移后的数据转为字符
            char result = (char) asciiCode;
            // 5、拼接数据
            sb.append(result);
        }
        return sb.toString();
    }

    /**
     * 统计String里出现最多的字符
     *
     * @param data
     */
    public static List<Map.Entry<Character, Integer>> countChars(String data) {
        //创建TreeMap集合,键是Character,值是Integer
        Map<Character, Integer> map = new HashMap<>(16);

        //遍历字符串,得到每一个字符
        for (int i = 0; i < data.length(); i++) {
            char key = data.charAt(i);

            //拿到每一个字符作为键到TreeMap集合中去找对应的值,看其返回值
            Integer value = map.get(key);

            //如果返回值是null,说明该字符在TreeMap集合中不存在,就把该字符串作为键,1作为值存储
            if (value == null) {
                map.put(key, 1);
            } else {
                //如果返回值不是null,说明该字符在TreeMap集合中存在,把该值加一,然后重新存储该字符和对应的值
                value++;
                map.put(key, value);
            }
        }
        // 对结果进行排序
        List<Map.Entry<Character, Integer>> mapList = new ArrayList<>(map.entrySet());
        //根据字符出现次数排序
        mapList.sort((o1, o2) -> o2.getValue().compareTo(o1.getValue()));

        StringBuilder sb = new StringBuilder();
        //遍历Map集合,得到键和值,按照要求进行拼接
        mapList.forEach(entry -> {
            Integer value = entry.getValue();
            Character key = entry.getKey();
            sb.append(key).append("出现").append(value).append("次; ");
        });

        //调用toString方法,从StringBuilder转为String类型输出
        String result = sb.toString();
        System.out.println(result);
        return mapList;
    }
}

效果:
在这里插入图片描述
注意:key指的是当前验证的密文的字符

举报

相关推荐

0 条评论