1
|
; 2013 год
|
2
|
; Шрифт: Lucida Console (10)
|
3
|
|
4
|
// Реализация алгоритма шифрования ГОСТ 28147-89 для MC P1.
|
5
|
// Режим шифрования данных - простая замена.
|
6
|
|
7
|
// Особенности:
|
8
|
// * входной буффер должен быть кратным 8 байтам
|
9
|
// * параметр "blocks_count" указывает количество блоков размером по 8 байт во входном буффере
|
10
|
|
11
|
|
12
|
// void mc_gost_encdec(int direction, unsigned int *key, unsigned int *buf, int blocks_count);
|
13
|
|
14
|
|
15
|
|
16
|
.alias SP 39 /* Стек. (в алгоритме старшие 4 байта не сохраняются!)*/
|
17
|
.alias DEC 0 /* Запрошена операция шифрования или расшифровывания */
|
18
|
.alias AA 1 /* Ai */
|
19
|
.alias BB 2 /* Bi */
|
20
|
.alias KI 3 /* Ki */
|
21
|
.alias BLK 4 /* Текущий номер блока */
|
22
|
.alias IDX 5 /* Номер раунда */
|
23
|
.alias SB 32 /* Sblock */
|
24
|
|
25
|
|
26
|
.global mc_gost_encdec
|
27
|
|
28
|
.data
|
29
|
|
30
|
.align 8
|
31
|
|
32
|
Sblock:
|
33
|
/* Определяем тестовые S-блоки в соответствии с ГОСТ Р 34.11-94 (ГОСТ Р 34.11-94 устарел. С 1 января 2013 года надо использвать ГОСТ Р 34.11-2012)*/
|
34
|
.quad 0x35F7C1B6E08D29A4
|
35
|
.quad 0x95701832AFD6C4BE
|
36
|
.quad 0xB9067CFE243AD185
|
37
|
.quad 0x352BC64EF9801AD7
|
38
|
.quad 0x2B30E9A48DF517B6
|
39
|
.quad 0xEFC95863D1270AB4
|
40
|
.quad 0xC2867EA095F314BD
|
41
|
.quad 0xC8B6E3294A750DF1
|
42
|
|
43
|
|
44
|
.bss
|
45
|
|
46
|
.align 8
|
47
|
|
48
|
Keys:
|
49
|
.long 0
|
50
|
|
51
|
.align 8
|
52
|
|
53
|
BufPtr:
|
54
|
.long 0
|
55
|
|
56
|
|
57
|
.text
|
58
|
|
59
|
//====================================
|
60
|
.alias gost_encdec.dec #SP,4 /* operation */
|
61
|
.alias gost_encdec.key #SP,8 /* pointer keys */
|
62
|
.alias gost_encdec.buf #SP,12 /* pointer buf */
|
63
|
.alias gost_encdec.blk #SP,16 /* block count */
|
64
|
.alias gost_encdec.old_r1 #SP,-8 ; Из-за особенностей 'SETx' приходится брать все 8 байт
|
65
|
.alias gost_encdec.old_r2 #SP,-16
|
66
|
.alias gost_encdec.old_r3 #SP,-24
|
67
|
.alias gost_encdec.old_r4 #SP,-32
|
68
|
.alias gost_encdec.old_r5 #SP,-40
|
69
|
.alias gost_encdec.old_r6 #SP,-48
|
70
|
.alias gost_encdec.old_r7 #SP,-56
|
71
|
|
72
|
.alias gost_encdec.stackb 56 ; Количество байт под стек. #BP(#38) не используется.
|
73
|
.alias gost_encdec.old_r1.newSP #SP,48
|
74
|
.alias gost_encdec.old_r2.newSP #SP,40
|
75
|
.alias gost_encdec.old_r3.newSP #SP,32
|
76
|
.alias gost_encdec.old_r4.newSP #SP,24
|
77
|
.alias gost_encdec.old_r5.newSP #SP,16
|
78
|
.alias gost_encdec.old_r6.newSP #SP,8
|
79
|
.alias gost_encdec.old_r7.newSP #SP
|
80
|
|
81
|
.alias gost_encdec.RET.newSP #SP, gost_encdec.stackb ; Возврат из функции
|
82
|
|
83
|
|
84
|
mc_gost_encdec:
|
85
|
gost_encdec:
|
86
|
|
87
|
SP13 := getq #SP ; выделяем наш кадр стека. Часть 1 из 3
|
88
|
|
89
|
dec := rdl gost_encdec.dec /* operation */
|
90
|
key := rdl gost_encdec.key /* key */
|
91
|
buf := rdl gost_encdec.buf /* buf */
|
92
|
blk := rdl gost_encdec.blk /* block count */
|
93
|
|
94
|
; Получение значений регистров
|
95
|
old1 := getq #DEC
|
96
|
old2 := getq #AA
|
97
|
old3 := getq #BB
|
98
|
old4 := getq #KI
|
99
|
old5 := getq #BLK
|
100
|
old6 := getq #IDX
|
101
|
old7 := getq #SB
|
102
|
|
103
|
SP23 := subl @SP13, gost_encdec.stackb ; выделяем наш кадр стека. Часть 2 из 3
|
104
|
|
105
|
setl #DEC, @dec
|
106
|
wrl @key, Keys
|
107
|
setl #BLK, @blk
|
108
|
wrl @buf, BufPtr
|
109
|
|
110
|
setl #SB, Sblock
|
111
|
|
112
|
setl #SP, @SP23 ; выделяем наш кадр стека. Часть 3 из 3
|
113
|
|
114
|
; Сохранение старых значений регистров в стеке
|
115
|
wrq @old1, gost_encdec.old_r1
|
116
|
wrq @old2, gost_encdec.old_r2
|
117
|
wrq @old3, gost_encdec.old_r3
|
118
|
wrq @old4, gost_encdec.old_r4
|
119
|
wrq @old5, gost_encdec.old_r5
|
120
|
wrq @old6, gost_encdec.old_r6
|
121
|
wrq @old7, gost_encdec.old_r7
|
122
|
|
123
|
jmp gost.next_block
|
124
|
|
125
|
complete
|
126
|
|
127
|
//====================================
|
128
|
|
129
|
gost.next_block:
|
130
|
|
131
|
r1 := getl #BLK
|
132
|
r2 := subl @r1, 1
|
133
|
setl #BLK, @r2
|
134
|
|
135
|
je @r1, gost.return
|
136
|
jne @r1, gost.fetch_block
|
137
|
|
138
|
complete
|
139
|
|
140
|
//====================================
|
141
|
|
142
|
gost.fetch_block:
|
143
|
|
144
|
r1 := getl #DEC
|
145
|
|
146
|
r2 := rdl BufPtr /* указатель на буффер */
|
147
|
r3 := addl @r2, 4
|
148
|
|
149
|
r4 := rdl @r2 /* считывает два первых значения */
|
150
|
r5 := rdl @r3
|
151
|
|
152
|
setl #AA, @r4
|
153
|
setl #BB, @r5
|
154
|
|
155
|
je @r1, gost_enc.prologue
|
156
|
jne @r1, gost_dec.prologue
|
157
|
|
158
|
complete
|
159
|
|
160
|
//====================================
|
161
|
|
162
|
gost_enc.prologue:
|
163
|
|
164
|
setl #IDX, 0
|
165
|
|
166
|
jmp gost.load_key1_24
|
167
|
|
168
|
complete
|
169
|
|
170
|
//====================================
|
171
|
|
172
|
gost_dec.prologue:
|
173
|
|
174
|
setl #IDX, 31
|
175
|
|
176
|
jmp gost.load_key25_32
|
177
|
|
178
|
complete
|
179
|
|
180
|
//====================================
|
181
|
|
182
|
gost.load_key1_24:
|
183
|
|
184
|
kp := rdl Keys
|
185
|
r1 := getl #IDX
|
186
|
|
187
|
r2 := and @r1, 7 /* Ограничиваем i пределами [0..7] */
|
188
|
r3 := slll @r2, 2 /* Смещение до Ki */
|
189
|
r4 := addl @kp, @r3 /* Ki = kp + i*4 */
|
190
|
r5 := rdl @r4
|
191
|
setl #KI, @r5
|
192
|
|
193
|
jmp gost.round
|
194
|
|
195
|
complete
|
196
|
|
197
|
//====================================
|
198
|
|
199
|
gost.load_key25_32:
|
200
|
|
201
|
kp := rdl Keys
|
202
|
r1 := getl #IDX
|
203
|
|
204
|
r2 := and @r1, 7 /* Ограничиваем i пределами [7..0] */
|
205
|
r3 := slll @r2, 2 /* Смещение до Ki */
|
206
|
r4 := addl @kp, 7 * 4 /* Пермещаем указатель к последнему элементу */
|
207
|
r5 := subl @r4, @r3 /* Отсчитываем ключ с конца: Ki = kp - i*4 */
|
208
|
r6 := rdl @r5
|
209
|
setl #KI, @r6
|
210
|
|
211
|
jmp gost.round
|
212
|
|
213
|
complete
|
214
|
|
215
|
//====================================
|
216
|
|
217
|
gost.round:
|
218
|
|
219
|
r1 := getl #KI
|
220
|
|
221
|
/* Сохраняем в коммутатор 8 значений Sblock */
|
222
|
s0 := rdq #SB
|
223
|
s1 := rdq #SB, 8
|
224
|
s2 := rdq #SB, 16
|
225
|
|
226
|
axk := xor @r1, #AA /* Сложение Ai + Ki по mod 2 */
|
227
|
|
228
|
s3 := rdq #SB, 24
|
229
|
s4 := rdq #SB, 32
|
230
|
s5 := rdq #SB, 40
|
231
|
s6 := rdq #SB, 48
|
232
|
s7 := rdq #SB, 56
|
233
|
|
234
|
/* Разбиваем на 4-х битную подпоследовательность */
|
235
|
r3 := slrl @axk, 4
|
236
|
r4 := slrl @axk, 8
|
237
|
r5 := slrl @axk, 12
|
238
|
r6 := slrl @axk, 16
|
239
|
r7 := slrl @axk, 20
|
240
|
r8 := slrl @axk, 24
|
241
|
r9 := slrl @axk, 28
|
242
|
/* Получаем индекс для каждой подпоследовательности */
|
243
|
r10 := and @axk, 0xf
|
244
|
r11 := and @r3, 0xf
|
245
|
r12 := and @r4, 0xf
|
246
|
r13 := and @r5, 0xf
|
247
|
r14 := and @r6, 0xf
|
248
|
r15 := and @r7, 0xf
|
249
|
r16 := and @r8, 0xf
|
250
|
r17 := and @r9, 0xf
|
251
|
/* ...растягиваем, чтобы потом сдвигать вправо с кратностью по 4 бита */
|
252
|
r18 := slll @r10, 2
|
253
|
r19 := slll @r11, 2
|
254
|
r20 := slll @r12, 2
|
255
|
r21 := slll @r13, 2
|
256
|
r22 := slll @r14, 2
|
257
|
r23 := slll @r15, 2
|
258
|
r24 := slll @r16, 2
|
259
|
r25 := slll @r17, 2
|
260
|
/* Получаем значение по индексу */
|
261
|
r26 := slrq @s0, @r18
|
262
|
r27 := slrq @s1, @r19
|
263
|
r28 := slrq @s2, @r20
|
264
|
r29 := slrq @s3, @r21
|
265
|
r30 := slrq @s4, @r22
|
266
|
r31 := slrq @s5, @r23
|
267
|
r32 := slrq @s6, @r24
|
268
|
r33 := slrq @s7, @r25
|
269
|
|
270
|
r34 := and @r26, 0xf
|
271
|
r35 := and @r27, 0xf
|
272
|
r36 := and @r28, 0xf
|
273
|
r37 := and @r29, 0xf
|
274
|
r38 := and @r30, 0xf
|
275
|
r39 := and @r31, 0xf
|
276
|
r40 := and @r32, 0xf
|
277
|
r41 := and @r33, 0xf
|
278
|
/* Склеиваем подпоследовательности */
|
279
|
r42 := slll @r35, 4
|
280
|
r43 := slll @r36, 8
|
281
|
r44 := slll @r37, 12
|
282
|
r45 := slll @r38, 16
|
283
|
r46 := slll @r39, 20
|
284
|
r47 := slll @r40, 24
|
285
|
r48 := slll @r41, 28
|
286
|
|
287
|
;мин 3 такта
|
288
|
r49 := or @r34, @r42
|
289
|
r50 := or @r43, @r44
|
290
|
r51 := or @r45, @r46
|
291
|
r52 := or @r47, @r48
|
292
|
r53 := or @r49, @r50
|
293
|
r54 := or @r51, @r52
|
294
|
r55 := or @r53, @r54
|
295
|
|
296
|
r61 := getl #DEC
|
297
|
|
298
|
r56 := roll @r55, 11 /* Циклический сдвиг влево на 11 бит */
|
299
|
r57 := getl #BB
|
300
|
r58 := xor @r57, @r56 /* Bi ^ f(Ai,Ki) */
|
301
|
r59 := setl #BB, #AA /* Bi+1 = Ai */
|
302
|
r60 := setl #AA, @r58 /* Ai+1 = Bi ^ f(Ai,Ki) */
|
303
|
|
304
|
r62 := je @r61, gost_enc.epilogue
|
305
|
r63 := jne @r61, gost_dec.epilogue
|
306
|
|
307
|
complete
|
308
|
|
309
|
//====================================
|
310
|
|
311
|
gost_enc.epilogue:
|
312
|
|
313
|
r1 := getl #IDX
|
314
|
r2 := addl @r1, 1
|
315
|
setl #IDX, @r2
|
316
|
|
317
|
r3 := subl @r2, 24
|
318
|
r4 := subl @r2, 32
|
319
|
|
320
|
r5 := and @r3, 0x80000000
|
321
|
jne @r5, gost.load_key1_24
|
322
|
|
323
|
r6 := and @r4, 0x80000000
|
324
|
r7 := xor @r5, @r6
|
325
|
jne @r7, gost.load_key25_32
|
326
|
|
327
|
r8 := or @r5, @r7
|
328
|
|
329
|
je @r8, gost.save_results ; Готово, далее сохраняем и берём следующие значения из буфера
|
330
|
|
331
|
complete
|
332
|
|
333
|
//====================================
|
334
|
|
335
|
gost_dec.epilogue:
|
336
|
|
337
|
r1 := getl #IDX
|
338
|
r2 := subl @r1, 1
|
339
|
setl #IDX, @r2
|
340
|
|
341
|
je @r1, gost.save_results ; Готово, далее сохраняем и берём следующие значения из буфера
|
342
|
jne @r1, gost_dec.epilogue.2
|
343
|
|
344
|
complete
|
345
|
|
346
|
gost_dec.epilogue.2: ; Убрали лишнее
|
347
|
|
348
|
r1 := getl #IDX
|
349
|
|
350
|
r2 := subl @r1, 24
|
351
|
|
352
|
r4 := and @r2, 0x80000000
|
353
|
jne @r4, gost.load_key1_24
|
354
|
|
355
|
je @r4, gost.load_key25_32
|
356
|
complete
|
357
|
|
358
|
/* ; Полный вариант
|
359
|
gost_dec.epilogue.2:
|
360
|
|
361
|
r1 := getl #IDX
|
362
|
|
363
|
r2 := subl @r1, 24
|
364
|
r3 := subl @r1, 32
|
365
|
|
366
|
r4 := and @r2, 0x80000000
|
367
|
jne @r4, gost.load_key1_24
|
368
|
|
369
|
r5 := and @r3, 0x80000000
|
370
|
r6 := xor @r5, @r4
|
371
|
jne @r6, gost.load_key25_32
|
372
|
|
373
|
or @r4, @r6 ;Возможно это лишнее надо уточнить (без них на тестовом примере работает норамльно)
|
374
|
je gost.round ;Возможно это лишнее надо уточнить (без них на тестовом примере работает норамльно)
|
375
|
|
376
|
complete
|
377
|
*/
|
378
|
|
379
|
//====================================
|
380
|
|
381
|
gost.save_results:
|
382
|
|
383
|
r1 := rdl BufPtr
|
384
|
|
385
|
r2 := addl @r1, 4
|
386
|
newp := addl @r1, 8
|
387
|
|
388
|
r3 := getl #BB
|
389
|
r4 := getl #AA
|
390
|
|
391
|
wrl @r3, @r1 /* Сохраняем новые значения в буфере */
|
392
|
wrl @r4, @r2
|
393
|
|
394
|
wrl @newp, BufPtr /* Сохраняем новый указатель */
|
395
|
|
396
|
jmp gost.next_block
|
397
|
|
398
|
complete
|
399
|
|
400
|
//====================================
|
401
|
|
402
|
gost.return:
|
403
|
|
404
|
SP13 := getq #SP ; убираем наш кадр стека. Часть 1 из 3
|
405
|
|
406
|
; Восстановление старых значений индексных регистров. Часть 1 из 2
|
407
|
old7 := rdq gost_encdec.old_r7.newSP
|
408
|
old6 := rdq gost_encdec.old_r6.newSP
|
409
|
old5 := rdq gost_encdec.old_r5.newSP
|
410
|
old4 := rdq gost_encdec.old_r4.newSP
|
411
|
old3 := rdq gost_encdec.old_r3.newSP
|
412
|
old2 := rdq gost_encdec.old_r2.newSP
|
413
|
old1 := rdq gost_encdec.old_r1.newSP
|
414
|
|
415
|
NP := rdl gost_encdec.RET.newSP ; Следующий параграф. Часть 1 из 2
|
416
|
|
417
|
SP23 := addl @SP13, gost_encdec.stackb ; убираем наш кадр стека. Часть 2 из 3
|
418
|
|
419
|
; Восстановление старых значений индексных регистров. Часть 2 из 2
|
420
|
setq #SB, @old7
|
421
|
setq #IDX, @old6
|
422
|
setq #BLK, @old5
|
423
|
setq #KI, @old4
|
424
|
setq #BB, @old3
|
425
|
setq #AA, @old2
|
426
|
setq #DEC, @old1
|
427
|
|
428
|
setl #SP, @SP23 ; убираем наш кадр стека. Часть 3 из 3
|
429
|
|
430
|
jmp @NP ; Следующий параграф. Часть 2 из 2
|
431
|
|
432
|
complete
|
433
|
|
434
|
//====================================
|