目录
1 题意
将某个ASCII码文本用如下算法加密。
for(int i=0;i<contentLength;i+=keyLength){
for(int j=0;j<keyLength&&i+j<contentLength;j++){
fprintf(f,"%.2x",content[i+j]^key[j]);
}
}
加密后的密文如下。现要求通过密文得出原文。
7b000f0c241a113f490d433201072b4b245f640e21065a35080801604655216338562917462d0b384
1075a7f49137954505f78541c7142184b4c6c67220a3e4907093b521065595a056952446a590a5a6
d4e473f6f456867012000523107154f2352456102100d77555e7f0e674a476d467b73636368663554
7f53143b1066454e6b4a18090b472c1d1e3d49030a2e00073f49584366101d210929121d4b6f1d143
4104109271d553307524223041d2d0b2b411a0f2a52163d07061b204f1a3c4945582f164e270a2804
406d6f525a78191306261b13724b615c23041d21453f140c0a26065a350c4d4f3c07103449485f334
5192d09204109023b523b1b495b4261331b78400a3a66454e64153e080013295a580c01044f230a0
c7a0042101e0c0f2b2d2314340e7e423c3d07250a040e1b3d26434a1a0b4c6d5e46414e476f5d550
c01044f291a0132064343660a08641124081d473f00153a0504026855553600524332041c6404220
54e0320001b3d040e0127047f7a49111034001a311722415e5c450f70
链接:link。
2 思路
从加密算法可以看出,其利用一个密文序列 k e y key key异或加密一个ASCII文件 c o n t e n t content content,并将加密后的ASCII字符按两位十六进制输出(一个ASCII码用8位表示,对应两个十六进制位)。
2.1 将密文还原为十进制
为了更便于处理,现将十六进制密文转化为十进制,并用空格隔开每个密文字符。
123 0 15 12 36 26 17 63 73 13 67 50 1 7 43 75 36 95 100 14 33 6 90 53 8 8 1 96 70 85 33 99 56
86 41 23 70 45 11 56 65 7 90 127 73 19 121 84 80 95 120 84 28 113 66 24 75 76 108 103 34 10 62
73 7 9 59 82 16 101 89 90 5 105 82 68 106 89 10 90 109 78 71 63 111 69 104 103 1 32 0 82 49 7
21 79 35 82 69 97 2 16 13 119 85 94 127 14 103 74 71 109 70 123 115 99 99 104 102 53 84 127
83 20 59 16 102 69 78 107 74 24 9 11 71 44 29 30 61 73 3 10 46 0 7 63 73 88 67 102 16 29 33 9
41 18 29 75 111 29 20 52 16 65 9 39 29 85 51 7 82 66 35 4 29 45 11 43 65 26 15 42 82 22 61 7 6
27 32 79 26 60 73 69 88 47 22 78 39 10 40 4 64 109 111 82 90 120 25 19 6 38 27 19 114 75 97 92
35 4 29 33 69 63 20 12 10 38 6 90 53 12 77 79 60 7 16 52 73 72 95 51 69 25 45 9 32 65 9 2 59 82
59 27 73 91 66 97 51 27 120 64 10 58 102 69 78 100 21 62 8 0 19 41 90 88 12 1 4 79 35 10 12
122 0 66 16 30 12 15 43 45 35 20 52 14 126 66 60 61 7 37 10 4 14 27 61 38 67 74 26 11 76 109
94 70 65 78 71 111 93 85 12 1 4 79 41 26 1 50 6 67 67 102 10 8 100 17 36 8 29 71 63 0 21 58 5 4
2 104 85 85 54 0 82 67 50 4 28 100 4 34 5 78 3 32 0 27 61 4 14 1 39 4 127 122 73 17 16 52 0 26
49 23 34 65 94 92 69 15 112
2.2 推测密钥的头几个字符
一般来说cpp文件第一句话就是"#include",所以将这几个字符与前几个密文进行异或。
ENC 123 0 15 12 36 26 17 63
ORI # i n c l u d e
ASC 23 69 110 63 108 75 64 65
KEY 58 69 61 111 48 111 75 90
ASC X i a o H o u Z
得出明文密钥第一部分"XiaoHouZ"
2.3 推测密钥的长度
以"XiaoHouZ"为模板暴力异或,找出第一个有意义的字符串。
2.3.1 代码
#include<iostream>
#include<cstdio>
#include<string>
#include<cctype>
using namespace std;
int content[]={123,0,15,12,36,26,17,63,73,13,67,50,1,7,43,75,36,95,100,14,33,6,90,53,8,8,1,96,70,85,33,99,56,86,41,23,70,45,11,56,65,7,
90,127,73,19,121,84,80,95,120,84,28,113,66,24,75,76,108,103,34,10,62,73,7,9,59,82,16,101,89,90,5,105,82,68,106,89,10,90,
109,78,71,63,111,69,104,103,1,32,0,82,49,7,21,79,35,82,69,97,2,16,13,119,85,94,127,14,103,74,71,109,70,123,115,99,99,104,
102,53,84,127,83,20,59,16,102,69,78,107,74,24,9,11,71,44,29,30,61,73,3,10,46,0,7,63,73,88,67,102,16,29,33,9,41,18,29,75,
111,29,20,52,16,65,9,39,29,85,51,7,82,66,35,4,29,45,11,43,65,26,15,42,82,22,61,7,6,27,32,79,26,60,73,69,88,47,22,78,39,
10,40,4,64,109,111,82,90,120,25,19,6,38,27,19,114,75,97,92,35,4,29,33,69,63,20,12,10,38,6,90,53,12,77,79,60,7,16,52,73,72,
95,51,69,25,45,9,32,65,9,2,59,82,59,27,73,91,66,97,51,27,120,64,10,58,102,69,78,100,21,62,8,0,19,41,90,88,12,1,4,79,35,
10,12,122,0,66,16,30,12,15,43,45,35,20,52,14,126,66,60,61,7,37,10,4,14,27,61,38,67,74,26,11,76,109,94,70,65,78,71,111,93,
85,12,1,4,79,41,26,1,50,6,67,67,102,10,8,100,17,36,8,29,71,63,0,21,58,5,4,2,104,85,85,54,0,82,67,50,4,28,100,4,34,5,78,
3,32,0,27,61,4,14,1,39,4,127,122,73,17,16,52,0,26,49,23,34,65,94,92,69,15,112};
int main(){
string key="XiaoHouZ";
for(int i=0;i<=391-key.size();i++){
cout<<"|"<<i+1<<"|";
string str;
for(int j=0;j<key.size();j++){
printf("%d",content[i+j]^key[j]);
if(j!=key.size()-1) cout<<" ";
else cout<<"|";
str.push_back(content[i+j]^key[j]);
}
for(auto c:str){
if(!isprint(c)){
cout<<"\\\\("<<oct<<int(c)<<dec<<")";
}else{
cout<<c;
}
}
cout<<"|"<<endl;
}
}
2.3.2 结果
i | 十进制表示 | 字符表示(非可打印字符用转义字符表示) |
---|---|---|
1 | 35 105 110 99 108 117 100 101 | #include |
2 | 88 102 109 75 82 126 74 19 | XfmKR~J\(23) |
3 | 87 101 69 117 89 80 60 87 | WeEuYP<W |
4 | 84 77 123 126 119 38 120 25 | TM{~w&x\(31) |
5 | 124 115 112 80 1 98 54 104 | |
6 | 66 120 94 38 69 44 71 91 | Bx^&E,G[ |
7 | 73 86 40 98 11 93 116 93 | IV(b\(13)]t] |
8 | 103 32 108 44 122 110 114 113 | g l,znrq |
9 | 17 100 34 93 73 104 94 17 | \(21)d"]Ih^\(21) |
10 | 85 42 83 110 79 68 62 126 | U*SnOD>~ |
11 | 27 91 96 104 99 36 81 5 | \(33)[`hc$Q\(5) |
12 | 106 104 102 68 3 75 42 62 | jhfD\(3)K*> |
13 | 89 110 74 36 108 48 17 84 | YnJ$l0\(21)T |
14 | 95 66 42 75 23 11 123 123 | _B*K\(27)\(13){{ |
15 | 115 34 69 48 44 97 84 92 | s"E0,aT\ |
16 | 19 77 62 11 70 78 115 0 | \(23)M>\(13)FNs\(0) |
17 | 124 54 5 97 105 105 47 111 | |
18 | 7 13 111 78 78 53 64 82 | \(7)\(15)oNN5@R |
19 | 60 103 64 105 18 90 125 82 | <g@i\(22)Z}R |
20 | 86 72 103 53 125 103 125 91 | VHg5}g}[ |
21 | 121 111 59 90 64 103 116 58 | yo;Z@gt: |
22 | 94 51 84 103 64 110 21 28 | ^3Tg@n\(25)\(34) |
23 | 2 92 105 103 73 15 51 15 | \(2)\igI\(17)3\(17) |
24 | 109 97 105 110 40 41 32 123 | main() { |
25 | 80 97 96 15 14 58 84 57 | Pa`\(17)\(16):T9 |
26 | 80 104 1 41 29 78 22 98 | Ph\(1))\(35)N\(26)b |
27 | 89 9 39 58 105 12 77 12 | Y\(11)’:i\(14)M\(14) |
28 | 56 47 52 78 43 87 35 115 | 8/4N+W#s |
29 | 30 60 64 12 112 57 92 77 | \(36)<@\(14)p9\M |
30 | 13 72 2 87 30 70 98 28 | \(15)H\(2)W\(36)Fb\(34) |
31 | 121 10 89 57 97 120 51 119 | y\(12)Y9ax3w |
32 | 59 81 55 70 95 41 88 81 | ;Q7F_)XQ |
33 | 96 63 72 120 14 66 126 98 | `?Hx\(16)B~b |
34 | 14 64 118 41 101 100 77 27 | \(16)@v)edM\(33) |
35 | 113 126 39 66 67 87 52 93 | q~'BCW4] |
36 | 79 47 76 100 112 46 114 0 | O/Ldp.r\(0) |
37 | 30 68 106 87 9 104 47 37 | \(36)DjW\(11)h/% |
38 | 117 98 89 46 79 53 10 19 | ubY.O5\(12)\(23) |
39 | 83 81 32 104 18 16 60 73 | SQ h\(22)\(20)<I |
40 | 96 40 102 53 55 38 102 35 | `(f57&f# |
41 | 25 110 59 16 1 124 12 14 | \(31)n;\(20)\(1) |
42 | 95 51 30 38 91 22 33 10 | _3\(36)&[\(26)!\(12) |
43 | 2 22 40 124 49 59 37 5 | \(2)\(26)( |
44 | 39 32 114 22 28 63 42 34 | ’ r\(26)\(34)?*" |
45 | 17 122 24 59 24 48 13 14 | \(21)z\(30);\(30)0\(15)\(16) |
46 | 75 16 53 63 23 23 33 70 | K\(20)5?\(27)\(27)!F |
47 | 33 61 49 48 48 59 105 43 | !=100;i+ |
48 | 12 57 62 23 28 115 4 24 | \(14)9>\(27)\(34)s\(4)\(30) |
49 | 8 54 25 59 84 30 55 66 | \(10)6\(31);T\(36)7B |
50 | 7 17 53 115 57 45 109 17 | \(7)\(21)5s9-m\(21) |
… | … | … |
2.3.3 结论
当 i = 24 i=24 i=24时,出现"main() {"这几个字符,得知密钥长度为23。
2.4 推测密钥的剩余部分
“main() {“之前应该是"int “,所以密钥的末尾四个字符为"gOrz”。
此时中间还差了
11
11
11个字符,推测中间的明文为” <stdio.h>\n”,进而得到中间的密钥为"i10FenDeLan"
综上key值为"XiaoHouZi10FenDeLangOrz"。
2.5 利用密钥破译密文
2.5.1 代码
#include<iostream>
#include<cstdio>
using namespace std;
int content[]={123,0,15,12,36,26,17,63,73,13,67,50,1,7,43,75,36,95,100,14,33,6,90,53,8,8,1,96,70,85,33,99,56,86,41,23,70,45,11,56,65,7,
90,127,73,19,121,84,80,95,120,84,28,113,66,24,75,76,108,103,34,10,62,73,7,9,59,82,16,101,89,90,5,105,82,68,106,89,10,90,
109,78,71,63,111,69,104,103,1,32,0,82,49,7,21,79,35,82,69,97,2,16,13,119,85,94,127,14,103,74,71,109,70,123,115,99,99,104,
102,53,84,127,83,20,59,16,102,69,78,107,74,24,9,11,71,44,29,30,61,73,3,10,46,0,7,63,73,88,67,102,16,29,33,9,41,18,29,75,
111,29,20,52,16,65,9,39,29,85,51,7,82,66,35,4,29,45,11,43,65,26,15,42,82,22,61,7,6,27,32,79,26,60,73,69,88,47,22,78,39,
10,40,4,64,109,111,82,90,120,25,19,6,38,27,19,114,75,97,92,35,4,29,33,69,63,20,12,10,38,6,90,53,12,77,79,60,7,16,52,73,72,
95,51,69,25,45,9,32,65,9,2,59,82,59,27,73,91,66,97,51,27,120,64,10,58,102,69,78,100,21,62,8,0,19,41,90,88,12,1,4,79,35,
10,12,122,0,66,16,30,12,15,43,45,35,20,52,14,126,66,60,61,7,37,10,4,14,27,61,38,67,74,26,11,76,109,94,70,65,78,71,111,93,
85,12,1,4,79,41,26,1,50,6,67,67,102,10,8,100,17,36,8,29,71,63,0,21,58,5,4,2,104,85,85,54,0,82,67,50,4,28,100,4,34,5,78,
3,32,0,27,61,4,14,1,39,4,127,122,73,17,16,52,0,26,49,23,34,65,94,92,69,15,112};
int main(){
char key[]="XiaoHouZi10FenDeLangOrz";
for(int i=0;i<391;i+=23){
for(int j=0;j<23&&i+j<391;j++){
printf("%c",content[i+j]^key[j]);
}
}
}
2.5.2 解密结果
#include <stdio.h>
int main() {
for(int i=0;i!=100;i++){
for(int j=0;j!=100;j++){
for(int k=0;k!=100;k++)
;
};
}
//The code before is useless, only for increasing the length of this code.
printf("Please submit me, then you will get AC :-)\n");
printf("The key is XiaoHouZi10FenDeLangOrz\n");
//The authors of this problem : licstar and doraemonok
return 0;
}