Java加密算法—凯撒加密实现以及暴力破解
目录
- 1、概念
- 2、加密实现
- 3、解密实现
- 4、频率分析法破解
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指的是当前验证的密文的字符