#include
typedef struct
{
long values[40][40];
long total;
}
BIGRAMM;
#include "etalon.h"
BIGRAMM current;
// использованный алфавит (укороченный в целях упрощения)
// «а» маленькое играет роль пробела и заменителя всех остальных знаков
unsigned char alpha[33] = {'А','Б','В','Г','Д','Е','Ж','З','И','Й','К','Л',
'М','Н','О','П','Р','С','Т','У','Ф','Х','Ц','Ч','Ш','Щ','Ъ','Ы','Ь',
'Э','Ю','Я','а'};
// ключ-таблица для зашифрования
unsigned char key[33] = {'Б','В','Г','Д','Е','Ж','З','И','Й','К','Л','М','Н',
'О','П','Р','С','Т','У','Ф','Х','Ц','Ч','Ш','Щ','Ъ','Ы','Ь','Э',
'Ю','Я','а','А'};
// ключ-таблица для расшифрования
unsigned char right_unkey[33] = {'Я','а','А','Б','В','Г','Д','Е','Ж','З','И',
'Й','К','Л','М','Н','О','П','Р','С','Т','У','Ф','Х','Ц','Ч',
'Ш','Щ',
'Ъ','Ы','Ь','Э','Ю'};
unsigned char unkey[33] = {'Е','П','Р','С','Т','Я','а','А','Б','В','Г','Д','Ж','З',
'И','Й','К','Л','М','Н','О','У','Ф','Х','Ц','Ч','Ш','Щ','Ъ',
'Ы','Ь','Э','Ю'};
// шифр простой замены
void encrypt(unsigned char *buf, int len, char *key) {
for (int i = 0; i < len; i++)
if (buf[i] >= 0xC0 && buf[i] <= 0xE0) buf[i] = key[buf[i]-0xC0];
}
void decrypt(unsigned char *buf, int len, char *key) {
for (int i = 0; i < len; i++)
if (buf[i] >= 0xC0 && buf[i] <= 0xE0) buf[i] = unkey[buf[i]-0xC0];
}
// вычисляем биграммы
void calc_gramm(unsigned char *buf, int len) {
for (int i = 0; i < len-1; i++) {
current.values[ buf[i]-0xC0 ][ buf[i+1]-0xC0 ]++;
current.total++;
}
}
// вычисляем «расстояние» рабочего ключа до настоящего
double calc_measure()
{
double result = 0;
if (!current.total) current.total++;
for (int i = 0; i < 40; i++)
for (int j = 0; j < 40; j++)
result += fabs(((double) current.values[i][j]/current.total) -
((double) etalon.values[i][j]/etalon.total));
return result;
}
// поиск ключа
void findkey_jakobsen(char *buf, int len, char *guesskey) {
char work_key[33];
double V, V_;
int c, pos, sym;
char *temp, s;
temp = (char *) malloc(len);
memcpy(work_key, guesskey, sizeof(work_key));
strncpy(temp, buf, len);
memset(¤t, 0, sizeof(current));
calc_gramm(temp, len);
V = calc_measure();
randomize();
c = 0;
for (;;) {
// переставляем символы в ключе
pos = rand() % 33;
sym = (pos + 1 + rand()) % 33;
s = work_key[pos];
work_key[pos] = work_key[sym];
work_key[sym] = s;
// дешифруем текст
strncpy(temp, buf, len);
decrypt(temp, len, work_key);
memset(¤t, 0, sizeof(current));
calc_gramm(temp, len);
// считаем расстояние до эталона
V_ = calc_measure();
if (++c % 1000 == 0) printf("%f < %f, %d, %d\n", V_, V, pos, sym);
if (V_ < V) {
// ура! улучшили результат!
printf("WORK_KEY == %s, KEY = %s (V == %f, V_ == %f)",
work_key, guesskey, V, V_);
printf("!!!\n", work_key);
memcpy(guesskey, work_key, sizeof(work_key));
V = V_;
}
else
// оставляем все без изменений
memcpy(work_key, guesskey, sizeof(work_key));
}
printf("%f", V);
}
#define MAKE_ETALON 0
int main(int argc, char* argv[])
{
char text[] = "Каждое время года имеет свою особенность. Зимой всё покрывается белым снегом. Зима начинает год и заканчивает его. Весной снег тает, распускаются цветы, прилетают птицы, цветут сады. Летом созревают ягоды, грибы, овощи и фрукты. Это самая теплая пора года. Осенью природа засыпает. Опадают листья";
int len = strlen(text);
for (int i = 0; i < len; i++)
if (text[i] < 'А' || text[i] > 'Я') text[i] = 0xE0;
// создание эталона
if (MAKE_ETALON) {
FILE *f = fopen("collect.txt", "rb");
char buf[32768];
while (!feof(f)) {
int r = fread(buf, 1, sizeof(buf), f);
for (int i = 0; i < r; i++) if (buf[i] < 'А' || buf[i] > 'Я')
buf[i] = 0xE0;
calc_gramm(buf, r);
}
fclose(f);
f = fopen("etalon.h", "wt");
fprintf(f, "BIGRAMM etalon = {\n");
for (int i = 0; i < 40; i++) {
for (int j = 0; j < 40; j++)
fprintf(f, "%d ", current.values[i][j]);
fprintf(f, "\n");
}
fprintf(f, "%d };\n", current.total);
fclose(f);
return 0;
}
encrypt(text, len, key);
printf("%s\n", text);
findkey_jakobsen(text, len, unkey);
decrypt(text, len, unkey);
printf("%s\n", text);
return 0;
}
Do'stlaringiz bilan baham: |