Main step of GOST 28147-89

From Rosetta Code
Task
Main step of GOST 28147-89
You are encouraged to solve this task according to the task description, using any language you may know.

GOST 28147-89 is a standard symmetric encryption. Structure of the algorithm consists of three levels:

1) encryption modes - simple replacement, application range, imposing a range of feedback and authentication code generation;

2) cycles - 32-З, 32-Р and 16-З, is a repetition of the main step;

3) main step, a function that takes a 64-bit block of text and one of the eight 32-bit encryption key elements, and uses the replacement table (8x16 matrix of 4-bit values), and returns encrypted block.

C

Version with packed replacement table.

<lang C>static unsigned char k87[256]; static unsigned char k65[256]; static unsigned char k43[256]; static unsigned char k21[256];

void kboxinit(void) { int i; for (i = 0; i < 256; i++) { k87[i] = k8[i >> 4] << 4 | k7[i & 15]; k65[i] = k6[i >> 4] << 4 | k5[i & 15]; k43[i] = k4[i >> 4] << 4 | k3[i & 15]; k21[i] = k2[i >> 4] << 4 | k1[i & 15]; } }

static word32 f(word32 x) { x = k87[x>>24 & 255] << 24 | k65[x>>16 & 255] << 16 | k43[x>> 8 & 255] << 8 | k21[x & 255]; return x<<11 | x>>(32-11); }</lang>

C++

<lang Cpp>UINT_32 TGost::ROL(UINT_32 X, BYTE n) {

   _asm{
    mov  eax, X
    mov  cl,  n
    rol  eax, cl

mov X,eax

   }

return UINT_32(X); }

UINT_64 TGost::SWAP32(UINT_32 N1, UINT_32 N2) {

   UINT_64 N;

N = N1; N = (N<<32)|N2; return UINT_64(N); }

UINT_32 TGost::ReplaceBlock(UINT_32 x) {

   register i;
   UINT_32 res = 0UL;
   for(i=7;i>=0;i--)
   {
      ui4_0 = x>>(i*4);
      ui4_0 = BS[ui4_0][i];
      res = (res<<4)|ui4_0;
   }
   return res;

}

UINT_64 TGost::MainStep(UINT_64 N,UINT_32 X) {

  UINT_32 N1,N2,S=0UL;
  N1=UINT_32(N);
  N2=N>>32;
  S = N1 + X % 0x4000000000000;
  S = ReplaceBlock(S);
  S = ROL(S,11);
  _asm{

mov eax,N2 xor S,eax

  }
  N2 = N1;
  N1 = S;
  return SWAP32(N2,N1);

}</lang>

Variable "BS" is the replacement table.

JavaScript

<lang JavaScript>function ОсновнойШаг(блок_текста, элемент_ключа) {

 var N = блок_текста.slice(0);
 var X = элемент_ключа;
 var S = (N[0] + X) & 0xFFFFFFFF;
 var ячейка; var нов_S = 0;
 for (var сч = 0; сч < 4; сч++) {
   ячейка = (S >>> (сч << 3)) & 0xFF;
   нов_S += (ТаблицаЗамен[сч*2][ячейка & 0x0F] + (ТаблицаЗамен[сч*2+1][ячейка >>> 4] << 4)) << (сч << 3);
 }
 S = (((нов_S << 11) + (нов_S >>> 21)) & 0xFFFFFFFF) ^ N[1];
 N[1] = N[0]; N[0] = S;
 return N;

}</lang>

Note: the variable "блок_текста" is an array of two 32-bit values that make up the block.

Glagol

Here the function "БеззнСлжПоМод32" sells unsigned add numbers modulo 232, "ИсклИЛИ" implements bitwise XOR of 32-bit variables, and "Замена" by replacing the specified 4-bit block.

 ПЕР 
   Ключ: РЯД 8 ИЗ ЦЕЛ; 
   ТаблицаЗамен: РЯД 8, 16 ИЗ ЯЧЦЕЛ; 
 
 ЗАДАЧА БеззнСлжПоМод32(ч1, ч2: ЦЕЛ): ЦЕЛ; 
 ПЕР 
    память1, память2: ШИРЦЕЛ; 
    результат: ЦЕЛ; 
 УКАЗ 
   память1 := 0; ОБХОД.Образ(ОБХОД.ПолучитьАдрес(ч1), ОБХОД.ПолучитьАдрес(память1), 4); 
   память2 := 0; ОБХОД.Образ(ОБХОД.ПолучитьАдрес(ч2), ОБХОД.ПолучитьАдрес(память2), 4); 
   УВЕЛИЧИТЬ(память1, память2); 
   ОБХОД.Образ(ОБХОД.ПолучитьАдрес(память1), ОБХОД.ПолучитьАдрес(результат), 4); 
   ВОЗВРАТ результат 
 КОН БеззнСлжПоМод32; 
  
 ЗАДАЧА ИсклИЛИ(ч1, ч2: ЦЕЛ): ЦЕЛ; 
 УКАЗ 
   ВОЗВРАТ ОБХОД.Значение(ЦЕЛ, ОБХОД.Значение(МНОЖ, ч1) / ОБХОД.Значение(МНОЖ, ч2)) 
 КОН ИсклИЛИ; 
 
 ЗАДАЧА Замена(стр: ЯЧЦЕЛ; яч: ОБХОД.Ячейка): ЯЧЦЕЛ; 
 ПЕР 
   п1, п2, п3: ЦЕЛ; результат: ЯЧЦЕЛ;
 УКАЗ 
   п1 := 0; п2 := 0; ОБХОД.Образ(ОБХОД.ПолучитьАдрес(яч), ОБХОД.ПолучитьАдрес(п1), 1); 
   п1 := Асм.Сдвиг(п1, 4); ОБХОД.Образ(ОБХОД.ПолучитьАдрес(п1), ОБХОД.ПолучитьАдрес(п2), 1); 
   п2 := Асм.Сдвиг(п2, -4); п1 := Асм.Сдвиг(п1, -8); 
   п3 := ТаблицаЗамен[стр*2, п2] + Асм.Сдвиг(ТаблицаЗамен[стр*2+1, п1], 4); 
   ОБХОД.Образ(ОБХОД.ПолучитьАдрес(п3), ОБХОД.ПолучитьАдрес(результат), 1); 
   ВОЗВРАТ результат
 КОН Замена; 
 
 ЗАДАЧА ОсновнойШаг(N: ШИРЦЕЛ; X: ЦЕЛ): ШИРЦЕЛ; 
 ПЕР 
   N1, N2, S: ЦЕЛ; 
   сч: ЯЧЦЕЛ; 
   ячейка: ЯЧЦЕЛ; 
   результат: ШИРЦЕЛ; 
 УКАЗ 
   ОБХОД.Образ(ОБХОД.ПолучитьАдрес(N), ОБХОД.ПолучитьАдрес(N1), 4); 
   ОБХОД.Образ(ОБХОД.ПолучитьАдрес(N)+4, ОБХОД.ПолучитьАдрес(N2), 4); 
   S := БеззнСлжПоМод32(N1, X); 
   ОТ сч := 0 ДО 3 ВЫП 
     ОБХОД.Образ(ОБХОД.ПолучитьАдрес(S)+сч, ОБХОД.ПолучитьАдрес(ячейка), 1); 
     ячейка := Замена(сч, ячейка); 
     ОБХОД.Образ(ОБХОД.ПолучитьАдрес(ячейка), ОБХОД.ПолучитьАдрес(S)+сч, 1) 
   КОН; 
   S := Асм.Вращение(S, 11); 
   S := ИсклИЛИ(S, N2); 
   N2 := N1; N1 := S; 
   ОБХОД.Образ(ОБХОД.ПолучитьАдрес(N1), ОБХОД.ПолучитьАдрес(результат), 4); 
   ОБХОД.Образ(ОБХОД.ПолучитьАдрес(N2), ОБХОД.ПолучитьАдрес(результат)+4, 4); 
   ВОЗВРАТ результат 
 КОН ОсновнойШаг;

X86 Assembly

Parameter in the call:

  • EAX - the youngest part of the transformed block (N1);
  • EDX - leading part transformed block (N2);
  • ESI - address of the first element of the key;
  • EBX - table address changes;
  • ECX - the number of major steps.

Output results:

  • EDX = N1, EAX = N2 for cycles 32-З, 32-Р;
  • EAX = N1, EDX = N2 for cycle 16-З.

Register Usage: all except EDI.

Notes:

  • At the end of the run the registers as follows:
  • EBX (pointer to table of changes) - the same as that in the early
  • ESI (pointer to key) - points to the first byte of the key - it's N * 4 larger than the initial values for the SI cycle reps N (for encryption cycles N = 32 => 4 * N = 128, for authentication code generation cycle N = 16 => 4 * N = 64), larger than the initial values for the generation cycle authentication code.
  • ECX = 0
  • The contents of the segment registers unchanged.

<lang Asm> .386

       .model  flat
       .code

_gost32 proc near32

       public  _gost32
The inner loop of a subroutine
1. Beginning of the cycle, and preservation of the old N1

iloop: mov EBP,EAX

2. Adding to the S key modulo 2^32
       add     EAX,[ESI] ; add the key
       add     ESI,4   ; the next element of the key.
3. Block-replace in the rotation of S by 8 bits to the left

REPT 3

       xlat            ; recoding byte
       ror     EAX,8   ; AL <- next byte
       add     EBX,100h; next node changes

ENDM

       xlat            ; recoding byte
       sub     EBX,300h; BX -> 1st node changes
4. Complete rotation of the S at 3 bits to the left
       rol     EAX,3
5. The calculation of the new values of N1,N2
       xor     EAX,EDX
       mov     EDX,EBP
The completion of the inner loop
       loop    iloop
       ret

_gost32 endp

       end</lang>