Известная атака открытым текстом по алгоритму Берлекампа-Месси
Я реализовал алгоритм Berlekamp-Massey в ANSI C. У меня есть зашифрованный текст, который я хочу расшифровать, и первые 491 байт открытого текста.
Я написал программу, которая использует Berlekamp-Massey как функцию, чтобы получить минимальный LFSR и найти следующие ключи, чтобы расшифровать остальную часть зашифрованного текста.
Я прочитал последние 4 байта открытого текста и XOR их с соответствующими 4 байтами в зашифрованном тексте, чтобы получить ключевой поток, который был использован. Затем я даю ключевой поток в качестве аргумента функции Берлекампа-Месси. Массив f содержит LFSR, рассчитанный Берлекампом-Мэсси в форме 0 и 1, которые представляют полином, описывающий LFSR.
Так что теперь я должен быть в состоянии рассчитать остаток ключевого потока как таковой:
Где pj представлен массивом f, si - поток ключей, а умножение - логическое AND. Я вычисляю следующие 32 бита потока ключей и XOR их с соответствующим зашифрованным текстом, чтобы получить открытый текст.
Как вы можете видеть, я сделал это только для первых 4 байтов, которые я хочу расшифровать, для целей тестирования.
Проблема в том, что созданный открытый текст неверен. Когда я открываю его с помощью gedit, я получаю это:
Несколько замечаний по поводу кода:
- bm () - это функция, реализующая алгоритм Берлекампа-Масси.
- int2bin () принимает десятичное число и заполняет массив соответствующим двоичным файлом.
- Я читаю текст, который я читаю, и ключ как целые числа, используя маскирование, умножение и деление с конкретными числами. Это проще, чем обрабатывать их в двоичном формате.
Код:
int main(int argc, char** argv) {
short key_bin[32];
FILE plain_in, plain_out, *cipher_in;
plain_in = fopen("plaintext_known.txt", "r");
cipher_in = fopen("ciphertext_full.txt", "r");
plain_out = fopen("plain_out.txt", "a");
int plain32[4], cipher32[4], i, j, s, f[33], g[32], temp[33], n=0, d=0, count=1;
unsigned long plain, cipher, keystream;
fseek(plain_in, 488, SEEK_SET);
plain32[3] = fgetc(plain_in);
plain32[2] = fgetc(plain_in);
plain32[1] = fgetc(plain_in);
plain32[0] = fgetc(plain_in);
printf("plain: %d %d %d %d\n", plain32[3], plain32[2], plain32[1], plain32[0]);
fseek(cipher_in, 488, SEEK_SET);
cipher32[3] = fgetc(cipher_in);
cipher32[2] = fgetc(cipher_in);
cipher32[1] = fgetc(cipher_in);
cipher32[0] = fgetc(cipher_in);
printf("cipher: %d %d %d %d\n", cipher32[3], cipher32[2], cipher32[1], cipher32[0]);
plain = (unsigned long)plain32[3]*16777216 + (unsigned long)plain32[2]*65536
+ (unsigned long)plain32[1]*256 + (unsigned long)plain32[0];
cipher = (unsigned long)cipher32[3]*16777216 + (unsigned long)cipher32[2]*65536
+ (unsigned long)cipher32[1]*256 + (unsigned long)cipher32[0];
keystream = plain ^ cipher;
int2bin(keystream, 32, key_bin);
g[0]=1;
f[0]=1;
for(i=1; i<32; i++){
f[i]=0;
g[i]=0;
}
f[32]=0;
bm(32, key_bin, f, g, temp, d, n, count);
cipher32[3] = fgetc(cipher_in);
cipher32[2] = fgetc(cipher_in);
cipher32[1] = fgetc(cipher_in);
cipher32[0] = fgetc(cipher_in);
cipher = (unsigned long)cipher32[3]*16777216 + (unsigned long)cipher32[2]*65536
+ (unsigned long)cipher32[1]*256 + (unsigned long)cipher32[0];
keystream = 0;
for(i=0; i<32; i++){
s = f[1] & (int)key_bin[31];
for(j=1; j<32; j++){
s = s ^ (f[j+1] & (int)key_bin[31-j]);
}
if(s==1)
keystream += (unsigned long)pow((double)2, (double)i);
}
plain = keystream ^ cipher;
plain32[0] = plain & 255;
plain32[1] = (plain & 65280)/256;
plain32[2] = (plain & 16711680)/65536;
plain32[3] = (plain & 4278190080)/16777216;
fprintf(plain_out, "%c%c%c%c", plain32[3], plain32[2], plain32[1], plain32[0]);
fclose(plain_in);
fclose(plain_out);
fclose(cipher_in);
return (EXIT_SUCCESS);
}