Однажды мне понадобилось использовать эллиптическую криптографию в коде на ассемблере (FASM). Мой взор пал на легкую либу curve25519 с исходником на C. Нужен был чистый код, без зависимостей (а их там аж три штуки: умножение 64-битных чисел, memset и memcpy). Было решено просто рипнуть скомпилированный код (ибо делать имплементацию этого чуда на ассемблере совсем лениво), и собрать с учетом некоторых правок, что я и сделал.
main.asm (curve_lib.inc лежит в аттаче)
Результат работы:
Размер пи-кода составляет 7004 байт.
Также подчеркну интересную особенность в ходе работы: так как компиляция производится "студийным" компилятором, рипнутый код необходимо ассемблировать microsoft'ным ассемблером. Мы можем собрать и FASM'ом, но на выходе получим неожиданный результат - любая пара будет вычислять неверный shared-ключ. Вся проблема заключается в разнице генерируемых опкодов.
Вот такой камень преткновения при ассемблировании сложного кода после умного компилятора.
Скачать -
main.asm (curve_lib.inc лежит в аттаче)
Код:
format pe console
entry start
include 'win32a.inc'
section '.data' data readable writeable
priv db 'private: ', 0
publ db ' public: ', 0
shar db ' shared: ', 0
frmt db '%02X', 0
next_line db 13, 10, 0
; uint8_t basepoint[32] = {9};
basepoint db 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
private_key_1 db 0x50, 0xA9, 0xB2, 0x19, 0x0B, 0xC3, 0x71, 0x44, 0x12, 0xEB, 0x2E, 0xEB, 0x80, 0x03, 0xC3, 0x69
db 0xEC, 0x60, 0x90, 0x44, 0x57, 0x24, 0xF5, 0x0D, 0x08, 0xD3, 0x23, 0xD3, 0x18, 0x9D, 0x6D, 0xFD
private_key_2 db 0x38, 0x77, 0x55, 0xD6, 0x8C, 0xA4, 0xA0, 0x2A, 0xAB, 0x00, 0x50, 0xAE, 0x13, 0xAE, 0x2E, 0x1B
db 0x09, 0x9E, 0x34, 0x8E, 0xC6, 0x7C, 0xA4, 0xFA, 0x8A, 0x59, 0x60, 0x45, 0xEC, 0xDC, 0x21, 0x89
public_key_1 rb 32
public_key_2 rb 32
shared_key_1 rb 32
shared_key_2 rb 32
section '.text' code readable executable
; Шеллкод curve25519-donna.
include 'curve_lib.inc'
; От нас требуют:
; "...
; To generate a private key, generate 32 random bytes and:
;
; mysecret[0] &= 248;
; mysecret[31] &= 127;
; mysecret[31] |= 64;
; ..."
proc prepare_private_key, key
mov esi, [key]
and byte[esi], 248
mov al, byte[esi + 31]
and al, 127
or al, 64
mov byte[esi + 31], al
ret
endp
; Вывод значений.
proc print, szLabel, pBuffer
cinvoke printf, [szLabel]
mov esi, [pBuffer]
xor ecx, ecx
@@: movzx eax, byte[esi]
push ecx
cinvoke printf, frmt, eax
pop ecx
inc ecx
inc esi
cmp ecx, 32
jne @b
cinvoke printf, next_line
ret
endp
start:
; ---------------------------------------------------------------------------------
stdcall prepare_private_key, private_key_1
stdcall prepare_private_key, private_key_2
; ---------------------------------------------------------------------------------
stdcall curve25519_donna, public_key_1, private_key_1, basepoint
stdcall curve25519_donna, public_key_2, private_key_2, basepoint
stdcall curve25519_donna, shared_key_1, private_key_1, public_key_2
stdcall curve25519_donna, shared_key_2, private_key_2, public_key_1
; ---------------------------------------------------------------------------------
stdcall print, priv, private_key_1
stdcall print, priv, private_key_2
cinvoke printf, next_line
stdcall print, publ, public_key_1
stdcall print, publ, public_key_2
cinvoke printf, next_line
stdcall print, shar, shared_key_1
stdcall print, shar, shared_key_2
; ---------------------------------------------------------------------------------
cinvoke getchar
xor eax, eax
ret
section '.idata' import data readable writeable
library msvcrt, 'msvcrt.dll'
import msvcrt,\
printf, 'printf',\
getchar, 'getchar'
Результат работы:
private: 50A9B2190BC3714412EB2EEB8003C369EC6090445724F50D08D323D3189D6D7D
private: 387755D68CA4A02AAB0050AE13AE2E1B099E348EC67CA4FA8A596045ECDC2149
public: CB0647D9457C536DB7FB18C8044E4B8DAA9E811166C830D8B72803D4E1498E21
public: 54D0057FBC4A08B30266DFA0B6702C91960811AC7F45C95064911A73B8AAAD58
shared: 47AAB98094C63AA159F5444E0C502FBC6425D6E175749AB73C3C3C085FDAC153
shared: 47AAB98094C63AA159F5444E0C502FBC6425D6E175749AB73C3C3C085FDAC153
Размер пи-кода составляет 7004 байт.
Также подчеркну интересную особенность в ходе работы: так как компиляция производится "студийным" компилятором, рипнутый код необходимо ассемблировать microsoft'ным ассемблером. Мы можем собрать и FASM'ом, но на выходе получим неожиданный результат - любая пара будет вычислять неверный shared-ключ. Вся проблема заключается в разнице генерируемых опкодов.
Вот такой камень преткновения при ассемблировании сложного кода после умного компилятора.
Скачать -