1. Пользуйтесь тегами кода. - [code] ... [/code] 2. Точно указывайте язык, название и версию компилятора (интерпретатора). 3. Название темы должно быть информативным. В описании темы указываем язык!!!
Здравствуйте! Требуется реализовать алгоритм блочного шифрования ГОСТ 28147-89 в следующих режимах шифрования: режим простой замены; режим гаммирования; режим гаммирования с обратной связью. Программа должна запрашивать имя входного и выходного файлов, ключ, вектор инициализации (синхропосылку), режим работы (зашифрование или расшифрование), режим шифрования.
У меня прежде всего вопрос по организации данных.. В соответствии с алгоритмом
размер блока – 64 бита; - размер ключа – 256 бит. Ключ представляется как массив из восьми 32-битных подключей K={K0,K1,…,K7}; - количество S-блоков – 8. Каждый S-блок (в терминах стандарта – узел замены) содержит 16 четырехбитных значений, представляющих собой произвольную перестановку чисел от 0 до 15. Совокупность всех S-блоков можно представить в виде матрицы (таблицы замен) размером 8 на 16.
Скажите пожалуйста, какие типы правильнее использовать для массива ключей и таблицы замен?
какие типы правильнее использовать для массива ключей и таблицы замен?
Язык - С++, как видно? Тогда тебе нельзя привязываться к размеру конкретного типа, а единственный тип, который имеет одинаковый размер везде - это char. Там что или описывай все в байтах:
typedef unsigned char Tsubkey[4]; // 32 bit typedef Tsubkey Tkey[8]; // 8 * 32 bit
(представляй каждый элемент типа Tsubkey отдельным битом...) В первом случае будет меньше размер, занимаемый данными. Во втором - размер (возможно) будет больше (если компилятор не оптимизирует), но зато будет очень быстрый доступ к битам, причем можно будет элементарно "убрать" разницу между little-endian и big-endian.
Все вышесказанное можешь не принимать во внимание, если твоя задача - реализовать это под строго заданным компилятором и под одной аппаратной платформой. Тогда можешь выбирать, что тебе больше нравится - работать с битами внутри байта, или работать с bool-ами и потом "собирать" байты из них. Я бы все-таки выбрал второй вариант...
Ой..Забыла указать, да, язык С++ (Builder C++ 6).. Скажи пожалуйста, если действовать таким образом, то как ключ вводить (одним числом или нет)? И как заполнять Tsubkey?
Строкой... Все вводится строкой. Если длина ключа - 256 бит, то длина строки должна быть = 256/8 = 32 символа. Ввела 32-символьную строку, "перевела" ее в биты, и работай дальше. Вот пример "перевода" строки в последовательность бит, и обработки ПОДключа:
Мне не очень понятно, как поступить с таблицей замен..Каждая из 8-ми строк там содержит 4-хбитные числа от 0 до 15..Преподаватель несколько упростил задачу: предложил самостоятельно её составить, хранить соответственно в файле.. Объясните мне пожалуйста, как тогда добиться при её считывании в некотором смысле единообразия с тем, как поступаем с ключом?
Пока не могу добиться нормального считывания из файла... если содержимое файла такое 15 0 3 12.... то считываются числа порядка 13617 и в таком духе.. Помогите, пожалуйста, разобраться с этим..!
Файл текстовый? Двоичный? Здесь не форум телепатов, если ты хочешь, чтоб тебе помогли - приводи информацию, которая будет полезна, а не какие-то обрывки...
Если файл текстовый - почему открыт без "rt", и зачем читаешь из него fread-ом? Если двоичный - почему открыт без "rb"? Пример файла приведи (запакуй его и присоедини).
У меня ещё вопрос по считыванию блока текста (текст в текстовом файле)..По алгоритму размер такого блока 64 бита.. Здесь снова использовать fscanf или можно и fread? Пробовала и то, и то - в результате считывается что-то странное, а не то, что представлено в файле..
int N1,N2; __int64 N; f=fopen(fileIn,"rt"); while (!feof(f)) { fscanf(f, "%s", &N); //fread(&N,sizeof(__int64),1,f); }
Кроме того, входной блок должен быть разбит на правую и левую части (соответственно по 32 бита). Объясните пожалуйста, как это производится?
// Можно предварительно создать форматную строку, чтоб не привязываться // к "магическому числу" 8, вместо использования sizeof(__int64) fscanf(f, "%8s", str); } value64 = *(__int64*)(&str[0]); // копируем содержимое строки как __int64
В общем, выше показано, как прочитать блок символов определенной длины из текстового файла. Дальше делай с ним, что тебе надо...
Итак..далее.. У меня будет функция (выступающая в качестве основного шага криптопреобразования) по преобразованию очередного 64-битного блока текста (его и будет возвращать ф-ция), в которую помимо этого блока необходимо передавать подключи в таком порядке: К0К1К2К3К4К5К6К7К0К1К2К3К4К5К6К7К0К1К2К3К4К5К6К7К7К6К 5К4К3К2К1К0.. Вызов функции с такой последовательностью ключей обеспечивает шифрование блока открытого текста в режиме простой замены.. И мне не понятно, как передать определённый подключ в функцию.. Объясните пожалуйста..!
p.s. привожу статью, на которую опираюсь (пункты 1.3, 1.4, 1.5)
мне не понятно, как передать определённый подключ в функцию..
Я ж тебе в четвертом посте показывал, как работать с под-ключами, как "выдирать" их из ключа в любом порядке...
У тебя есть документы, которые содержат все необходимые тебе преобразования. Продумай, наконец, систему типов программы. Продумай систему преобразований типов (явных или неявных, может, будет проще написать небольшой класс, может, будет проще работать с массивами bool-ов, может - со строками, может - с __int64, я не знаю, у меня информация об алгоритме только очень отрывочная), а то так и будешь плавать в ненужных наворотах от одной задачи к другой. Я не буду делать все задание за тебя. Это мне не интересно (кстати, я сомневаюсь, что программная реализация стандарта шифрования ГОСТ 28147-89 вообще законна, у меня есть документ, однозначно утверждающий: "приведенный ниже материал не должен ни при каких условиях использоваться для программной или аппаратной реализации алгоритма криптографического преобразования" (С), так что можно ли вообще делать то, что ты делаешь - еще очень большой вопрос)
...так что можно ли вообще делать то, что ты делаешь - еще очень большой вопрос)
Ну поскольку учебная программа предполагает, то почему нельзя?) И к тому же, программа-то не предназначена для использования вне учебных целей)
Вообщем реализовала я основной шаг криптопреобразования, шифрование-дешифрование в режиме простой замены.. Вот только в процессе зашифрования получаю идентичный исходному текст...
int blokS[8][16]; __int32 Keys[8]; char *fileS,*fileIn,*fileOut; //основной шаг __int64 BaseStep(__int64 N,__int32 Key) { __int32 L,R,S,helpS=0; int i,Sm; R = (N & 0x00000000FFFFFFFF); L = (N & 0xFFFFFFFF00000000) >> 32; S = (R+Key)%0xffffffff; for (i=0;i<8;i++) //замена с использование таблицы замен { Sm=(S&0xf); S=S>>4; helpS=(helpS|blokS[i][Sm])<<4; } helpS=helpS<<11; helpS=helpS^L; //меняем половины местами и получаем преобразованный блок L=R; R=helpS; N=0; N=(N|L)<<32; N=N|R; return N; }
__int64 emcryption(__int64 n) { int k,j; __int32 l; for (k=0; k<3; k++) for (j=0; j<8; j++) n=BaseStep(n,Keys[j]); for (j=7; j>=0; j--) n=BaseStep(n,Keys[j]); l = (n & 0xFFFFFFFF00000000) >> 32; n=(n & 0x00000000FFFFFFFF)<<32; n=n|l; return n; }
__int64 decryption(__int64 n) { int k,j; __int32 l; for (j=0; j<8; j++) n=BaseStep(n,Keys[j]); for (k=0; k<3; k++) for (j=7; j>=0; j--) n=BaseStep(n,Keys[j]); l = (n & 0xFFFFFFFF00000000) >> 32; n=(n & 0x00000000FFFFFFFF)<<32; n=n|l; return n; }
void __fastcall TFormMain::ButBeginClick(TObject *Sender) { int i; //Ключ for (i=0;i<8;i++) Keys[i]=StrToInt(MemoKey->Lines->Strings[i]);
Поправила вызов функций зашифрования-расшифрования... Приведённый выше файл удалось зашифровать..Но результат расшифрования не совпал с исходным текстом... Зашифрование-расшифрование проводилось с ключом (1;2;3;4;5;6;7;8) - вводится в Memo..
Все-таки что-то не так в функции decryption(): если сделать точку останова и посмотреть, какое значение получилось после прочтения исходного текста в N (еще до encryption), а потом сравнить его со значением N после decryption, то выясняется, что после decryption значение N = -1. Хотя в самом начале было совсем другое значения.
Это первое. Второе: ты все запутала окончательно. Смотри... Ты читаешь изначальный текст из файла 2.txt, значит, входной файл у тебя там, перед шифрованием, должен открываться как "rt", а выходной (поскольку записываешь ты в него __int64) должен открываться как "wb"... Не просто "w", а именно "wb"... ТЕперь обратный процесс: ты читаешь данные для дешифрования из бинарного файла, т.е., открываться должен как "rb", а пишешь в decrypted.txt - как в текстовый - значит, вот так:
// шифрование: f = fopen("2.txt","rt"); FILE *fOut; fOut=fopen(fileIn,"wb"); // encrypted.txt __int32 L,R; while (!feof(f)) { char str[sizeof(__int64) + 1] = {0}; fscanf(f, "%8s", str); // читаешь как строку из txt-файла N = *(__int64*)(&str[0]); N=emcryption(N); fwrite(&N,sizeof(__int64),1,fOut); // пишешь в бинарный файл как значение __int64 } fclose(fOut);
// дешифрование f=fopen(fileIn,"rb"); // encrypted.txt FILE *fOut; fOut=fopen(fileOut,"wt"); // decrypted.txt __int32 L,R; while (!feof(f)) { char str[sizeof(__int64) + 1] = {0}; fread(&N, sizeof(__int64), 1, f); // читаешь значение __int64 N=decryption(N); // шифруешь это значение N. Но тут почему-то получается (-1) fprintf(fOut, "%8s\0", (char*)(&N)); // а вот пишешь - уже строку } fclose(fOut);
Так... А вот теперь я разбирался со всеми функциями. И вот что удалось сделать:
1) не работай со знаковыми __int64, везде придется поменять этот тип на unsigned __int64... 2) в некоторых местах я убрал заведомо лишние действия, и добавил явные приведения типов там, где без них могут быть проблемы... 3) самое главное: в функции BaseStep ты делаешь:
Цитата
helpS=helpS<<11;
- это совершенно неверно. В твоем документа ясно сказано, что сдвиг должен быть циклическим, т.е., выталкиваемый слева бит становится крайним справа. Это тоже поправил... 4) Ну, по мелочам: сделал локальные переменные в циклах, убрал неиспользуемые массивы и переменные, при чтении из зашифрованного файла проверяю значение, возвращаемое fread, иначе в расшифрованный файл записывается 8 байт мусора. Вот что получилось в итоге: