Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.65/54: Рейтинг темы: голосов - 54, средняя оценка - 4.65
43 / 43 / 19
Регистрация: 22.05.2011
Сообщений: 156
Записей в блоге: 5
1

Алгоритм шифрования ГОСТ 28147-89. Режим простой замены

12.03.2014, 16:39. Просмотров 10420. Ответов 16

Реализовывал алгоритм по wiki. Но что то не то получилось.Вот код:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
 
namespace InformationSecurity1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        byte[,] Sblocks = {
                            {4, 10, 9, 2, 13, 8, 0, 14, 6, 11, 1, 12, 7, 15, 5, 3},
                            {14, 11, 4, 12, 613, 15, 10, 23810759},
                            {5, 8,1, 13, 10, 3, 4, 2, 14, 15, 12, 7, 6, 0911},
                            {7, 13, 10, 1, 0, 8 ,9  ,15, 14, 4, 6, 1211, 253},
                            {6, 12, 71515, 13, 8410, 914, 0311, 2},
                            {4, 11, 10, 072113, 3685912, 15, 14},
                            {13,    11, 41315, 59010, 14, 768212},
                            {1, 15, 13, 05710, 492314, 611, 812}
                          };//Блок замен
        List<byte[]> lsKey = new List<byte[]>();//Список подключей размером в 4 байта
        List<byte[]> lsData = new List<byte[]>();//Список блоков открытого текста размером 8 байт
 
        byte[] fillingArrayData(List<byte[]> list)
        {
            byte[] array = new byte[list.Count * 8];
            int index = 0;
            for (int i = 0; i < list.Count; ++i)
            {
                for (int j = 0; j < list[i].Length; ++j)
                {
                    array[index] = list[i][j];
                    index++;
                }
            }
            return array;
        }
 
        void fillingListData(string data)
        {
            byte[] temp = Encoding.Default.GetBytes(data);
            int count = 0;
            byte[] k = new byte[8];
            for (int i = 0; i < temp.Length; ++i)
            {
                if (count != 8)
                {
                    k[count] = temp[i];
                    count++;
                }
                else
                {
                    lsData.Add(k);
                    --i;
                    count = 0;
                    k = new byte[8];
                }
            }
            lsData.Add(k);
        }
 
        void fillingListKey(string key)
        {
            byte[] temp = Encoding.Default.GetBytes(key);
            int count = 0;
            byte[] k = new byte[4];
            for (int i = 0; i < temp.Length; ++i)
            {
                if (count != 4)
                {
                    k[count] = temp[i];
                    count++;
                }
                else
                {
                    lsKey.Add(k);
                    --i;
                    count = 0;
                    k = new byte[4];
                }
            }
            lsKey.Add(k);
        }
 
        int lengthKey(string key)
        {
            byte[] temp = Encoding.Default.GetBytes(key);
            return temp.Length;
        }
 
        byte[] retL(byte[] data)
        {
            byte[] temp = new byte[4];
            for (int i = 0; i < 4; ++i)
            {
                temp[i] = data[i];
            }
            return temp;
        }//Возвращает старшую часть 8 байтового блока данных
 
        byte[] retR(byte[] data)
        {
            byte[] temp = new byte[4];
            int count = 4;
            for (int i = 0; i < 4; ++i)
            {
                temp[i] = data[count];
                count++;
            }
            return temp;
        }//Возвращает младшую часть 8 байтового блока данных
 
 
        byte[] mod2_32(byte[] a, byte[] b)
        {
            byte[] res;
            UInt32 A = BitConverter.ToUInt32(a, 0);
            UInt32 B = BitConverter.ToUInt32(b, 0);
            A += B;
            res = BitConverter.GetBytes(A);
            return res;
        }// Сложение по модулю 2^32
 
        UInt32 func(byte[] R, byte[] Ki)
        {
            byte[] s8 = new byte[8];
            int count = 0;
            byte[] s = mod2_32(R, Ki);
            for (int j = 0; j < s.Length; ++j)
            {
                byte e = (byte)((s[j] >> 4));
                s8[count] = e;
                ++count;
                byte f = (byte)((s[j] & 15));
                s8[count] = f;
                ++count;
            }
            for (int i = 0; i < 8; ++i)
            {
                    s8[i] = Sblocks[i, (int)s8[i]];
            }
            UInt32 result = BitConverter.ToUInt32(s8, 0);
            result = result << 11;
            return result;
        }
 
        byte[] encode(byte[] data)
        {
            byte[] L = retL(data);
            byte[] R = retR(data);
            byte[] block = new byte[4];
            UInt32 temp = 0;
            int index = 0;
            bool flag = true;
            for (int i = 0; i < 32; ++i)
            {
                if (i == 24)
                {
                    flag = false;
                }
                if (flag)
                {
                    if (index == 8)
                    {
                        index = 0;
                    }
                    temp = func(R, lsKey[index]);
                    index++;
                }
                else
                {
                    if (index == 8)
                    {
                        --index;
                    }
                    temp = func(R, lsKey[index]); 
                    --index;
                }
                temp = BitConverter.ToUInt32(L, 0) ^ temp;
                L = R;
                R = BitConverter.GetBytes(temp);
            }
            byte[] result = new byte[8];
            index = 0;
            for (int i = 0; i < 8; ++i)
            {
                if (i < 4)
                {
                    result[i] = L[i];
                }
                else
                {
                    result[i] = R[index];
                    index++;
                }
            }
            return result;
        }
 
        byte[] decode(byte[] data)
        {
            byte[] L = retL(data);
            byte[] R = retR(data);
            byte[] block = new byte[4];
            UInt64 temp = 0;
            int index = 0;
            bool flag = false;
            for (int i = 0; i < 32; ++i)
            {
                if (i == 24)
                {
                    flag = true;
                }
                if (flag)
                {
                    if (index == 8)
                    {
                        index = 0;
                    }
                    temp = func(R, lsKey[index]);
                    index++;
                }
                else
                {
                    if (index == 0)
                    {
                        index=7;
                    }
                    temp = func(R, lsKey[index]); //index выходит за рамки равен -1
                    --index;
                }
                temp = BitConverter.ToUInt32(L, 0) ^ temp;
                L = R;
                R = BitConverter.GetBytes(temp);
                //++index;
            }
            byte[] result = new byte[8];
            index = 0;
            for (int i = 0; i < 8; ++i)
            {
                if (i < 4)
                {
                    result[i] = L[i];
                }
                else
                {
                    result[i] = R[index];
                    index++;
                }
            }
            return result;
        }
 
        private void textBox2_TextChanged(object sender, EventArgs e)
        {
            if (lengthKey(textBox2.Text) < 32)
            {
                textBox2.BackColor = Color.Red;
                button1.Enabled = false;
            }
            else
            {
                if (lengthKey(textBox2.Text) > 32)
                {
                    textBox2.BackColor = Color.Red;
                    button1.Enabled = false;
                }
                else
                {
                    textBox2.BackColor = Color.Green;
                    button1.Enabled = true;
                    textBox2.MaxLength = textBox2.TextLength;
                }
            }
 
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            fillingListKey(textBox2.Text);
            fillingListData(textBox1.Text);
           // byte[] temp = Encoding.Default.GetBytes(textBox1.Text);
 
            byte[] t = new byte[8];
            List<byte[]> result = new List<byte[]>();
            for (int i = 0; i < lsData.Count; ++i)
            {
                t = encode(lsData[i]);
                result.Add(t);
            }
            byte[] res = fillingArrayData(result);
            textBox3.Text = Encoding.Default.GetString(res);
        }
 
        private void button2_Click(object sender, EventArgs e)
        {
            fillingListKey(textBox2.Text);
            fillingListData(textBox3.Text);
            byte[] temp = Encoding.Default.GetBytes(textBox3.Text);
            byte[] t = new byte[8];
            List<byte[]> result = new List<byte[]>();
            for (int i = 0; i < lsData.Count; ++i)
            {
                t = decode(lsData[i]);
                result.Add(t);
            }
            byte[] res = fillingArrayData(result);
            textBox4.Text = Encoding.Default.GetString(res);
        }
    }
}
Возможно я неверно понял алгоритм?
P.S. Если возникли не понимания в коде спрашивайте разъясню: что делает, почему и как
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
12.03.2014, 16:39
Ответы с готовыми решениями:

Реализация алгоритма шифрования по ГОСТ 28147-89
Добрый день! Пытаюсь реализовать все тот же алгоритм шифрования ГОСТ-89. Уже целую неделю долблюсь,...

Нужны исходники программы шифрования и дешифрования файлов на базе алгоритма ГОСТ 28147-89
у кого есть исходники программы шифрования и дешифрования файлов на базе алгоритма ГОСТ 28147-89 в...

ГОСТ 28147-89 режим простой замены
Добрый день, уважаемые формучане. Решил написать программу, которая реализует ГОСТ в режиме...

ГОСТ 28147-89 (Режим простой замены). (C++)
Добрый день! В программе реализовывается алгоритм шифрования ГОСТ 28147-89 в режиме простой...

16
taksebe
12.03.2014, 17:01
  #2

Не по теме:

Это вообще что такое??? :-|

0
43 / 43 / 19
Регистрация: 22.05.2011
Сообщений: 156
Записей в блоге: 5
12.03.2014, 19:42  [ТС] 3
Цитата Сообщение от taksebe Посмотреть сообщение
Это вообще что такое??
По конкретнее вопрос нельзя поставить?
Да и в заголовке указано что хотелось бы получить.

Добавлено через 2 минуты

Не по теме:

taksebe, Я тоже на любой не понятный мне код могу написать как вы. НО, ведь можно же просто указать где именно не понятно. Или вам глобально все не понятно т.е. как объявлять переменные, методы и т.п.

0
35 / 10 / 6
Регистрация: 12.06.2013
Сообщений: 24
15.03.2014, 14:15 4
magnum1992, похоже, у Вас есть небольшие пробелы в понимании самого алгоритма. Я сильно не копался в коде, но что бросается в глаза:
1. У Вас нету сложения по модулю 2^32, у Вас просто сложение.
2. Вместо циклического сдвига на 11 бит влево у Вас просто сдвиг на 11 бит влево.

В общем, если хотите разобраться в алгоритме, лучше почитайте Винокурова, там подробно и доступно написано. Кроме того, вот моя тема, в которой я реализовал рабочий алгоритм простой замены: Реализация алгоритма шифрования по ГОСТ 28147-89.
Если понадобится реализация режима гаммирования или алгоритм генерации случайных 256-битовых ключей и 64-х битовой синхропосылки, можете заглянуть сюда.
0
43 / 43 / 19
Регистрация: 22.05.2011
Сообщений: 156
Записей в блоге: 5
16.03.2014, 20:18  [ТС] 5
Andoku, Про циклический сдвиг я понял и уже переделал. А на счет сложения по модулю 2^32 насколько мне известно 32-х битные числа итак складываются по модулю 2^32

Добавлено через 3 минуты
Я вынес весь алгоритм в отдельный класс и оформил более понятнее. Все перепроверил исправил несколько ошибок и получил в итоге что если я ввожу слово helloooo то он мне возвращает шифрованное слово oooohell и потом если его расшифровать возвращает исходное слово. Так вот где возможна ошибка?

Добавлено через 58 секунд

Не по теме:

Может быть все правильно и это алгоритм так шифрует что бы никто не догадался:D



Добавлено через 18 минут
Andoku, Я на первый взгляд глянул ваш код и вот какие вопросы появились:
Фрагмент вашего кода:
C#
1
N1 = (uint)(dateFragment >> 32);
Вы тут получаете старшую часть
C#
1
(uint)((X + N1) % (Convert.ToUInt64(Math.Pow(2, 32))));
А тут делаете сложение по модулю 2^32 части ключа и старшей части данных. Хотя нужно брать судя по википедии младшую часть.

Добавлено через 1 минуту
Кликните здесь для просмотра всего текста
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace IS
{
    public static class Encryption
    {
        #region Инициализация блока замен
        private static byte[,] Sblocks = {
                            {4, 10, 9, 2, 13, 8, 0, 14, 6, 11, 1, 12, 7, 15, 5, 3},
                            {14, 11, 4, 12, 613, 15, 10, 23810759},
                            {5, 8,1, 13, 10, 3, 4, 2, 14, 15, 12, 7, 6, 0911},
                            {7, 13, 10, 1, 0, 8 ,9  ,15, 14, 4, 6, 1211, 253},
                            {6, 12, 71515, 13, 8410, 914, 0311, 2},
                            {4, 11, 10, 072113, 3685912, 15, 14},
                            {13,    11, 41315, 59010, 14, 768212},
                            {1, 15, 13, 05710, 492314, 611, 812}
                          };//Блок замен
        #endregion
 
        private static bool mod64(int length)//Проверка делится ли открытый текст нацело на 64 бита
        {
            if ((length % 8) == 0)
                return true;
            else
                return false;
        }
 
        private static List<UInt64> fillingListData(string data)//Возвращает список из 64-х битных блоков данных
        {
            List<UInt64> resultList = new List<UInt64>();
            byte[] temp = Encoding.Default.GetBytes(data);
            int startIndex =0;
            while (startIndex < temp.Length)
            {
                resultList.Add(BitConverter.ToUInt64(temp, startIndex));
                startIndex += 8;
            }
            return resultList;
        }
 
        private static List<UInt32> fillingListKey(string key)
        {
            List<UInt32> resultList = new List<UInt32>();
            byte[] temp = Encoding.Default.GetBytes(key);
            resultList.Add(BitConverter.ToUInt32(temp, 0));
            resultList.Add(BitConverter.ToUInt32(temp, 4));
            resultList.Add(BitConverter.ToUInt32(temp, 8));
            resultList.Add(BitConverter.ToUInt32(temp, 12));
            resultList.Add(BitConverter.ToUInt32(temp, 16));
            resultList.Add(BitConverter.ToUInt32(temp, 20));
            resultList.Add(BitConverter.ToUInt32(temp, 24));
            resultList.Add(BitConverter.ToUInt32(temp, 28));
            return resultList;
        }//Возвращает список из 32-х битных блоков ключа
 
        private static string getPartString(UInt64 partText)
        {
            byte[] temp = BitConverter.GetBytes(partText);
            string result = Encoding.Default.GetString(temp);
            return result;
        }
 
        private static string fillingArrayData(List<UInt64> list)//Из списка чисел UInt64 возвращает строку
        {
            byte[] array = new byte[list.Count * 8];
            int index = 0;
            
            for (int i = 0; i < list.Count; ++i)
            {
                byte[] tempArray =  BitConverter.GetBytes(list[i]);
                for (int j = 0; j <tempArray.Length; ++j)
                {
                    array[index] = tempArray[j];
                    index++;
                }
            }
            string resultStr = Encoding.Default.GetString(array);
            return resultStr;
        }
 
        private static UInt32 mod2_32(UInt32 a, UInt32 b)
        {
            UInt32 result = a + b;
            return result;
        }// Сложение по модулю 2^32
 
        private static UInt32 shiftN(UInt32 num, int n)
        {
            UInt32 c = num;
            for (int i = 0; i < n; ++i)
            {
                //UInt32 temp = (UInt32)(num / Convert.ToUInt32(Math.Pow(2, 31)));
                UInt32 temp = num >> 31;
                num <<= 1;
                num += temp;
            }
            return num;
        }//циклический сдвиг 32-х битового числа на n разрядов 
 
        private static UInt32 retL(UInt64 data)
        {
            data >>= 32;
            UInt32 result = (UInt32)data;//temp;
            return result;
        }//Возвращает старшую часть 8 байтового блока данных
 
        private static UInt32 retR(UInt64 data)
        {
            UInt32 result = (UInt32)data;
            return result;
        }//Возвращает младшую часть 8 байтового блока данных
 
        private static UInt32 func(UInt32 R, UInt32 Ki)
        {
            UInt32 s = mod2_32(R, Ki);
            List<UInt32> partsS = new List<UInt32>();
            for (int i = 0; i < 8; ++i)
            {
 
                UInt32 temp = s>>28;
                partsS.Add(temp);
                s <<= 4;
            }
            for (int i = 0; i < 8; ++i)
            {
                partsS[i] = Sblocks[i, (int)partsS[i]];
            }
            s = 0;
            UInt32 my = 0;
            for (int i = 0; i < partsS.Count; ++i)
            {
                my += partsS[i];
                my <<= 4;
            }
            my = shiftN(my, 11);
            return s;
        }//Функция f(Ri, Ki), используемая в сети Фейстеля
 
        private static UInt64 encodePartData(UInt64 partData, List<UInt32> partsKey)//Шифрует 64-х битный блок данных
        {
            UInt32 L = retL(partData);
            UInt32 R = retR(partData);
            UInt32 temp = 0;
            int index = 0;
            bool flag = true;
            for (int i = 0; i < 32; ++i)
            {
                if (i == 24)
                {
                    flag = false;
                }
                if (flag)
                {
                    if (index == 8)
                    {
                        index = 0;
                    }
                    temp = func(R, partsKey[index]);
                    index++;
                }
                else
                {
                    if (index == 8)
                    {
                        --index;
                    }
                    temp = func(R, partsKey[index]);
                    --index;
                }
                temp = L ^ temp;
                L = R;
                R = temp;
            }
            UInt64 result = R;
            result <<= 32;
            result += L;
            return result;
        }
 
        private static UInt64 decodePartData(UInt64 partData, List<UInt32> partsKey)
        {
            UInt32 L = retL(partData);
            UInt32 R = retR(partData);
            UInt32 temp = 0;
            int index = 0;
            bool flag = false;
            for (int i = 0; i < 32; ++i)
            {
                if (i == 24)
                {
                    flag = true;
                }
                if (flag)
                {
                    if (index == 8)
                    {
                        index = 0;
                    }
                    temp = func(R, partsKey[index]);
                    index++;
                }
                else
                {
                    if (index == 0)
                    {
                        index = 7;
                    }
                    temp = func(R, partsKey[index]); 
                    --index;
                }
                temp = L ^ temp;
                L = R;
                R = temp;
            }
            UInt64 result = R;
            result <<= 32;
            result += L;
            return result;
        }//Расшифровывает 64-х битный блок шифрованных данных
 
        public static string encode(string data, string key)
        {
            if (!mod64(data.Length))
            {
                while (!mod64(data.Length))
                {
                    data += "\0";
                }
            }
            List<UInt32> partsKey = fillingListKey(key);
            List<UInt64> partsData = fillingListData(data);
            List<UInt64> encodedData = new List<UInt64>();
            string result = "";
            for (int i = 0; i < partsData.Count; ++i)
            {
               encodedData.Add(encodePartData(partsData[i], partsKey));
            }
            for (int i = 0; i < encodedData.Count; ++i)
            {
                result += getPartString(encodedData[i]);
            }
            return result;
        
        }//Метод шифрования
 
        public static string decode(string codedData, string key)
        {
            List<UInt32> partsKey = fillingListKey(key);
            List<UInt64> partsData = fillingListData(codedData);
            List<UInt64> decodedData = new List<UInt64>();
            string result = "";
            for (int i = 0; i < partsData.Count; ++i)
            {
                decodedData.Add(decodePartData(partsData[i], partsKey));
            }
            for (int i = 0; i < decodedData.Count; ++i)
            {
                result += getPartString(decodedData[i]);
            }
            return result;
        }//Метод расшифровки
    }
}

Вот мой класс

Добавлено через 30 минут
Andoku,
Цитата Сообщение от Andoku Посмотреть сообщение
Ошибка была таки в алгоритме. Оказывается, последний шаг 32-З и 32-Р должен отличаться от предыдущих 31-го тем, что в нем не производится сдвиг по цепочке в конце.
Про это на википедии не написано.
1
35 / 10 / 6
Регистрация: 12.06.2013
Сообщений: 24
16.03.2014, 21:07 6
А на счет сложения по модулю 2^32 насколько мне известно 32-х битные числа итак складываются по модулю 2^32
Логично, не додумался сразу

А тут делаете сложение по модулю 2^32 части ключа и старшей части данных. Хотя нужно брать судя по википедии младшую часть.
Да, действительно, этот момент я упустил. Но думаю, что это никак не влияет на стойкость алгоритма, так как в остальном коде на месте старшей части у меня младшая.

Все перепроверил исправил несколько ошибок и получил в итоге что если я ввожу слово helloooo то он мне возвращает шифрованное слово oooohell и потом если его расшифровать возвращает исходное слово. Так вот где возможна ошибка?
Думаю, что вся проблема как раз в этом:
Ошибка была таки в алгоритме. Оказывается, последний шаг 32-З и 32-Р должен отличаться от предыдущих 31-го тем, что в нем не производится сдвиг по цепочке в конце.
У меня тоже в изначальном коде перевернутые данные получались. Самое смешное, что об этом молчит не только Википедия, но и Винокуров. А в сети, если поискать готовый алгоритм, все пишут без сдвига в конце. И откуда это пошло - непонятно
0
Master of Orion
Эксперт .NET
6078 / 4934 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
16.03.2014, 21:32 7
magnum1992, википедия вообще плохой источник
0
43 / 43 / 19
Регистрация: 22.05.2011
Сообщений: 156
Записей в блоге: 5
16.03.2014, 22:26  [ТС] 8
В общем проблема решена путем разделения сети Фейстеля в отдельный метод. В методе en/decodePartData на столько было все запутано что уже и сам толком не мог разделить где что.
Вот полностью рабочий класс:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace IS
{
    public static class Encryption
    {
        #region Инициализация блока замен
        private static byte[,] Sblocks = {
                            {4, 10, 9, 2, 13, 8, 0, 14, 6, 11, 1, 12, 7, 15, 5, 3},
                            {14, 11, 4, 12, 613, 15, 10, 23810759},
                            {5, 8,1, 13, 10, 3, 4, 2, 14, 15, 12, 7, 6, 0911},
                            {7, 13, 10, 1, 0, 8 ,9  ,15, 14, 4, 6, 1211, 253},
                            {6, 12, 71515, 13, 8410, 914, 0311, 2},
                            {4, 11, 10, 072113, 3685912, 15, 14},
                            {13,    11, 41315, 59010, 14, 768212},
                            {1, 15, 13, 05710, 492314, 611, 812}
                          };//Блок замен
        #endregion
 
        private static bool mod64(int length)//Проверка делится ли открытый текст нацело на 64 бита
        {
            if ((length % 8) == 0)
                return true;
            else
                return false;
        }
 
        private static List<UInt64> fillingListData(string data)//Возвращает список из 64-х битных блоков данных
        {
            List<UInt64> resultList = new List<UInt64>();
            byte[] temp = Encoding.Default.GetBytes(data);
            int startIndex = 0;
            while (startIndex < temp.Length)
            {
                resultList.Add(BitConverter.ToUInt64(temp, startIndex));
                startIndex += 8;
            }
            return resultList;
        }
 
        private static List<UInt32> fillingListKey(string key)
        {
            List<UInt32> resultList = new List<UInt32>();
            byte[] temp = Encoding.Default.GetBytes(key);
            resultList.Add(BitConverter.ToUInt32(temp, 0));
            resultList.Add(BitConverter.ToUInt32(temp, 4));
            resultList.Add(BitConverter.ToUInt32(temp, 8)); 
            resultList.Add(BitConverter.ToUInt32(temp, 12));
            resultList.Add(BitConverter.ToUInt32(temp, 16));
            resultList.Add(BitConverter.ToUInt32(temp, 20));
            resultList.Add(BitConverter.ToUInt32(temp, 24));
            resultList.Add(BitConverter.ToUInt32(temp, 28));
            return resultList;
        }//Возвращает список из 32-х битных блоков ключа
 
        private static string getPartString(UInt64 partText)
        {
            byte[] temp = BitConverter.GetBytes(partText);
            string result = Encoding.Default.GetString(temp);
            return result;
        }//Возврашает часть зашифрованной/расшифрованной строки
 
        private static UInt32 mod2_32(UInt32 a, UInt32 b)
        {
            UInt32 result = a + b;
            return result;
        }// Сложение по модулю 2^32
 
        private static UInt32 shiftN(UInt32 num, int n)
        {
            UInt32 c = num;
            for (int i = 0; i < n; ++i)
            {
                //UInt32 temp = (UInt32)(num / Convert.ToUInt32(Math.Pow(2, 31)));
                UInt32 temp = num >> 31;
                num <<= 1;
                num += temp;
            }
            return num;
        }//циклический сдвиг 32-х битового числа на n разрядов 
 
        private static UInt32 retL(UInt64 data)
        {
            data >>= 32;
            UInt32 result = (UInt32)data;//temp;
            return result;
        }//Возвращает старшую часть 8 байтового блока данных
 
        private static UInt32 retR(UInt64 data)
        {
            UInt32 result = (UInt32)data;
            return result;
        }//Возвращает младшую часть 8 байтового блока данных
 
        private static UInt32 func(UInt32 R, UInt32 Ki)
        {
            UInt32 s = mod2_32(R, Ki);
            List<UInt32> partsS = new List<UInt32>();
            for (int i = 0; i < 8; ++i)
            {
 
                UInt32 temp = s >> 28;
                partsS.Add(temp);
                s <<= 4;
            }
            partsS.Reverse();
            for (int i = 0; i < 8; ++i)
            {
                partsS[i] = Sblocks[i, (int)partsS[i]];
            }
            s = 0;
            for (int i = 0; i < partsS.Count; ++i)
            {
                s += partsS[i];
                s <<= 4;
            }
                s = shiftN(s, 11);
            return s;
        }//Функция f(Ri, Ki), используемая в сети Фейстеля
 
        private static UInt64 encodePartData(UInt64 partData, List<UInt32> partsKey)
        {
            for (int i = 0; i < 24; ++i)
            {
                partData = feistel(partData, partsKey[i%8]);
            }
            for (int i = 7; i >= 0; --i)
            {
                partData = feistel(partData, partsKey[i]);
            }
            UInt64 result = (partData << 32) + (partData >> 32);
            return result;
        }//Шифрует 64-х битный блок данных
 
        private static UInt64 decodePartData(UInt64 partData, List<UInt32> partsKey)
        {
            for (int i = 0; i < 8; ++i)
            {
                partData = feistel(partData, partsKey[i]);
            }
            for (int i = 23; i >= 0; --i)
            {
                partData = feistel(partData, partsKey[i % 8]);
            }
            UInt64 result = (partData << 32) + (partData >> 32);
            return result;
        }//Расшифровывает 64-х битный блок шифрованных данных
 
        private static UInt64 feistel(UInt64 partData, UInt32 partKey)//осуществляет шаг в сети Фейстеля
        {
            UInt32 L = retL(partData);
            UInt32 R = retR(partData);
            UInt32 temp = func(R, partKey);
            UInt32 xor = L ^ temp;
            UInt64 result = (UInt64)R;
            result <<= 32;
            result += (UInt64)xor;
            return result;
        }
 
        public static string encode(string data, string key)
        {            
            if (!mod64(data.Length))
            {
                while (!mod64(data.Length))
                {
                    data += "\0";
                }
            }
            List<UInt32> partsKey = fillingListKey(key);
            List<UInt64> partsData = fillingListData(data);
            List<UInt64> encodedData = new List<UInt64>();
            string result = "";
            for (int i = 0; i < partsData.Count; ++i)
            {
                encodedData.Add(encodePartData(partsData[i], partsKey));
            }
            for (int i = 0; i < encodedData.Count; ++i)
            {
                result += getPartString(encodedData[i]);
            }
            return result;
 
        }//Метод шифрования
 
        public static string decode(string codedData, string key)
        {
            List<UInt32> partsKey = fillingListKey(key);
            List<UInt64> partsData = fillingListData(codedData);
            List<UInt64> decodedData = new List<UInt64>();
            string result = "";
            for (int i = 0; i < partsData.Count; ++i)
            {
                decodedData.Add(decodePartData(partsData[i], partsKey));
            }
            for (int i = 0; i < decodedData.Count; ++i)
            {
                result += getPartString(decodedData[i]);
            }
            return result;
        }//Метод расшифровки
    }
}
И кстати Andoku, все 32 шага выполнял со сдвигом.
3
35 / 10 / 6
Регистрация: 12.06.2013
Сообщений: 24
16.03.2014, 23:12 9
magnum1992, объясню, почему у тебя так вышло: смотри, ты в основном шаге криптопреобразования делаешь сдвиг, то есть меняешь R на L. Далее, в методах en/decodePartData ты в конце еще раз переставляешь R и L (не знаю, есть ли эта операция в Википедии, но по Винокурову ее быть не должно). То есть, если бы в последнем шаге ты не делал эту самую перестановку R и L, тебе бы не пришлось еще раз менять их местами в en/decodePartData. Так что по сути, ты все равно не делаешь сдвиг по цепочке на последнем шаге
1
169 / 143 / 68
Регистрация: 02.10.2011
Сообщений: 613
21.12.2014, 17:03 10
magnum1992,
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  private static UInt32 func(UInt32 R, UInt32 Ki)
        {
            UInt32 s = mod2_32(R, Ki);
            List<UInt32> partsS = new List<UInt32>();
            for (int i = 0; i < 8; ++i)
            {
 
                UInt32 temp = s >> 28;
                partsS.Add(temp);
                s <<= 4;
            }
            partsS.Reverse();
            for (int i = 0; i < 8; ++i)
            {
                partsS[i] = Sblocks[i, (int)partsS[i]];
            }
            s = 0;
            for (int i = 0; i < partsS.Count; ++i)
            {
                s += partsS[i];
                s <<= 4;
            }
                s = shiftN(s, 11);
            return s;
Можно объяснить что тут происходит? Я не совсем понимаю.
0
0 / 0 / 0
Регистрация: 21.01.2015
Сообщений: 3
21.01.2015, 10:50 11
magnum1992, спасибо за представленную реализацию. У меня несколько вопросов:
1. Проверял ты свой код на примере из Госта 34.11-94?
В приложении А представлен процесс получения хэша, для шаговой функции строка
00000000 00000000
шифруется ключом
733d2C20 65686573 74746769 79676120
626e7373 20657369 326c6568 33206d54
на таблице замен, как у тебя,
и получается
42ABBCCE 32BC0B1B.

Я как крутил, у меня так и не получилось..

Потом я нашел этот пример в RFC 5831RFC 5831. В нем вроде написано, что это перевод, хотя значения ключа для шифрования другое... Как будто переставлены местами 4 и 7 октет.
K[1] = 733D2C20 65686573 74746769 326C6568
626E7373 20657369 79676120 33206D54
Я опять попробовал зашифровать и опять значения получились отличные от тех, что должны были.
Потом я посмотрел твою реализацию. В методе func(UInt32 R, UInt32 Ki) в части сбора частей после замены:
C#
1
2
3
4
5
 for (int i = 0; i < partsS.Count; ++i)
            {
                s += partsS[i];
                s <<= 4;
            }
неправильно собирается uint, сдвиг происходит на 1 символ больше, чем нужно, т.е. [4][1][0][3][A][6][4][4] превращаются в 0x103A6440, старший бит пропадает, а в младшем появляется 0.
По идее надо переставить строки в коде местами, т.е.
C#
1
2
3
4
5
 for (int i = 0; i < partsS.Count; ++i)
            {
                s <<= 4;
                s += partsS[i];
            }
После этого uint собрался нормально, но пример из госта все равно не получился.
Дальше я посмотрел, что ты инвертируешь partsS до замены, а после замены - нет и сдвигаешь уже перевернутый uint. Как я понял, надо перевернуть после замены обратно, что я и сделал, но это тоже не помогло

Я решил попробовать другие реализации - и из openssl, и ту которую сделал Andoku. Так и не получилось у меня..
Я решил написать свою В приложении к сообщению - моя реализация.

.. но пример запустить у меня так и не получилось..
Может есть у кого рабочий пример? Или может кто знает, как запустить представленные реализации госта, чтоб он заработал?
P.S. для запуска моей реализации - код такой:
Кликните здесь для просмотра всего текста

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// Ключ
            // Секретный Ключ шифрования (32 байта)
            byte[] bKey = {
                 0x73,  0x3d,  0x2C,  0x20,
         0x65,  0x68,  0x65,  0x73,
         0x74,  0x74,  0x67,  0x69,
         0x32,  0x6c,  0x65,  0x68,
         0x62,  0x6e,  0x73,  0x73,
         0x20,  0x65,  0x73,  0x69,
         0x79,  0x67,  0x61,  0x20,
         0x33,  0x20,  0x6d,  0x54
                          };
// Таблица с узлами замен
            // гост 34.11-94
            byte[] bRepTab = {
                                 0x4A,0x92,0xD8,0x0E,0x6B,0x1C,0x7F,0x53,
                                 0xEB,0x4C,0x6D,0xFA,0x23,0x81,0x07,0x59,
                                 0x58,0x1D,0xA3,0x42,0xEF,0xC7,0x60,0x9B,
                                 0x7D,0xA1,0x08,0x9F,0xE4,0x6C,0xB2,0x53,
                                 0x6C,0x71,0x5F,0xD8,0x4A,0x9E,0x03,0xB2,
                                 0x4B,0xA0,0x72,0x1D,0x36,0x85,0x9C,0xFE,
                                 0xDB,0x41,0x3F,0x59,0x0A,0xE7,0x68,0x2C,
                                 0x1F,0xD0,0x57,0xA4,0x92,0x3E,0x6B,0x8C
                             };
 
            byte[] data = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
 
// Самопроверка
            var codecE = new Coder();
 
            // Установка ключа
            codecE.SetKey(bKey);
 
            // Установка таблицы замен
            codecE.SetReplaceTable(bRepTab);
 
            byte[] enc_Data = codecE.SimpleEncoding(data);
            byte[] dec_Data = codecE.SimpleDecoding(enc_Data);

Заранее спасибо!!
0
Вложения
Тип файла: rar Coder.rar (2.8 Кб, 183 просмотров)
0 / 0 / 0
Регистрация: 21.01.2015
Сообщений: 3
22.01.2015, 09:47 12
Все, понял.. Ключ в примере из ГОСТа 43.11-94 надо было перевернутым задавать.
т.е. вместо
C#
1
2
3
4
5
6
7
8
9
10
 byte[] bKey = {
                 0x73,  0x3d,  0x2C,  0x20,
         0x65,  0x68,  0x65,  0x73,
         0x74,  0x74,  0x67,  0x69,
         0x79,  0x67,  0x61,  0x20,
         0x62,  0x6e,  0x73,  0x73,
         0x20,  0x65,  0x73,  0x69,
         0x32,  0x6c,  0x65,  0x68,
         0x33,  0x20,  0x6d,  0x54
                          };
надо было вводить:
C#
1
2
3
4
5
6
7
8
9
10
byte[] bKey = {
         0x33,  0x20,  0x6d,  0x54,
         0x32,  0x6c,  0x65,  0x68,
         0x20,  0x65,  0x73,  0x69,
         0x62,  0x6e,  0x73,  0x73,
         0x79,  0x67,  0x61,  0x20,
         0x74,  0x74,  0x67,  0x69,
         0x65,  0x68,  0x65,  0x73,
                 0x73,  0x3d,  0x2C,  0x20
                          };
Если кому-то понадобится, то в моей реализации при вводе этого ключа - получается ответ, как в примере.
0
0 / 0 / 0
Регистрация: 04.12.2015
Сообщений: 2
10.12.2015, 20:15 13
А можно как нибудь этот код связать с файлом. Что бы тот его шифровал и расшифровал?
0
0 / 0 / 0
Регистрация: 21.01.2015
Сообщений: 3
11.12.2015, 14:48 14
Да, можно. Я дал ссылку на свое приложение, но модератор ее стер за рекламу. Поищите в интернете.
0
Администратор
Эксперт .NET
12895 / 10514 / 4356
Регистрация: 17.03.2014
Сообщений: 21,195
Записей в блоге: 1
12.12.2015, 01:35 15
GPrarok, в теории да. Методы SimpleEncoding/SimpleDecoding принимают на вход массив байт. Читаем файл с помощью File.ReadAllBytes и шифруем. Однако больщие файлы так не зашифровать из-за банальной нехватки ОЗУ. Плюс реализация принимает данные с длинами кратными восьми. Надо дописывать шифрование под данные произвольной длиный используя метод GammaСoding(byte[] data, byte[] s).
1
0 / 0 / 0
Регистрация: 04.12.2015
Сообщений: 2
12.12.2015, 21:28 16
Спасибо большое, вот насчет метода GammaСoding(), поискал в интернете, не совсем разобрался как он будет работать, можете показать пример реализации в данном коде пожалуйста.
0
18 / 17 / 4
Регистрация: 22.03.2018
Сообщений: 701
02.11.2018, 23:06 17
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace ConsoleApp5
{
    class Program
    {
        static void Main()
        {
        }
        /// <summary>
        ///     Класс кодирования по ГОСТ 28147-89.
        ///     Для выполнения кодирования надо создать экземпляр класса и добавить ключ (SetKey) и таблицу замен
        ///     (SetReplaceTable).
        ///     SimpleEncoding - кодирование простой вставкой
        ///     SimpleDecoding - декодирование простой вставкой
        ///     GammaСoding - кодирование c использованием гаммирования
        ///     GammaWithFeedBackCoding - кодирование c использованием гаммирования с обратной связью
        ///     ImitationPaste - формирование имитовставки
        ///     Разработчик - Ефремов С.В.
        /// </summary> 
        public class Coder
        {
            #region Fields
 
            private UInt32[] key;
 
            private byte[,] replaceTable;
 
            #endregion
 
            #region Public Methods and Operators
 
            /// <summary>
            ///     Преобразование из UInt64 в 8 байт
            /// </summary>
            /// <param name="s"></param>
            /// <returns></returns>
            public static byte[] Get8BytesFromUInt64(UInt64 s)
            {
                var result = new byte[8];
                for (int i = 0; i < 8; i++)
                {
                    int shift = (56 - 8 * i);
                    result[i] = (byte)(s >> shift);
                    s = s & (UInt64.MaxValue - ((UInt64)0xff << shift));
                }
                return result;
            }
 
            /// <summary>
            ///     Преобразование из 8 байт в UInt64
            /// </summary>
            /// <param name="s">массив байт</param>
            /// <param name="startIndex">начальный индекс в массиве</param>
            /// <returns></returns>
            public static UInt64 GetUint64From8Bytes(byte[] s, int startIndex)
            {
                UInt64 result = 0;
                for (int i = startIndex; i < startIndex + 8; i++)
                {
                    int shift = (56 - 8 * i);
                    result += ((UInt64)s[i] << shift);
                }
                return result;
            }
 
            /// <summary>
            ///     Шифрование гаммированием с обратной связью
            /// </summary>
            /// <param name="data">блок данных, размером кратным 8</param>
            /// <param name="s">синхропосылка, размером 8 байт</param>
            /// <returns></returns>
            public byte[] GammaWithFeedBackCoding(byte[] data, byte[] s)
            {
                #region проверка
 
                if (data.Length % 8 != 0)
                {
                    throw new ArgumentOutOfRangeException("Размер данных должен быть кратным 8!");
                }
 
                if (s.Length != 8)
                {
                    throw new ArgumentOutOfRangeException("Размер синхропосылки должен быть равным 8!");
                }
 
                if (this.key == null)
                {
                    throw new ArgumentNullException("Не задан ключ шифрования!");
                }
 
                if (this.replaceTable == null)
                {
                    throw new ArgumentNullException("Не задана таблица замен!");
                }
 
                #endregion
 
                #region преобразование массива байт в массив uint64
 
                int lenght = data.Length / 8;
 
                var ulongsData = new UInt64[lenght];
 
                for (int i = 0; i < lenght; i++)
                {
                    ulongsData[i] = GetUint64From8Bytes(data, 8 * i);
                }
 
                ulong ulongS = GetUint64From8Bytes(s, 0);
 
                #endregion
 
                #region шифрование и дешифрование
 
                ulong[] crypt = GammaWithFeedBackCoding(ulongsData, ulongS);
 
                #endregion
 
                #region преобразование массива uint64 в массив байт
 
                var result = new byte[data.Length];
 
                for (int i = 0; i < crypt.Length; i++)
                {
                    byte[] bytes = Get8BytesFromUInt64(crypt[i]);
                    for (int j = 0; j < 8; j++)
                    {
                        result[i * 8 + j] = bytes[j];
                    }
                }
 
                #endregion
 
                return result;
            }
 
            /// <summary>
            ///     Шифрование гаммированием
            /// </summary>
            /// <param name="data">блок данных, размером кратным 8</param>
            /// <param name="s">синхропосылка, размером 8 байт</param>
            /// <returns></returns>
            public byte[] GammaСoding(byte[] data, byte[] s)
            {
                #region проверка
 
                if (data.Length % 8 != 0)
                {
                    throw new ArgumentOutOfRangeException("Размер данных должен быть кратным 8!");
                }
 
                if (s.Length != 8)
                {
                    throw new ArgumentOutOfRangeException("Размер синхропосылки должен быть равным 8!");
                }
 
                if (this.key == null)
                {
                    throw new ArgumentNullException("Не задан ключ шифрования!");
                }
 
                if (this.replaceTable == null)
                {
                    throw new ArgumentNullException("Не задана таблица замен!");
                }
 
                #endregion
 
                #region преобразование массива байт в массив uint64
 
                int lenght = data.Length / 8;
 
                var ulongsData = new UInt64[lenght];
 
                for (int i = 0; i < lenght; i++)
                {
                    ulongsData[i] = GetUint64From8Bytes(data, 8 * i);
                }
 
                ulong ulongS = GetUint64From8Bytes(s, 0);
 
                #endregion
 
                #region шифрование и дешифрование
 
                ulong[] crypt = GammaСoding(ulongsData, ulongS);
 
                #endregion
 
                #region преобразование массива uint64 в массив байт
 
                var result = new byte[data.Length];
 
                for (int i = 0; i < crypt.Length; i++)
                {
                    byte[] bytes = Get8BytesFromUInt64(crypt[i]);
                    for (int j = 0; j < 8; j++)
                    {
                        result[i * 8 + j] = bytes[j];
                    }
                }
 
                #endregion
 
                return result;
            }
 
            /// <summary>
            ///     Формирование имитовставки
            /// </summary>
            /// <param name="plainData">блок открытых данных, размером кратным 8</param>
            /// <returns></returns>
            public byte[] ImitationPaste(byte[] plainData)
            {
                #region проверка
 
                if (plainData.Length % 8 != 0)
                {
                    throw new ArgumentOutOfRangeException("Размер данных должен быть кратным 8!");
                }
 
                if (this.key == null)
                {
                    throw new ArgumentNullException("Не задан ключ шифрования!");
                }
 
                if (this.replaceTable == null)
                {
                    throw new ArgumentNullException("Не задана таблица замен!");
                }
 
                #endregion
 
                #region преобразование массива байт в массив uint64
 
                int lenght = plainData.Length / 8;
 
                var data = new UInt64[lenght];
 
                for (int i = 0; i < lenght; i++)
                {
                    data[i] = GetUint64From8Bytes(plainData, 8 * i);
                }
 
                #endregion
 
                #region расшифрование
 
                ulong crypt = ImitationPaste(data);
 
                #endregion
 
                #region преобразование массива uint64 в массив байт
 
                byte[] result = Get8BytesFromUInt64(crypt);
 
                #endregion
 
                return result;
            }
 
            /// <summary>
            ///     Метод установки ключа - восьми 32-битовых элементов кода
            /// </summary>
            /// <param name="keyData">массив из 32 байт</param>
            public void SetKey(byte[] keyData)
            {
                if (keyData.Length != 32)
                {
                    throw new ArgumentOutOfRangeException("Длина массива для ключа должна быть равна 32!");
                }
 
                this.key = new UInt32[8];
                for (int i = 0; i < keyData.Length; i += 4)
                {
                    UInt32 k = keyData[i];
                    k = k << 8;
                    k = k | keyData[i + 1];
                    k = k << 8;
                    k = k | keyData[i + 2];
                    k = k << 8;
                    k = k | keyData[i + 3];
                    this.key[i / 4] = k;
                }
            }
 
            /// <summary>
            ///     Метод установки таблицы замен - матрицы размера 8 х 16, содержащей 4-битовые элементы
            /// </summary>
            /// <param name="replaceTableData">массив из 64 байт</param>
            public void SetReplaceTable(byte[] replaceTableData)
            {
                if (replaceTableData.Length != 64)
                {
                    throw new ArgumentOutOfRangeException("Длина массива для ключа должна быть равна 64!");
                }
 
                this.replaceTable = new byte[8, 16];
 
                for (int i = 0; i < 8; i++)
                {
                    for (int j = 0; j < 8; j++)
                    {
                        int index = i * 8 + j;
                        byte rtd = replaceTableData[index];
                        this.replaceTable[i, j * 2] = (byte)(rtd >> 4);
                        this.replaceTable[i, j * 2 + 1] = (byte)(rtd & 0x0F);
                    }
                }
            }
 
            /// <summary>
            ///     Расшифрование простой заменой
            /// </summary>
            /// <param name="plainData">блок открытых данных, размером кратным 8</param>
            /// <returns></returns>
            public byte[] SimpleDecoding(byte[] plainData)
            {
                #region проверка
 
                if (plainData.Length % 8 != 0)
                {
                    throw new ArgumentOutOfRangeException("Размер данных должен быть кратным 8!");
                }
 
                if (this.key == null)
                {
                    throw new ArgumentNullException("Не задан ключ шифрования!");
                }
 
                if (this.replaceTable == null)
                {
                    throw new ArgumentNullException("Не задана таблица замен!");
                }
 
                #endregion
 
                #region преобразование массива байт в массив uint64
 
                int lenght = plainData.Length / 8;
 
                var data = new UInt64[lenght];
 
                for (int i = 0; i < lenght; i++)
                {
                    data[i] = GetUint64From8Bytes(plainData, 8 * i);
                }
 
                #endregion
 
                #region расшифрование
 
                ulong[] crypt = SimpleDecoding(data);
 
                #endregion
 
                #region преобразование массива uint64 в массив байт
 
                var result = new byte[plainData.Length];
 
                for (int i = 0; i < crypt.Length; i++)
                {
                    byte[] bytes = Get8BytesFromUInt64(crypt[i]);
                    for (int j = 0; j < 8; j++)
                    {
                        result[i * 8 + j] = bytes[j];
                    }
                }
 
                #endregion
 
                return result;
            }
 
            /// <summary>
            ///     Шифрование простой заменой
            /// </summary>
            /// <param name="plainData">блок открытых данных, размером кратным 8</param>
            /// <returns></returns>
            public byte[] SimpleEncoding(byte[] plainData)
            {
                #region проверка
 
                if (plainData.Length % 8 != 0)
                {
                    throw new ArgumentOutOfRangeException("Размер данных должен быть кратным 8!");
                }
 
                if (this.key == null)
                {
                    throw new ArgumentNullException("Не задан ключ шифрования!");
                }
 
                if (this.replaceTable == null)
                {
                    throw new ArgumentNullException("Не задана таблица замен!");
                }
 
                #endregion
 
                #region преобразование массива байт в массив uint64
 
                int lenght = plainData.Length / 8;
 
                var data = new UInt64[lenght];
 
                for (int i = 0; i < lenght; i++)
                {
                    data[i] = GetUint64From8Bytes(plainData, 8 * i);
                }
 
                #endregion
 
                #region шифрование
 
                ulong[] crypt = SimpleEncoding(data);
 
                #endregion
 
                #region преобразование массива uint64 в массив байт 
 
                var result = new byte[plainData.Length];
 
                for (int i = 0; i < crypt.Length; i++)
                {
                    byte[] bytes = Get8BytesFromUInt64(crypt[i]);
                    for (int j = 0; j < 8; j++)
                    {
                        result[i * 8 + j] = bytes[j];
                    }
                }
 
                #endregion
 
                return result;
            }
 
            #endregion
 
            #region Methods
 
            private UInt64 BaseCycle32I(UInt64 data)
            {
                UInt64 result = data;
 
                for (int i = 0; i < 2; i++)
                {
                    for (int j = 0; j < 8; j++)
                    {
                        result = this.MainCryptoStep(result, this.key[j]);
                    }
                }
 
                return result;
            }
 
            private UInt64 BaseCycle32R(UInt64 data)
            {
                UInt64 result = data;
 
                for (int j = 0; j < 8; j++)
                {
                    result = this.MainCryptoStep(result, this.key[j]);
                }
 
                for (int i = 0; i < 3; i++)
                {
                    for (int j = 7; j >= 0; j--)
                    {
                        result = this.MainCryptoStep(result, this.key[j]);
                    }
                }
 
                result = ((result & UInt32.MaxValue) << 32) | (result >> 32);
 
                return result;
            }
 
            private UInt64 BaseCycle32Z(UInt64 data)
            {
                UInt64 result = data;
 
                for (int i = 0; i < 3; i++)
                {
                    for (int j = 0; j < 8; j++)
                    {
                        result = this.MainCryptoStep(result, this.key[j]);
                    }
                }
 
                for (int j = 7; j >= 0; j--)
                {
                    result = this.MainCryptoStep(result, this.key[j]);
                }
 
                result = ((result & UInt32.MaxValue) << 32) | (result >> 32);
 
                return result;
            }
 
            private uint CycleLeftShift11(uint value)
            {
                uint result = value << 11 | value >> (32 - 11);
                return result;
            }
 
            private UInt64[] GammaWithFeedBackCoding(UInt64[] data, UInt64 s)
            {
                var result = new UInt64[data.Length];
 
                for (int i = 0; i < data.Length; i++)
                {
                    s = this.BaseCycle32Z(s);
                    result[i] = data[i] ^ s;
                    s = result[i];
                }
 
                return result;
            }
 
            private UInt64[] GammaСoding(UInt64[] data, UInt64 s)
            {
                var result = new UInt64[data.Length];
 
                const uint C1 = 0x1010101;
                const uint C2 = 0x1010104;
 
                #region шаг 1
 
                ulong newS = this.BaseCycle32Z(s);
 
                #endregion
 
                var s0 = (UInt32)(newS & UInt32.MaxValue);
                var s1 = (UInt32)(newS >> 32);
 
                for (int i = 0; i < data.Length; i++)
                {
                    #region шаг 2
 
                    s0 = s0 + C1;
                    s1 = (uint)((s1 + C2 - 1) % (Math.Pow(2, 32) - 1) + 1);
                    newS = s1;
                    newS = newS << 32;
                    newS = newS | s0;
 
                    #endregion
 
                    #region шаг 3
 
                    newS = this.BaseCycle32Z(newS);
                    result[i] = data[i] ^ newS;
 
                    #endregion
                }
 
                return result;
            }
 
            private UInt64 ImitationPaste(UInt64[] data)
            {
                UInt64 s = 0;
                for (int i = 0; i < data.Length; i++)
                {
                    s = this.BaseCycle32I(s ^ data[i]);
                }
                return s;
            }
 
            private UInt64 MainCryptoStep(UInt64 data, UInt32 keyPart)
            {
                #region шаг 0 - разбивание UInt64 на два UInt32
 
                var n2 = (UInt32)(data >> 32);
                var n1 = (UInt32)(data & UInt32.MaxValue);
 
                #endregion
 
                #region шаг 1 - сложение по модулю 2^32
 
                UInt32 step1Value = n1 + keyPart;
 
                #endregion
 
                #region шаг 2 - замена
 
                uint step2Value = this.ReplaceValues(step1Value);
 
                #endregion
 
                #region шаг 3 - сдвиг влево на 11
 
                uint step3Value = this.CycleLeftShift11(step2Value);
 
                #endregion
 
                #region шаг 4 - сложение по модулю 2
 
                uint step4Value = step3Value ^ n2;
 
                #endregion
 
                #region шаг 5 - сдвиг по цепочке
 
                n2 = n1;
                n1 = step4Value;
 
                #endregion
 
                #region шаг 6 - возврат полученного значения
 
                UInt64 step6Value = (UInt64)n2 << 32 | n1;
 
                #endregion
 
                return step6Value;
            }
 
            private uint ReplaceValues(uint step1Value)
            {
                uint result = 0;
                for (int i = 0; i < 8; i++)
                {
                    result <<= 4;
                    int shift = 32 - 4 - 4 * i;
                    uint index = (step1Value >> shift) & 0xf;
                    step1Value = step1Value & (UInt32.MaxValue - ((UInt32)0xf << shift));
                    result += this.replaceTable[7 - i, index];
                }
                return result;
            }
 
            private UInt64[] SimpleDecoding(UInt64[] encryptedData)
            {
                var plainText = new UInt64[encryptedData.Length];
                for (int i = 0; i < encryptedData.Length; i++)
                {
                    plainText[i] = this.BaseCycle32R(encryptedData[i]);
                }
                return plainText;
            }
 
            private UInt64[] SimpleEncoding(UInt64[] plainData)
            {
                var result = new UInt64[plainData.Length];
                for (int i = 0; i < plainData.Length; i++)
                {
                    result[i] = this.BaseCycle32Z(plainData[i]);
                }
                return result;
            }
 
            #endregion
        }
    }
}
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
02.11.2018, 23:06

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь.

Гост 28147-89 режим простой замены
Здравствуйте, расскажите пожалуйста как работает эта программа # -*- coding: UTF-8 -*- import sys...

ГОСТ 28147-89 Режим простой замены. Исходный текст не совпадает с дешифрованным
Добрый вечер, уважаемы форумчане. Решил реализовать шифр ГОСТ 28147-89 Режим простой замены. ...

ГОСТ 28147-89. Метод простой замены
Доброй ночи, уважаемые форумчане! У меня есть исходный код программы: ...

алгоритм шифрования ГОСТ 28147-89
писалось на коленке за 1 день. режим простой замены.для имитовставки воспользоваться 2 раундами....


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
17
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.