unit GOSTEncryption; interface { This class contains generic pocedures for GOST 28147-89 encryption standard. Based on a program algorithm realization for DOS (c) A.Y. Vinokurov, 1998. Transformed into Delphi by Yuri Popoff, 2000 } type Item=type longint; DWORD=type longint; TEncKey=array[0..31] of byte; TExtEncKey=array[0..127] of byte; TExtTable=array[0..1023] of byte; T128Table=array[0..127] of byte; TImito=record I1,I2:Item;end; TPEncKey=^TEncKey; TPExtEncKey=^TExtEncKey; TPExtTable=^TExtTable; TP128Table=^T128Table; TPImito=^TImito; TGOSTEncryption=class private ExtKey:TExtEncKey; //Expanded key KeyMask:DWORD ; //маска for expantion procedure Gost386; procedure simple(src,dst:pointer;noblocks:DWORD);// Шифрование простой заменой procedure ExpandKey ( // Любое расширение ключа src:TPEncKey;dst:TPExtEncKey;// область исходного и расширен. ключа KeyLength:DWORD; // размер ключа в 4-байтовых блоках KeyRepeat:DWORD; // число повторений ключа RepeatMask:DWORD); // маска повторений ключа public //Properties //Here is the key data ExtChTab:TExtTable; //Expanded Exchange table Key:TEncKey; //Key I1,I2:Item; //Вычисленное значение имитовставки constructor Create; destructor destroy;override; //Methods procedure EncryptSimple(src,dst:pointer;noblocks:DWORD); procedure DecryptSimple(src,dst:pointer;noblocks:DWORD); procedure GenerateImito(src:pointer;noblocks:DWORD);overload; procedure GenerateImito(src:pointer;noblocks:DWORD;s1,s2:Item);overload; procedure GenerateGamma(dst:pointer;noblocks:DWORD);overload; procedure GenerateGamma(dst:pointer;noblocks:DWORD;var s1,s2:Item);overload; //S1,S2 - synchronization procedure ApplyGamma(src:pointer;gamma:pointer;len:DWORD); procedure SetPassword(pwd:string); //sets the whole KeyData according to pwd procedure Set128Table(p:TP128Table);//sets the 128 byte exchange table //p should point to 128 byte table procedure SetTable(p:TPExtTable); //sets the 1024 extended table //p should point to 1024 byte table procedure SetKey(p:TPEncKey); end; implementation constructor TGOSTEncryption.Create; var i:integer; begin inherited Create; KeyMask:=8; // Стандартная маска 0001 // Этот цикл строит тривиальную таблицу замен for i:=0 to 1023 do ExtChTab[i]:=i mod 255; end; destructor TGOSTEncryption.destroy; begin inherited Destroy; end; {---------------------------------------------------- Реализация универсального цикла шифрования алгоритма криптографического преобразования ГОСТ 28147-89. Разработал Винокуров А.Ю., г.Москва., 1992-1995 г. (c) 1992-1995 Свободное копирование и использование. Adapted for Delphi5 by Popoff Yuri, 2000 ----------------------------------------------------- >Параметры при вызове: EAX=N1, EDX=N2; ESI - адрес первого элемента ключа; EBX - адрес таблицы замен; CX - число основных шагов >Результаты на выходе: EDX=N1, EAX=N2 для циклов 32-З,32-Р; EAX=N1, EDX=N2 для цикла 16-З; } procedure TGOSTEncryption.Gost386; asm {Внутренний цикл работы П/П} {1. Начало цикла и сохранение старого N1} @iloop: push EAX {2. Добавление к S ключа по модулю 2^32} add EAX,[ESI] { добавить ключ} add ESI,4 { следующий эл. ключа} {3. Поблочная замена в S с вращением на 8 бит влево} xlat { перекодировка байта} ror EAX,8 { AL <- следующий байт} add ebx,256 { следующий узел замен} xlat { перекодировка байта} ror EAX,8 { AL <- следующий байт} add ebx,256 { следующий узел замен} xlat { перекодировка байта} ror EAX,8 { AL <- следующий байт} add ebx,256 { следующий узел замен} xlat { перекодировка байта} sub ebx,3*256 { BX -> 1-й узел замен} {4. Доворот S на 3 бита влево} rol EAX,3 {5. Вычисление новых значений N1,N2} xor EAX,EDX pop EDX { Завершение внутреннего цикла} loop @iloop end; var vesi,vedi,veax,vebx,vecx,vedx:DWORD; procedure PushAll; asm {Сохранение регистров согласно соглашениям} mov vesi,esi mov vedi,edi mov veax,eax mov vebx,ebx mov vecx,ecx mov vedx,edx end; procedure PopAll; asm {Восстановление регистров} mov esi,vesi mov edi,vedi mov eax,veax mov ebx,vebx mov ecx,vecx mov edx,vedx end; {----------------------------------------------------- Генерация массива криптографической гаммы согласно криптоалгоритму ГОСТ 28147-89. Разработал Винокуров А.Ю., г.Москва, 1992-1995 г. (C)1992-1995, Свободное копирование и использование. Adapted for Delphi5 by Popoff Yuri, 2000 ------------------------------------------------------ Замечания: 1. Данная процедура вырабатывает гамму блоками по 8 байтов, что отражает свойство использованного алго- ритма быть блочным шифром. ------------------------------------------------------ } procedure TGOSTEncryption.GenerateGamma(dst:pointer;noblocks:DWORD); var s1,s2:Item; begin s1:=0;s2:=0; GenerateGamma(dst,noblocks,s1,s2); end; procedure TGOSTEncryption.GenerateGamma(dst:pointer;noblocks:DWORD;var s1,s2:Item); const // определяем константы C1,C2 по ГОСТ C1=$01010101; C2=$01010104; var k:TPExtEncKey; // адрес ключа c:TPExtTable; // адрес табл. замен l:DWORD; cur:pointer; begin k:=@ExtKey; c:=@ExtChTab; l:=noblocks; cur:=dst; ExpandKey(@Key,k,8,4,KeyMask); asm call PushAll cmp l,0 je @ex // настройка регистров mov EBX,c // EBX <- адрес табл.замен mov edi,s2 @circle: mov esi,s1 // Добавление констант mov EAX,[esi] mov EDX,[edi] add EAX,C1 // изменение S1, s2: adc EDX,C2 // S1=(S1+C1) mod 2^32 // S2=(S2+C2) mod (2^32-1) adc EDX,0 // если был перенос, // надо добавить 1 к результату mov [esi],EAX // заносим новые mov [edi],EDX // значения S1,S2 на их место // Готовим регистры для вызова цикла 32-З; mov ESI,k // ESI <- адрес ключа mov ECX,32 // CX <- число основн. шагов call Gost386 // шаг простой замены // Использование сгенерированного блока гаммы mov esi,cur mov [ESI],EDX // Заносим 8-байтный блок mov [ESI+4],EAX // гаммы в область назначения add cur,8 // коррекция указателя dec l // коррекция счетчика jnz @circle // на генерацию нового блока @ex: call PopAll end; end; procedure TGOSTEncryption.ApplyGamma(src:pointer;gamma:pointer;len:DWORD); //Applies gamma asm call PushAll mov esi,src mov edi,gamma mov ecx,len cmp ecx,0 je @ex @l1: mov al,[edi] xor [esi],al inc esi inc edi loop @l1 @ex: call PopAll end; {------------------------------------------------------ Выработка имивставки для массива данных согласно криптоалгоритму ГОСТ 28147-89. Разработал Винокуров А.Ю., г.Москва, 1992-1995 г. (C)1992-1995, Свободное копирование и использование. Adapted for Delphi5 by Popoff Yuri, 2000 ------------------------------------------------------ } procedure TGOSTEncryption.GenerateImito(src:pointer;noblocks:DWORD); begin GenerateImito(src,noblocks,0,0); end; procedure TGOSTEncryption.GenerateImito(src:pointer;noblocks:DWORD;s1,s2:Item); const ExtMask:DWORD=$2; var l:DWORD; pt:TPExtTable; pk:TPExtEncKey; pI1,pI2:^DWORD; begin ExpandKey(@Key,@ExtKey,8,2,ExtMask); l:=noblocks; pt:=@ExtChTab;pk:=@ExtKey; pI1:=@I1;pI2:=@I2; asm call PushAll mov EAX,s1 // Загрузка начального значения контрольной комбинации mov EDX,s2 // Начальная загрузка указателей mov EBX,pt // EBX <- адрес ТЗ mov EDI,src // EDI <- адрес данных cmp l,0 je @ex // Добавляем блок данных @circle: xor EAX,[EDI] // Гаммируем xor EDX,[EDI+4] // 8-байтный // Вызов простой замены mov ECX,16 // CX <- число основн. шагов mov ESI,pk // ESI <- адрес ключа call Gost386 // Организация цикла add EDI,8 //коррекция адреса назн. dec l jnz @circle // циклимся @ex: mov esi,pI1 mov [esi],eax // заносим новые значения mov esi,pI2 mov [esi],edx call PopAll end; end; {----------------------------------------------------- Построение расширенного ключа шифрования из однократ- ного ключа для шифра типа ГОСТ 28147-89. ** Схема расширения задается маской расширения. ** Маска расширения может иметь размер 1..32767 бит. Разработал Винокуров А.Ю., г.Москва, 1995 г. (c) 1992-1995, Свободное копирование и использование. Adapted for Delphi5 by Popoff Yuri, 2000 ------------------------------------------------------ } procedure TGOSTEncryption.ExpandKey (src:TPEncKey;dst:TPExtEncKey;KeyLength:DWORD; KeyRepeat:DWORD;RepeatMask:DWORD); asm call PushAll // Настройка регистров mov ESI,src // ESI=адрес source ключа mov EDI,dst // EDI=адрес назначения mov EBX,KeyLength // BX <- адрес конца ключа shl EBX,2 add ebx,esi sub ebx,4 xor EAX,EAX // AX=0 cld // Проверка условия завершения цикла @iloop: cmp EAX,KeyRepeat // нужное число сделано ? jge @ex // если да, выход mov ECX,KeyLength // CX=длина ключа bt RepeatMask,AX // CF=очередной бит маски jc @Rev // CF=1 -> реверс // Повторение элементов ключа в прямом порядке mov ESI,src // ESI=смещение ключа rep movsd // копируем ключ jmp @Incr // на счет повтор. ключа // Повторение элементов ключа в обратном порядке @Rev: mov ESI,EBX // SI=адрес конца ключа @rl: movsd // слова ключа sub ESI,8 // к предш. элементу loop @rl // организация цикла @Incr: inc AX // счетчик повторов ключа jmp @iloop @ex: call PopAll end; {----------------------------------------------------- Шифрование массива данных в режиме простой замены согласно криптоалгоритму ГОСТ 28147-89. Разработал Винокуров А.Ю., г.Москва, 1992-1995 г. (c) 1992-1995, Свободное копирование и использование. Adapted for Delphi5 by Popoff Yuri, 2000 ------------------------------------------------------ Замечания: 1.Зашифрование или расшифрование задается передачей соответствующего адреса ключа - порядок элементов в ключах зашифрования и расшифрования взаимно обратный. look DecryptSimple function on inversing the key 2.Согласно ГОСТ 28147-89 этот модуль может исполь- зоваться только для шифрования ключевой информации (и синхропосылки для гаммирования). } procedure TGOSTEncryption.simple(src,dst:pointer;noblocks:DWORD); // Шифрование простой заменой var l:DWORD; pt:TPExtTable; pk:TPExtEncKey; begin l:=noblocks; pt:=@ExtChTab; pk:=@ExtKey; asm call PushAll //Начальная загрузка указателей mov ebx,pt// BX <- адрес ТЗ mov esi,src //source address mov edi,dst // address назн. // Загрузка блока данных @circle: mov EAX,[esi] // EAX <- S1 mov EDX,[esi+4] // EDX <- S2 // Вызов простой замены; mov ecx,32 // CX <- число основн. шагов push esi mov esi,pk// ESI <- адрес ключа call Gost386 // <шаг простой замены> pop esi // Запись результата на место mov [edi+4],EAX // Заносим результат mov [edi],EDX // на его место // Организация цикла add edi,8 // коррекция адреса назн. add esi,8 //go to next element in the source dec l // коррекция счетчика б. jnz @circle // циклимся call PopAll end; end; procedure TGOSTEncryption.EncryptSimple(src,dst:pointer;noblocks:DWORD); //Encrypts using simple exchange mode begin ExpandKey (@Key,@ExtKey,8,4,KeyMask); simple(src,dst,noblocks); end; procedure TGOSTEncryption.DecryptSimple(src,dst:pointer;noblocks:DWORD); //Decrypts using simple exchange mode var InversedMask:DWORD; NotKeyMask:DWORD; i:integer; begin InversedMask:=0; NotKeyMask:=not KeyMask; // Инвертирование маски ключа for i:=4 downto 1 do begin InversedMask:=InversedMask shl 1; InversedMask:=InversedMask or NotKeyMask and 1; NotKeyMask:=NotKeyMask shr 1; end; ExpandKey(@Key,@ExtKey,8,4,InversedMask); simple(src,dst,noblocks); end; procedure TGOSTEncryption.SetPassword(pwd:string); // sets the whole KeyData according to pwd // !!! Эта процедура не принадлежит алгоритму GOST 28147-89 !!! var pt:array [0..1023] of byte; //Transformed password ns1,ns2,ns3,ns4:array of byte; //Number sequence i:integer; c,c1:integer; l:integer; l1,l2:integer; b:byte; begin //First build PasswordExchangeTable if length(pwd)<1 then exit; //Free password - may not be used SetLength(ns1,256); SetLength(ns2,256); SetLength(ns3,256); SetLength(ns4,256); for i:=0 to 255 do begin ns1[i]:=i; ns2[i]:=i; ns3[i]:=i; ns4[i]:=i; end; for i:=0 to 1023 do pt[i]:=i mod 256; l1:=0;l2:=0; c:=1;c1:=0; b:=0; while (l1<3)or(l2<3) do begin if c>Length(pwd) then begin c:=1;inc(l1);end; if c1>1023 then begin c1:=0;inc(l2);end; pt[c1]:=pt[c1] xor b xor ord(pwd[c]); b:=b+ord(pwd[c])+c+l1+l2; inc(c);inc(c1); end; //Little change to number sequence for i:=0 to 255 do ns1[i]:=ns1[i] xor b; b:=pt[b]; for i:=0 to 255 do ns2[i]:=ns2[i] xor b; b:=pt[b]; for i:=0 to 255 do ns3[i]:=ns3[i] xor b; b:=pt[b]; for i:=0 to 255 do ns4[i]:=ns4[i] xor b; //Now build ExchangeTable for i:=0 to 1023 do ExtChTab[i]:=0; c:=0; while length(ns1)>0 do begin //now look for a number in ns to put in et l1:=Length(ns1); //1st l:=(pt[c]*1007+ExtChTab[pt[c])mod l1; ExtChTab[256-l1]:=ns1[l]; ns1[l]:=ns1[l1-1]; SetLength(ns1,l1-1); inc(c); //2nd l:=(pt[c]*1007+ExtChTab[pt[c]+256])mod l1; ExtChTab[512-l1]:=ns2[l]; ns2[l]:=ns2[l1-1]; SetLength(ns2,l1-1); inc(c); //3rd l:=(pt[c]*1007+ExtChTab[pt[c]+512])mod l1; ExtChTab[768-l1]:=ns3[l]; ns3[l]:=ns3[l1-1]; SetLength(ns3,l1-1); inc(c); //4th l:=(pt[c]*1007+ExtChTab[pt[c]+768])mod l1; ExtChTab[1024-l1]:=ns4[l]; ns4[l]:=ns4[l1-1]; SetLength(ns4,l1-1); inc(c); end; for i:=0 to 31 do Key[i]:=0; for i:=0 to 1023 do pt[i]:=pt[i] xor ExtChTab[i]; c1:=0;c:=0; l1:=0; //Number of rounds KeyData encrypted while l1<32 do begin if c1>31 then begin c1:=0; for i:=0 to 255 do ExtChTab[((i xor b)+(l1+0)*256)mod 1024]:=ExtChTab[(ExtChTab[((i xor b)+(l1+0)*256)mod 1024]+(l1+1)*256)mod 1024]; b:=ExtChTab[b]; for i:=0 to 255 do ExtChTab[((i xor b)+(l1+1)*256)mod 1024]:=ExtChTab[(ExtChTab[((i xor b)+(l1+1)*256)mod 1024]+(l1+2)*256)mod 1024]; b:=ExtChTab[b+256]; for i:=0 to 255 do ExtChTab[((i xor b)+(l1+2)*256)mod 1024]:=ExtChTab[(ExtChTab[((i xor b)+(l1+2)*256)mod 1024]+(l1+3)*256)mod 1024]; b:=ExtChTab[b+512]; for i:=0 to 255 do ExtChTab[((i xor b)+(l1+3)*256)mod 1024]:=ExtChTab[(ExtChTab[((i xor b)+(l1+3)*256)mod 1024]+(l1+4)*256)mod 1024]; b:=ExtChTab[b+768]; inc(l1); end; b:=ExtChTab[b] xor ExtChTab[pt[c]+256]; Key[c1]:=ExtChTab[(Key[c1] xor b)+512]; b:=ExtChTab[(Key[c1] xor b)+768]; inc(c);inc(c1); end; end; {----------------------------------------------------- Построение расширенной таблицы замен (1024 байт) из таблицы замен (128 байт) алгоритма ГОСТ 28147-89. Разработал Винокуров А.Ю., г.Москва, 1992-1995 г. (c) 1992-1995, Свободное копирование и использование. Adapted for Delphi5 by Popoff Yuri, 2000 ------------------------------------------------------ } procedure TGOSTEncryption.Set128Table(p:TP128Table); //sets the 128 byte exchange table //p should point to 128 byte table var pt:TPExtTable; begin pt:=@ExtChTab; asm call PushAll mov ESI,p // ESI --> источник mov EDI,pt // EDI --> приемник cld // Цикл по блокам расширенной таблицы замен mov ecx,4 // CX <- число блоков большой ТЗ @blocks:mov EBX,ESI // BX<-адрес начала линии add EBX,10h // старших байтов блока // Цикл по линиям блока push eCX // сохранить счетчик блоков mov eCX,16 // загрузить счетчик линий @lines: push ESI // сохр. указ. текущ. блока mov AH,[EBX] // AH <- старший полубайт push eCX // сохранить счетчик линий mov CL,4 // сдвиг полубайта на место shl AH,CL // старшего полубайта // Цикл по байтам линии mov ECX,16 // загрузить счетчик байтов @bytes: lodsb // загрузить очередной байт or AL,AH // добавить старший полубайт stosb // ... и записать результат loop @bytes // цикл по байтам линни // Проверка цикла по линиям pop eCX // восстанов. счетчик линий pop ESI // восст. указат. тек. блока inc EBX // продвинуть указатель байт loop @lines // цикл по строкам таблицы // Проверка цикла по блокам pop eCX // восстанов. счетчик блоков add ESI,20h // продвинуть указат. блока loop @blocks // цикл по блокам call PopAll end; end; procedure TGOSTEncryption.SetTable(p:TPExtTable); //sets the 1024 extended table //p should point to 1024 byte table var pt:TPExtTable; begin pt:=@ExtChTab; asm call PushAll mov esi,p mov edi,pt mov ecx,1024 rep movsb call PopAll end; end; procedure TGOSTEncryption.SetKey(p:TPEncKey); //Sets the key //p should point to 32 byte key var pk:TPEncKey; begin pk:=@Key; asm call PushAll mov esi,p mov edi,pk mov ecx,32 rep movsb call PopAll end; end; end.