📜 ⬆️ ⬇️

GOST 28147-89 (Part 2. Simple replacement mode)

This article is a continuation of the article about GOST 28147-89 . As mentioned earlier, GOST 28147-89 supports four modes of operation, but perhaps the main one is the simple replacement mode, which is used both independently and as an integral part of other modes.
The article provides c ++ code that implements this mode.
To understand how GOST 28147-89 works in this mode, you need to consider the following scheme:

Actually, the essence

Encryption

  1. Open data is divided into blocks of 64 bits.
  2. Next, enter the first block in drives N 1 and N 2 . In this case, the bits of open information are entered as follows: The 1st bit of the open information is entered into the 1st bit of drive N 1 , ..., the 32nd bit into the 32nd bit of drive N 1 , the 33rd bit into the 1st discharge of drive N 2 and so on until the 64th bit of the open information is entered into the 32nd discharge of drive N 2 .
  3. A key with a length of 256 bits is inserted into the KZU in the manner described in the article GOST 28147-89 (Part 1. Introduction and general principles) .
  4. Encryption of open data is performed in the simple replacement mode (in 32 cycles):

    1. In the first cycle, the contents of the register N 1 is summed with the filling of X 0 from a KZU modulo 2 32 in the adder CM 1 .
    2. In the substitution block K, 32 bits of information received from the adder CM 1 are replaced according to the rules discussed in the first article .
    3. In the shift register R, there is a cyclic shift by 11 in the direction of the higher digit.
    4. Information from the shift register R and the drive N 2 is summed modulo 2 in the adder CM 2 .
    5. The old filling of drive N 1 is rewritten to drive N 2 .
    6. The result from the output of the adder CM 2 corresponds to the drive N 1 .
    7. The first cycle ends.
  5. Subsequent cycles are similar to the first, with the only difference that in the 2nd cycle the key X 1 is entered, in the 8th, X7, in the 9th, X0 and so on in the same order up to 24 cycles. From 25 to 32 cycle, the key is entered in the reverse order: X 7 - in the 25th, X 0 - in the 32nd.
  6. After the 32nd cycle in N 1 the information is saved, but the result from the output of the CM 2 adder is rewritten in N 2 .
  7. The filling of N 1 and N 2 is the first block of encrypted data.
  8. The following blocks are encrypted in the same way.

Decryption

Decryption is carried out using the same algorithm as encryption, only encrypted data divided into blocks of 64 bits are sent to the input of drives N 1 and N 2. Another important difference is that in direct order ( X 0 through X 7 ) the key is entered only in the first 8 cycles of the RPT, in the rest - in the reverse ( X 7 through X 0 ). And so, after passing 32 cycles, the drives N 1 and N 2 contain blocks of open data.

Explain all of the above with C ++ code.

This code was written in console mode in C ++ Builder 6 for a long time and does not claim to be the best, so do not hit hard, there is no time to optimize. Simply, it works, and, rather quickly.
gost28147.cpp
 // ------------------------------------------------ ---------------------------
 #include <vcl.h>
 #include <stdio.h>
 #include <conio.h>

 // ------------------------------------------------ ---------------------------

 // taken from the help, determine the file size
 long filesize (FILE * stream)
 {
  long curpos, length;
  curpos = ftell (stream);
  fseek (stream, 0L, SEEK_END);
  length = ftell (stream);
  fseek (stream, curpos, SEEK_SET);
  return length;
 }

 // function that implements the work of GOST 28147-89 in the simple replacement mode
 void rpz (int rezh, char * opener, char * saver)
 {
  FILE * f_begin, * f_end;  // streams for source and destination files

  // replacement table
  byte Tab_Z [8] [16] =
  {
   0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xA, 0xB, 0xC, 0xD, 0xE, 0xF,
   0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xA, 0xB, 0xC, 0xD, 0xE, 0xF,
   0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xA, 0xB, 0xC, 0xD, 0xE, 0xF,
   0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xA, 0xB, 0xC, 0xD, 0xE, 0xF,
   0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xA, 0xB, 0xC, 0xD, 0xE, 0xF,
   0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xA, 0xB, 0xC, 0xD, 0xE, 0xF,
   0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xA, 0xB, 0xC, 0xD, 0xE, 0xF,
   0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xA, 0xB, 0xC, 0xD, 0xE, 0xF
  };

 // key
  unsigned long key [8] =
  {
   0x0123,
   0x4567
   0x89AB,
   0xCDEF,
   0x0123,
   0x4567
   0x89AB,
   0xCDEF
  };

  char N [4];  // 32-bit drive

  unsigned long n1 = 0, n2 = 0, SUM232 = 0;  // drives N1, N2, and adder

  // open files
  f_begin = fopen (opener, "rb");
  f_end = fopen (saver, "wb");

  // determine the number of blocks
  float blokoff;
  blokoff = 8 * filesize (f_begin);
  blokoff = blokoff / 64;
  int block = blokoff;
  if (blokoff-block> 0) block ++;

  int sh;
  if (filesize (f_begin)> = 4) sh = 4;  else sh = filesize (f_begin);
  int sh1 = 0;
  int flag = 0;

  // start reading and converting blocks
  // there are checks for the completeness of the blocks to read only the required number of bits
  for (int i = 0; i <block; i ++)
  {
   // write to drive N1
   for (int q = 0; q <4; q ++) * ((byte *) & N + q) = 0x00;
   if ((sh1 + sh) <filesize (f_begin))
   {
    fread (N, sh, 1, f_begin);
    sh1 + = sh;
   }
   else
   {
    sh = filesize (f_begin) -sh1;
    fread (N, sh, 1, f_begin);
    flag = 1;
   }
   n1 = * ((unsigned long *) & N);

   // write to N2 drive
   for (int q = 0; q <4; q ++) * ((byte *) & N + q) = 0x00;
   if ((sh1 + sh) <filesize (f_begin))
   {
    fread (N, sh, 1, f_begin);
    sh1 + = sh;
   }
   else
   {
    if (flag == 0)
    {
     sh = filesize (f_begin) -sh1;
     fread (N, sh, 1, f_begin);
    } 
   }
   n2 = * ((unsigned long *) & N);

   // 32 simple replacement cycles
   // read the key in the required GOST order
   int c = 0;
   for (int k = 0; k <32; k ++)
   {
    if (rezh == 1) {if (k == 24) c = 7;  }
     else {if (k == 8) c = 7;  }

    // sum in the adder CM1
    SUM232 = key [c] + n1;

    // replace by replacement table
    byte first_byte = 0, second_byte = 0, zam_symbol = 0;
    int n = 7;
    for (int q = 3; q> = 0; q--)
    {
     zam_symbol = * ((byte *) & SUM232 + q);
     first_byte = (zam_symbol & 0xF0) >> 4;
     second_byte = (zam_symbol & 0x0F);
     first_byte = Tab_Z [n] [first_byte];
     n--;
     second_byte = Tab_Z [n] [second_byte];
     n--;
     zam_symbol = (first_byte << 4) |  second_byte;
     * ((byte *) & SUM232 + q) = zam_symbol;
    } 
   
    SUM232 = (SUM232 << 11) | (SUM232 >> 21);  // cyclic shift by 11
    SUM232 = n2 ^ SUM232;  // add in the adder CM2

    if (k <31)
    {
     n2 = n1;
     n1 = SUM232;
    }
    if (rezh == 1)
    {
     if (k <24)
     {
      c ++;
      if (c> 7) c = 0;
     }
     else
     {
      c--;
      if (c <0) c = 7;
     }
    }
    else
    {
     if (k <8)
     {
      c ++;
      if (c> 7) c = 0;
     }
    else
    {
     c--;
     if (c <0) c = 7;
    }
   }
  }
  n2 = SUM232;

  // output result to file
   char sym_rez;
   for (int q = 0; q <= 3; q ++)
   {
    sym_rez = * ((byte *) & n1 + q);
    fprintf (f_end, "% c", sym_rez);
   }
   for (int q = 0; q <= 3; q ++)
   {
    sym_rez = * ((byte *) & n2 + q);
    fprintf (f_end, "% c", sym_rez);
   }
  }
  fclose (f_begin);
  fclose (f_end);
 }

 // ------------------------------------------------ ---------------------------
 int main ()
 {
  // choose encryption or decryption
  int rezhim = 0;
  do
  {
   printf ("Select the mode of operation: \ nCrypting - 1 \ nCoding - 2 \ n");
    scanf ("% d", & rezhim);
  } while ((rezhim! = 1) && (rezhim! = 2));  // repeat until 1 or 

  // select the source and destination files (slash '\' in the path to write as '\\') 
  char open_str [50], save_str [50];
  printf ("\ nEnter the path to the source file \ n");
  scanf ("% s", & open_str);
  printf ("\ nEnter the path to the file where you want to write the result \ n");
  scanf ("% s", & save_str);

  rpz (rezhim, open_str, save_str);  // run the RPP
  return 0;
 }
 // ------------------------------------------------ ---------------------------

Note the advantages and disadvantages of this mode.

Advantages:

Disadvantages:

Application.

This mode is used in the remaining three modes of GOST 28147-89, in GOST R34.11-94 when performing mixing transformations, as well as for key processing. It is not recommended to use it for encryption / decryption, there are more advanced modes, which will be discussed in the following parts.

')

Source: https://habr.com/ru/post/81032/


All Articles