/*
各文字はそれぞれ一意のコードに割り当てられている.
よく使われる標準としてASCII (American Standard Code for Information Interchange) がある.
ASCIIでは, 大文字A = 65, アスタリスク (*) = 42, 小文字k = 107というふうに割り当てられている.
モダンな暗号化の方法として, テキストファイルの各バイトをASCIIに変換し,
秘密鍵から計算された値とXORを取るという手法がある.
XOR関数の良い点は, 暗号化に用いたのと同じ暗号化鍵でXORを取ると平文を復号できる点である.
65 XOR 42 = 107であり, 107 XOR 42 = 65である.
破られない暗号化のためには, 鍵は平文と同じ長さのランダムなバイト列でなければならない.
ユーザーは暗号文と暗号化鍵を別々の場所に保存する必要がある.
また, もし一方が失われると, 暗号文を復号することは不可能になる.
悲しいかな, この手法はほとんどのユーザーにとって非現実的である.
そこで, 鍵の変わりにパスワードを用いる手法が用いられる.
パスワードが平文より短ければ (よくあることだが), パスワードは鍵として繰り返し用いられる.
この手法では, 安全性を保つために十分長いパスワードを用いる必要があるが,
記憶するためにはある程度短くないといけない.
この問題での課題は簡単になっている. 暗号化鍵は3文字の小文字である.
cipher1.txtは暗号化されたASCIIのコードを含んでいる.
また, 平文はよく用いられる英単語を含んでいる. この暗号文を復号し, 平文のASCIIでの値の和を求めよ.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
#define N 1210
// 英文に使われてそうな文字ならtrue
bool check(int c) {
return isalnum(c) || isspace(c) ||
c == ',' || c == '.' || c == ':' || c == ';' ||
c == '?' || c == '!' || c == '\'' || c == '(' || c == ')';
}
int main(void) {
FILE *cipher1;
char cipher[N], plain[N];
int cipherLen;
char key[3];
char key0, key1, key2;
int sum;
int i;
char *str;
cipher1 = fopen("cipher1.txt", "r");
if( cipher1 == NULL ) {
fprintf(stderr, "can't open \"cipher1.txt\"");
exit(EXIT_FAILURE);
}
for( cipherLen = 0; fscanf(cipher1, "%d,", cipher + cipherLen) != EOF; cipherLen++ );
for( key0 = 'a'; key0 <= 'z'; key0++ ) {
for( key1 = 'a'; key1 <= 'z'; key1++ ) {
for( key2 = 'a'; key2 <= 'z'; key2++ ) {
key[0] = key0;
key[1] = key1;
key[2] = key2;
for( i = 0; i < cipherLen; i++ ) {
plain[i] = cipher[i] ^ key[i % 3];
if( !check(plain[i]) ) break;
}
if( i == cipherLen ) {
plain[i] = '\0';
sum = 0;
for( i = 0; i < cipherLen; i++ ) {
sum += plain[i];
}
puts(plain);
printf("%d\n\n", sum);
}
}
}
}
fclose(cipher1);
return 0;
}