Advanced Enigma Cracking
题目要求
本题目需要模拟当年破解Enigma的过程,现在我们已经知道Plugboard, RingSetting, CipherText 和 Word
已知 PlainText 中一定包含单词 Word, 求破解 MessageKey, PlainText 和 RotorNum
由于完全破解耗时太长,输入还会给出3个齿轮中最左侧那个齿轮的编号。
提示
建议你实现一个加密/解密函数 与MyEnigma.exe 产生的结果相对比 完全一致后再考虑破解
提示:函数返回值不能是局部变量的地址。
这里有你可能用到的常量:
char reflector[]="YRUHQSLDPXNGOKMIEBFZCWVJAT";
char rotor_table[5][27] =
{
"EKMFLGDQVZNTOWYHXUSPAIBRCJ",
"AJDKSIRUXBLHWTMCQGZNPYFVOE",
"BDFHJLCPRTXVZNYEIWGAKMUSQO",
"ESOVPZJAYQUIRHXLNFTGKDCMWB",
"VZBRGITYUPSDNHLXAWMJQOFECK"
};
char step_char[5]="RFWKA"; // Royal Flags Wave Kings Above
输入格式:
输入分为5行
第一行给出Plugboard,以空格分隔的10组, 如PO LM IU JK NH YT GB VF RE DC
第二行给出RingSetting,如TIP
(T为左边齿轮内部设置,P为右边齿轮内部设置)
第三行给出需要破解的密文,如MNZUXZEZWCAYJVTODAEFBVKYXW
第四行给出已知明文中包含的单词,如CRYPTO
第五行给出最左侧的齿轮编号,如1
密文长度不超过500,单词长度不超过20
输出格式:
本题保证有且仅有唯一解
假定破解出的MessageKey=XXX, PlainText=YYYYY, RotorNum=123 (1为左边齿轮编号,5为右边齿轮编号),
则程序输出格式如下:
MessageKey=XXX
PlainText=YYYYY
RotorNum=123
输入样例:
PO LM IU JK NH YT GB VF RE DC
TIP
MNZUXZEZWCAYJVTODAEFBVKYXW
CRYPTO
1
输出样例:
MessageKey=CRY
PlainText=CRYPTOISSOINTERESTINGISNIT
RotorNum=125
参考答案:
#include<stdio.h>
#include<malloc.h>
#include<iostream>
#include<string.h>
#include<string>
using namespace std;
char reflector[] = "YRUHQSLDPXNGOKMIEBFZCWVJAT";
char rotor_table[5][27] =
{
"EKMFLGDQVZNTOWYHXUSPAIBRCJ",
"AJDKSIRUXBLHWTMCQGZNPYFVOE",
"BDFHJLCPRTXVZNYEIWGAKMUSQO",
"ESOVPZJAYQUIRHXLNFTGKDCMWB",
"VZBRGITYUPSDNHLXAWMJQOFECK"
};
char step_char[6] = "QEVJZ";
struct Rotor {
int id;
char MK;
char RS;
};
typedef struct Rotor* rotor;
char* crypto(rotor left, rotor right, rotor middle, char* ciphertext, char* plug);
void change(rotor left, rotor right, rotor middle);
void u_change(rotor unit);
char r_crypto(char c, rotor unit);
char rr_crypto(char c, rotor unit);
int main(void) {
char plug[27] = "ABCDEFGHIZKLMNOPQRSTUVWXYZ";
char relate[3];
char RS[4];
char MK[4];
MK[3] = '\0';
char ciphertext[501];
char* plaintext;
string PlainText;
char word[20];
int left, middle, right;
int i;
for (i = 0; i < 10; i++) {
cin >> relate;
plug[relate[0] - 'A'] = relate[1];
plug[relate[1] - 'A'] = relate[0];
}
cin >> RS;
cin >> ciphertext;
cin >> word;
cin >> left;
rotor Left, Right, Middle;
Left = (rotor)malloc(sizeof(struct Rotor));
Right = (rotor)malloc(sizeof(struct Rotor));
Middle = (rotor)malloc(sizeof(struct Rotor));
for (middle = 1; middle <= 5; middle++) {
if (middle == left) {
continue;
}
for (right = 1; right <= 5; right++) {
if (right == left || right == middle) {
continue;
}
for (MK[0] = 'A'; MK[0] <= 'Z'; MK[0]++) {
for (MK[1] = 'A'; MK[1] <= 'Z'; MK[1]++) {
for (MK[2] = 'A'; MK[2] <= 'Z'; MK[2]++) {
Left->id = left;
Left->RS = RS[0];
Middle->RS = RS[1];
Right->RS = RS[2];
Left->MK = MK[0];
Middle->MK = MK[1];
Right->MK = MK[2];
Middle->id = middle;
Right->id = right;
plaintext = crypto(Left, Right, Middle, ciphertext, plug);
PlainText = (string)plaintext;
if (PlainText.find(word) != string::npos) {
printf("MessageKey=%s\n", MK);
printf("PlainText=%s\n", plaintext);
printf("RotorNum=%d%d%d", left, middle, right);
return 0;
}
}
}
}
}
}
return 0;
}
char* crypto(rotor left, rotor right, rotor middle, char* ciphertext, char* plug) {
int length, i;
char c;
length = strlen(ciphertext);
char* plaintext = (char*)malloc(sizeof(char) * (length + 1));
for (i = 0; i < length; i++) {
change(left, right, middle);
c = ciphertext[i];
c = plug[c - 'A'];
c = r_crypto(c, right);
c = r_crypto(c, middle);
c = r_crypto(c, left);
c = reflector[c - 'A'];
c = rr_crypto(c, left);
c = rr_crypto(c, middle);
c = rr_crypto(c, right);
c = plug[c - 'A'];
plaintext[i] = c;
}
plaintext[i] = '\0';
return plaintext;
}
void change(rotor left, rotor right, rotor middle) {
if (right->MK == step_char[right->id - 1] || middle->MK == step_char[middle->id - 1]) {
if (middle->MK == step_char[middle->id - 1]) {
u_change(left);
}
u_change(middle);
}
u_change(right);
}
void u_change(rotor unit) {
if (unit->MK == 'Z') {
unit->MK = 'A';
}
else {
unit->MK++;
}
}
char r_crypto(char c, rotor unit) {
int delta = unit->MK - unit->RS;
c = ((c - 'A') + delta + 26) % 26 + 'A';
c = rotor_table[unit->id - 1][c - 'A'];
c = ((c - 'A') - delta + 26) % 26 + 'A';
return c;
}
char rr_crypto(char c, rotor unit) {
int delta = unit->MK - unit->RS;
c = ((c - 'A') + delta + 26) % 26 + 'A';
for (int i = 0; i < 26; i++) {
if (rotor_table[unit->id - 1][i] == c) {
c = 'A' + i;
break;
}
}
c = ((c - 'A') - delta + 26) % 26 + 'A';
return c;
}