1+ package com .duwei .encrypt ;
2+
3+ import java .io .File ;
4+ import java .io .FileReader ;
5+ import java .io .FileWriter ;
6+ import java .io .IOException ;
7+ import java .util .ArrayList ;
8+ import java .util .Collections ;
9+ import java .util .Comparator ;
10+ import java .util .HashMap ;
11+ import java .util .List ;
12+ import java .util .Map ;
13+ import java .util .Map .Entry ;
14+
15+ /**
16+ * 频率分析法破解凯撒密码
17+ * http://blog.csdn.net/axi295309066/article/details/52491077
18+ */
19+ public class FrequencyAnalysis {
20+ //英文里出现次数最多的字符
21+ private static final char MAGIC_CHAR = 'e' ;
22+ //破解生成的最大文件数
23+ private static final int DE_MAX_FILE = 4 ;
24+
25+ public static void main (String [] args ) throws Exception {
26+ //测试1,统计字符个数
27+ //printCharCount("article1_en.txt");
28+
29+ //加密文件
30+ //int key = 3;
31+ //encryptFile("article1.txt", "article1_en.txt", key);
32+
33+ //读取加密后的文件
34+ String artile = file2String ("article1_en.txt" );
35+ //解密(会生成多个备选文件)
36+ decryptCaesarCode (artile , "article1_de.txt" );
37+ }
38+
39+ public static void printCharCount (String path ) throws IOException {
40+ String data = file2String (path );
41+ List <Entry <Character , Integer >> mapList = getMaxCountChar (data );
42+ for (Entry <Character , Integer > entry : mapList ) {
43+ //输出前几位的统计信息
44+ System .out .println ("字符'" + entry .getKey () + "'出现" + entry .getValue () + "次" );
45+ }
46+ }
47+
48+ public static void encryptFile (String srcFile , String destFile , int key ) throws IOException {
49+ String artile = file2String (srcFile );
50+ //加密文件
51+ String encryptData = MyEncrypt .encrypt (artile , key );
52+ //保存加密后的文件
53+ string2File (encryptData , destFile );
54+ }
55+
56+ /**
57+ * 破解凯撒密码
58+ * @param input 数据源
59+ * @return 返回解密后的数据
60+ */
61+ public static void decryptCaesarCode (String input , String destPath ) {
62+ int deCount = 0 ;//当前解密生成的备选文件数
63+ //获取出现频率最高的字符信息(出现次数越多越靠前)
64+ List <Entry <Character , Integer >> mapList = getMaxCountChar (input );
65+ for (Entry <Character , Integer > entry : mapList ) {
66+ //限制解密文件备选数
67+ if (deCount >= DE_MAX_FILE ) {
68+ break ;
69+ }
70+
71+ //输出前几位的统计信息
72+ System .out .println ("字符'" + entry .getKey () + "'出现" + entry .getValue () + "次" );
73+
74+ ++deCount ;
75+ //出现次数最高的字符跟MAGIC_CHAR的偏移量即为秘钥
76+ int key = entry .getKey () - MAGIC_CHAR ;
77+ System .out .println ("猜测key = " + key + ", 解密生成第" + deCount + "个备选文件" + "\n " );
78+ String decrypt = MyEncrypt .decrypt (input , key );
79+
80+ String fileName = "de_" + deCount + destPath ;
81+ string2File (decrypt , fileName );
82+ }
83+ }
84+
85+ //统计String里出现最多的字符
86+ public static List <Entry <Character , Integer >> getMaxCountChar (String data ) {
87+ Map <Character , Integer > map = new HashMap <Character , Integer >();
88+ char [] array = data .toCharArray ();
89+ for (char c : array ) {
90+ if (!map .containsKey (c )) {
91+ map .put (c , 1 );
92+ }else {
93+ Integer count = map .get (c );
94+ map .put (c , count + 1 );
95+ }
96+ }
97+
98+ //输出统计信息
99+ /*for (Entry<Character, Integer> entry : map.entrySet()) {
100+ System.out.println(entry.getKey() + "出现" + entry.getValue() + "次");
101+ }*/
102+
103+ //获取获取最大值
104+ int maxCount = 0 ;
105+ for (Entry <Character , Integer > entry : map .entrySet ()) {
106+ //不统计空格
107+ if (/*entry.getKey() != ' ' && */ entry .getValue () > maxCount ) {
108+ maxCount = entry .getValue ();
109+ }
110+ }
111+
112+ //map转换成list便于排序
113+ List <Entry <Character , Integer >> mapList = new ArrayList <Map .Entry <Character ,Integer >>(map .entrySet ());
114+ //根据字符出现次数排序
115+ Collections .sort (mapList , new Comparator <Entry <Character , Integer >>(){
116+ @ Override
117+ public int compare (Entry <Character , Integer > o1 ,
118+ Entry <Character , Integer > o2 ) {
119+ return o2 .getValue ().compareTo (o1 .getValue ());
120+ }
121+ });
122+ return mapList ;
123+ }
124+
125+ public static String file2String (String path ) throws IOException {
126+ FileReader reader = new FileReader (new File (path ));
127+ char [] buffer = new char [1024 ];
128+ int len = -1 ;
129+ StringBuffer sb = new StringBuffer ();
130+ while ((len = reader .read (buffer )) != -1 ) {
131+ sb .append (buffer , 0 , len );
132+ }
133+ return sb .toString ();
134+ }
135+
136+ public static void string2File (String data , String path ){
137+ FileWriter writer = null ;
138+ try {
139+ writer = new FileWriter (new File (path ));
140+ writer .write (data );
141+ } catch (Exception e ) {
142+ e .printStackTrace ();
143+ }finally {
144+ if (writer != null ) {
145+ try {
146+ writer .close ();
147+ } catch (IOException e ) {
148+ e .printStackTrace ();
149+ }
150+ }
151+ }
152+
153+ }
154+ }
0 commit comments