.dseg
RXBnCTRL: .BYTE 13
;==== !!! МЕСТАМИ НЕ МЕНЯТЬ !!! ====
GAMMABuf: .BYTE 8
GAMMA: .BYTE 8
;-----------------------------------
.cseg
;Однократный запуск при инициализации шифрования/дешифрования
rcall GammaInit
;Применение:
rcall GOST28147_89_ECB_encrypt ;RXBnCTRL+1+4 адрес обрабатываемых 8 байт
rcall GOST28147_89_ECB_decrypt
rcall GOST28147_89_encrypt_CNTRgamma
rcall GOST28147_89_decrypt_CNTRgamma
;Код:
;=========================================================================
;GOST28147-89 режимы ECB и счетчика с гаммированием.
;Основные алгоритмы соответствуют GOST28147-89, если нужно полное соответствие GOST28147-89 то дорабатываем самостоятельно
;RXBnCTRL -некий 1+4+8=13 байтный буфер содержащий 8 байт обрабатываемых данных. +1 -нигде не используется, оставлено чтобы текст сильно не править
;GOST28147_89_ECB_encrypt -шифрование ECB. Простые подстановки.
;GOST28147_89_ECB_decrypt -дешифрование ECB. Простые подстановки.
; Если размер обрабатываемых данных не превышает 8 байт или не сильно превышает, то достаточно ECB режима
;GOST28147_89_encrypt_CNTRgamma -шифрование алгоритм счетчика с гаммированием
;GOST28147_89_decrypt_CNTRgamma -дешифрование алгоритм счетчика с гаммированием
;
;Раундовые ключи по факту и есть сам ключь шифрования. Все раундовые ключи
;берутся из ключа без каких либо преобразований. Очередность применения
;раундовых ключей задаётся в JMap согласно GOST28147-89
;Инициализацию счетчика для гаммирования можете сделать свою
;=========================================================================
//Sbox 64 байта или 128 тетрад подстановок, таблица из ГОСТ Р 34.12-2015 МАГМА
//byte pi_0[] = {12, 4, 6, 2, 10, 5, 11, 9, 14, 8, 13, 7, 0, 3, 15, 1};
//byte pi_1[] = {6, 8, 2, 3, 9, 10, 5, 12, 1, 14, 4, 7, 11, 13, 0, 15};
//byte pi_2[] = {11, 3, 5, 8, 2, 15, 10, 13, 14, 1, 7, 4, 12, 9, 6, 0};
//byte pi_3[] = {12, 8, 2, 1, 13, 4, 15, 6, 7, 0, 10, 5, 3, 14, 9, 11};
//byte pi_4[] = {7, 15, 5, 10, 8, 1, 6, 13, 0, 9, 3, 14, 11, 4, 2, 12};
//byte pi_5[] = {5, 13, 15, 6, 9, 2, 12, 10, 11, 7, 8, 1, 4, 3, 14, 0};
//byte pi_6[] = {8, 14, 2, 5, 6, 9, 1, 12, 15, 4, 11, 0, 13, 10, 3, 7};
//byte pi_7[] = {1, 7, 14, 13, 0, 5, 8, 3, 4, 15, 10, 6, 9, 12, 11, 2};
Sbox: //Тетрады подстановок объединены в байты. Строки записаны старшие по младшему адресу
.db 0x18,0x7E,0xE2,0xD5,0x06,0x59,0x81,0x3C,0x4F,0xF4,0xAB,0x60,0x9D,0xCA,0xB3,0x27
.db 0x57,0xDF,0xF5,0x6A,0x98,0x21,0xC6,0xAD,0xB0,0x79,0x83,0x1E,0x4B,0x34,0xE2,0x0C
.db 0xCB,0x83,0x25,0x18,0xD2,0x4F,0xFA,0x6D,0x7E,0x01,0xA7,0x54,0x3C,0xE9,0x96,0xB0
.db 0x6C,0x84,0x26,0x32,0x9A,0xA5,0x5B,0xC9,0x1E,0xE8,0x4D,0x77,0xB0,0xD3,0x0F,0xF1
Key: //Ключ шифрования, он же раундовые ключи для шифрования и дешифрования
.db 0xee, 0x37, 0x5a, 0x41
.db 0x7f, 0x35, 0xd6, 0xab
.db 0xc3, 0x4a, 0x3b, 0x12
.db 0x45, 0x41, 0xab, 0x5e
.db 0x58, 0xa8, 0x3b, 0xca
.db 0x48, 0xa5, 0x5a, 0x3e
.db 0x46, 0x64, 0xa4, 0x5f
.db 0x61, 0xab, 0xc4, 0xeb
/*;Адреса раундовых ключей при шифровании. Первоначальный вариант
JMapEncrypt: .db 28, 24, 20, 16, 12, 8, 4, 0
.db 0, 4, 8, 12, 16, 20, 24, 28
.db 0, 4, 8, 12, 16, 20, 24, 28
.db 0, 4, 8, 12, 16, 20, 24, 28
;Адреса раундовых ключей при дешифровании. Первоначальный вариант
JMapDecrypt: .db 28, 24, 20, 16, 12, 8, 4, 0
.db 28, 24, 20, 16, 12, 8, 4, 0
.db 28, 24, 20, 16, 12, 8, 4, 0
.db 0, 4, 8, 12, 16, 20, 24, 28*/
;Адреса раундовых ключей в Sbox при шифровании/дешифровании компактный вариант
;Старшая тетрада содержит /2 указатель на раундовый ключ к шифрованию. /2 означает деленное на 2 адреса указателя чтобы влез в тетраду
;Младшая тетрада содержит /2 указатель на раундовый ключ к дешифрованию
JMap: .db 0xEE, 0xCC, 0xAA, 0x88, 0x66, 0x44, 0x22, 0x00
.db 0x0E, 0x2C, 0x4A, 0x68, 0x86, 0xA4, 0xC2, 0xE0
.db 0x0E, 0x2C, 0x4A, 0x68, 0x86, 0xA4, 0xC2, 0xE0
.db 0x00, 0x22, 0x44, 0x66, 0x88, 0xAA, 0xCC, 0xEE
//RXBnCTRL+1+4 -содержит 8 байт входных данных
//RXBnCTRL+1+4 -после преобразования будут содержать 8 выходных байт данных на тех же местах
//tmp = RXBnCTRL+1 - RXBnCTRL+1+3
//N1 = RXBnCTRL+1+4 - RXBnCTRL+1+7
//N2 = RXBnCTRL+1+8 - RXBnCTRL+1+11
GOST28147_89_ECB_encrypt: ;RXBnCTRL+1+4 адрес шифруемых 8 байт
andi r21, 0b11111110 ;флаг шифрования
rjmp Efddrg5ed
GOST28147_89_ECB_decrypt: ;RXBnCTRL+1+4 адрес дешифруемых 8 байт
ori r21, 0b00000001 ;флаг дешифрования
Efddrg5ed:
ldi r20, 31 ;Загрузка адреса раундового ключа в JMap, тетрада выбирается флагом r21:0
NextIterD:
//tmp = N1
ldi r27, high(RXBnCTRL+1+4) ;N1
ldi r26, low(RXBnCTRL+1+4)
ldi r29, high(RXBnCTRL+1) ;tmp
ldi r28, low(RXBnCTRL+1)
ldi r16, 4
Nxopderb:
ld r17, X+
st Y+, r17
dec r16
brne Nxopderb
//N1 = N2 ^ Gost28147_mainStep(N1, workingKey[j]); // CM2
rcall Gost28147_mainStep
ldi r18, 4
Nxde5gf:
ld r16, X ;RXBnCTRL+1+4 N1
adiw r26, 4
ld r17, X ;RXBnCTRL+1+8 N2
sbiw r26, 4
eor r17, r16
st X+, r17 //N1 = N2 ^ Gost28147_mainStep(N1, workingKey[j]); // CM2
dec r18
brne Nxde5gf
//N2 = tmp
ldi r29, high(RXBnCTRL+1) ;tmp
ldi r28, low(RXBnCTRL+1)
ldi r16, 4
Nxdeksw:
ld r17, Y+
st X+, r17
dec r16
brne Nxdeksw
dec r20
brpl NextIterD ;Переход на обработку следующего раунда
//Шег не нужен. N2 = N2 ^ Gost28147_mainStep(N1, workingKey[0]); // 32 step (N1=N1)
//Результат 8 байт будет в tmp + N1 оно же 8 байт по адресу RXBnCTRL+1
//Корректировка расположения байт
ldi r27, high(RXBnCTRL+1+4+4)
ldi r26, low(RXBnCTRL+1+4+4)
ldi r16, 8
Nxfjfssef:
ld r17, -X
adiw r26, 4
st X, r17
sbiw r26, 4
dec r16
brne Nxfjfssef
ret
//Gost28147_mainStep(N1, workingKey[j]) превращается в Gost28147_mainStep(RXBnCTRL+1+4, workingKey[r20])
//tmp = RXBnCTRL+1
//N1 = RXBnCTRL+1+4
//N2 = RXBnCTRL+1+4+4
//j = JMap(r20)
Gost28147_mainStep:
//int cm = (key + n1); // CM1
//RXBnCTRL+1+4 = RXBnCTRL+1+4 + key
ldi r31, high(JMap*2) ;Таблица указателей на раундовых ключи для шифрования/дешифрования
ldi r30, low(JMap*2)
add r30, r20
adc r31, r15
lpm r16, Z ;указатель на раундовый ключ
sbrs r21, 0
swap r16 ;Выбор индексов для шифрования или дешифрования
andi r16, 0b00001111
lsl r16 ;*2 в JMap указатели уменьшенны в 2 раза, чтобы они влезали в тетраду
ldi r31, high(Key*2) ;=== N1 + rKey[r20]
ldi r30, low(Key*2)
add r30, r16
adc r31, r15
ldi r27, high(RXBnCTRL+1+4+4) ;N1:L
ldi r26, low(RXBnCTRL+1+4+4)
ldi r16, 4 ;!!! Флаг переноса здесь гарантированно сброшен
Nxsder4f:
ld r17, -X ;
lpm r18, Z+
adc r17, r18
st X, r17
dec r16
brne Nxsder4f ;--- N1 + rKey[r20]
adiw r26, 4
;операция подстановки
ldi r16, 3 ;4 обрабатываемых байта для операции подстановки
Nxhgfjhtr6:
ldi r31, high(Sbox*2)
ldi r30, low(Sbox*2)
swap r16 ;*4 настройка на строку Sbox
add r30, r16
adc r31, r15
swap r16 ;/4 возврат к исходному значению
ld r17, -X ;Чтение N1:0 из N1:0 N1:1 N1:2 N1:3
andi r17, 0b00001111
add r30, r17
adc r31, r15
lpm r18, Z
sub r30, r17 ;Индекс возвращаем обраьно
sbc r31, r15
andi r18, 0b00001111 ;r18 накопитель двух тетрад после подстановки
ld r17, X ;Снова чтение N1:0 из N1:0 N1:1 N1:2 N1:3
swap r17
andi r17, 0b00001111
add r30, r17
adc r31, r15
lpm r17, Z
andi r17, 0b11110000
or r18, r17
st X, r18
dec r16
brpl Nxhgfjhtr6
;Циклический сдвиг RXBnCTRL+1+4 на 11 влево. return om << 11 | om >>> (32-11); // 11-leftshift
ld r31, X+
ld r30, X+
ld r18, X+
ld r17, X
ldi r16, 3
Nxref5f:
clc
rol r17
rol r18
rol r30
rol r31
adc r17, r15
dec r16
brne Nxref5f
st X, r31
st -X, r17
st -X, r18
st -X, r30
ret
;Начальное значение инкриментного счетчика GAMMA взято из ключа шифрования,
;без тайного смысла для удобства, начальное сочтояние счётчика для
;формирования гаммыможете задать самостоятельно
GammaInit:
ldi r31, high(Key*2)
ldi r30, low(Key*2)
ldi r27, high(GAMMA)
ldi r26, low(GAMMA)
ldi r16, 8
Nxdfeeffgs:
lpm r17, Z+
andi r17, 0b00110010 ;Защита от переполнения + разнообразие
st X+, r17
dec r16
brne Nxdfeeffgs
ret
;Инкримент 8 байтного счетчика на 1
;!!! Переполнение счетчика и запарывание чужого байта по адресу GAMMA-1 новозможно
GammaIncr:
ldi r29, high(GAMMA+8)
ldi r28, low(GAMMA+8)
Nxdfeeffgsr:
ld r17, -Y
inc r17
st Y, r17
breq Nxdfeeffgsr
ret
;Шифрование алгоритм счётчика с гаммированием
;RXBnCTRL+1+4 адрес шифруемых / дешифруемых 8 байт
GOST28147_89_encrypt_CNTRgamma:
andi r21, 0b11111101 ;Шифрование или сброс флага дешифрования
rcall GOST28147_89_ECB_encrypt
rjmp jhfgyrfs
GOST28147_89_decrypt_CNTRgamma:
ori r21, 0b00000010 ;Установка флага дешифрования или сброс шифрования
jhfgyrfs:
rcall GammaIncr ;инкримент счетчика гаммы
;Сохраняем зашифрованные данные в буфер GAMMABuf
ldi r27, high(RXBnCTRL+1+4)
ldi r26, low(RXBnCTRL+1+4)
ldi r29, high(GAMMABuf)
ldi r28, low(GAMMABuf)
ldi r16, 8
dfjf4df:
ld r17, X+
st Y+, r17
dec r16
brne dfjf4df
;Копируем гамму в буфер шифрования
ldi r29, high(GAMMA)
ldi r28, low(GAMMA)
ldi r27, high(RXBnCTRL+1+4)
ldi r26, low(RXBnCTRL+1+4)
ldi r16, 8
hekjwder:
ld r17, Y+ ;GAMMA
st X+, r17
dec r16
brne hekjwder
rcall GOST28147_89_ECB_encrypt ;Шифруем/создаём гамму
;Накладываем гамму на зашифрованные данные
ldi r27, high(RXBnCTRL+1+4+8)
ldi r26, low(RXBnCTRL+1+4+8)
ldi r29, high(GAMMABuf+8)
ldi r28, low(GAMMABuf+8)
ldi r16, 8
dhjfsdfrq:
ld r17, -Y
ld r18, -X
eor r18, r17
st X, r18
dec r16
brne dhjfsdfrq
sbrc r21, 1 ;Если шифрование то пропуск
rcall GOST28147_89_ECB_decrypt
ret
;-----------------------------------------------------
|