; libcrash -- cryptographic hash (and other) functions
;
; Copyright (C) <2012-2014,2016,2019,2021> Ivan Baravy
;
; SPDX-License-Identifier: GPL-2.0-or-later
;
; This program is free software: you can redistribute it and/or modify it under
; the terms of the GNU General Public License as published by the Free Software
; Foundation, either version 2 of the License, or (at your option) any later
; version.
;
; This program is distributed in the hope that it will be useful, but WITHOUT
; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
; FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License along with
; this program. If not, see .
format MS COFF
public @EXPORT as 'EXPORTS'
include 'proc32.inc'
include 'struct.inc'
include 'macros.inc'
include 'kglobals.inc'
purge section,mov,add,sub
section '.flat' code readable align 16
include 'libcrash.inc'
include 'hash/crc32.asm'
include 'hash/md5.asm'
include 'hash/sha1.asm'
include 'hash/sha2_224_256.asm'
include 'hash/sha2_384_512.asm'
include 'hash/sha3.asm'
include 'mac/poly1305.asm'
include 'mac/hmac.asm'
include 'cipher/chacha20.asm'
include 'cipher/mode/ctr.asm'
include 'cipher/mode/cbc.asm'
include 'cipher/aes.asm'
include 'cipher/aes_ctr.asm'
include 'cipher/aes_cbc.asm'
LIBCRASH_BUF_SIZE = 0x1000
struct hash_item
init dd ?
update dd ?
finish dd ?
oneshot dd ?
ctx_size dd ?
out_size dd ?
ends
struct mac_item
init dd ?
update dd ?
finish dd ?
oneshot dd ?
ctx_size dd ?
out_size dd ?
ends
struct cipher_item ; FIXME merge *_item, why not
init dd ?
update dd ?
finish dd ?
oneshot dd ?
ctx_size dd ?
dd ? ; placeholder for out_size
ends
; Initialize the library.
; This must be the first called function of the library.
; Parameters:
; eax = function pointer to allocate memory:
; stdcall void *alloc(size_t size)
; ebx = function pointer to free memory:
; stdcall void free(void *ptr)
; Return value: none
proc crash.init
mov [mem.alloc], eax
mov [mem.free], ebx
ret
endp
; Hash data read by a callback read function.
; The function calls the read callback until it returns 0, and hashes the read
; data with the specified algorithm. The result is written to the specified
; buffer in binary format.
; Parameters:
; [_id] = ID of a hash function to use.
; [_clbk_read] = function pointer to read data:
; stdcall ssize_t clbk_read(void *user, void *buf, size_t size)
; [_user] = pointer to user-specified data passed to the read callback as is.
; [_out] = buffer pointer where a hash value is to be written to.
; Return value:
; binary hash value in [_out] buffer.
proc crash.hash uses ebx esi edi, _id, _clbk_read, _user, _out
locals
.ctx dd ?
.buf dd ?
endl
; alloc buf
mov eax, [io_buf_size]
add eax, LIBCRASH_MAX_PAD_LEN
stdcall [mem.alloc], eax
test eax, eax
jz .quit
mov [.buf], eax
; alloc ctx
mov eax, [_id]
imul eax, sizeof.hash_item
lea ebx, [crash._.hash_table+eax]
stdcall [mem.alloc], [ebx+hash_item.ctx_size]
test eax, eax
jz .quit_free_buf
mov [.ctx], eax
stdcall [ebx+hash_item.init], [.ctx]
.update:
stdcall [_clbk_read], [_user], [.buf], [io_buf_size]
test eax, eax
jz .finish
stdcall [ebx+hash_item.update], [.ctx], [.buf], eax
jmp .update
.finish:
stdcall [ebx+hash_item.finish], [.ctx]
mov esi, [.ctx]
mov edi, [_out]
mov ecx, [ebx+hash_item.out_size]
rep movsd
.quit_free_buf_ctx:
stdcall [mem.free], [.ctx]
.quit_free_buf:
stdcall [mem.free], [.buf]
.quit:
ret
endp
; Calculate MAC of data read by a callback read function.
; The function calls the read callback until it returns 0, and calculates a MAC
; using a specified algorithm and a key. The result is written to the specified
; buffer.
; Parameters:
; [_id] = ID of a MAC function to use.
; [_key] = key pointer, no NULL terminator is needed
; [_key_len] = length of the [_key] data, in bytes
; [_clbk_read] = function pointer to read data:
; stdcall ssize_t clbk_read(void *user, void *buf, size_t size)
; [_user] = pointer to user-specified data passed to the read callback as is.
; [_out] = buffer pointer where a MAC value is to be written to.
; Return value:
; Binary MAC value in [_out] buffer.
proc crash.mac uses ebx esi edi, _id, _key, _key_len, _clbk_read, _user, _out
locals
.ctx dd ?
.buf dd ?
endl
; alloc buf
mov eax, [io_buf_size]
add eax, LIBCRASH_MAX_PAD_LEN
stdcall [mem.alloc], eax
test eax, eax
jz .quit
mov [.buf], eax
; alloc ctx
mov eax, [_id]
imul eax, sizeof.mac_item
lea ebx, [crash._.mac_table+eax]
stdcall [mem.alloc], [ebx+mac_item.ctx_size]
test eax, eax
jz .quit_free_buf
mov [.ctx], eax
stdcall [ebx+mac_item.init], [.ctx], [_key], [_key_len]
.update:
stdcall [_clbk_read], [_user], [.buf], [io_buf_size]
test eax, eax
jz .finish
stdcall [ebx+mac_item.update], [.ctx], [.buf], eax
jmp .update
.finish:
stdcall [ebx+mac_item.finish], [.ctx]
mov esi, [.ctx]
mov edi, [_out]
mov ecx, [ebx+mac_item.out_size]
rep movsd
.quit_free_buf_ctx:
stdcall [mem.free], [.ctx]
.quit_free_buf:
stdcall [mem.free], [.buf]
.quit:
ret
endp
; Encrypt or decrypt data read by a callback read function.
; The function calls the read callback until it returns 0, and encrypts or
; decrypts the data using a specified algorithm, a key and an input vector.
; The result is passed to the write callback function.
; * The maximum difference in input/output data lengths is LIBCRASH_MAX_PAD_LEN.
; * The input and output buffers can sometimes be the same buffer depending on
; the cipher. If unsure, use different buffers.
; Parameters:
; [_id] = ID of a MAC function to use.
; [_flags] = see LIBCRASH_CIPHER_* in libcrash.inc
; [_key] = key pointer, NULL terminated
; [_iv] = input vector pointer, no NULL terminator is needed
; [_clbk_read] = function pointer to read data:
; stdcall ssize_t clbk_read(void *user, void *buf, size_t size)
; [_user_read] = pointer to user-specified data passed to the read callback.
; [_clbk_write] = function pointer to write data:
; stdcall void clbk_write(void *user, void *buf, size_t size)
; [_user_write] = pointer to user-specified data passed to the write callback.
; Return value: none
proc crash.crypt uses ebx esi edi, _id, _flags, _key, _iv, _clbk_read, \
_user_read, _clbk_write, _user_write
locals
.ctx dd ?
.buf dd ?
.buf_in dd ?
.buf_out dd ?
endl
; alloc buf
mov eax, [io_buf_size]
mov [.buf_out], eax
shl eax, 1
add eax, LIBCRASH_MAX_PAD_LEN
stdcall [mem.alloc], eax
test eax, eax
jz .quit
mov [.buf], eax
mov [.buf_in], eax
add [.buf_out], eax
; alloc ctx
mov eax, [_id]
imul eax, sizeof.cipher_item
lea ebx, [crash._.cipher_table+eax]
stdcall [mem.alloc], [ebx+cipher_item.ctx_size]
test eax, eax
jz .quit_free_buf
mov [.ctx], eax
stdcall [ebx+cipher_item.init], [.ctx], [_key], [_iv], [_flags]
.update:
stdcall [_clbk_read], [_user_read], [.buf_in], [io_buf_size]
test eax, eax
jz .finish
stdcall [ebx+cipher_item.update], [.ctx], [.buf_in], eax, [.buf_out]
stdcall [_clbk_write], [_user_write], [.buf_out], eax
jmp .update
.finish:
stdcall [ebx+cipher_item.finish], [.ctx], [.buf_out]
stdcall [_clbk_write], [_user_write], [.buf_out], eax
.quit_free_buf_ctx:
stdcall [mem.free], [.ctx]
.quit_free_buf:
stdcall [mem.free], [.buf]
.quit:
ret
endp
; These crash.*_oneshot functions below are wrappers to .oneshot,
; .oneshot and .oneshot functions. The functions pop
; [_id] argument from the stack and jump to the oneshot function of the
; corresponding algorithm with all the other arguments in place.
; You can also call .oneshot functions directly.
; Hash data in a buffer.
; The function hashes data in the specified buffer with the specified algorithm.
; The result is written to the very beginning of the specified context buffer in
; binary format.
; Parameters:
; [_id] = ID of a hash function to use.
; [_ctx] = buffer pointer for internal use, LIBCRASH_CTX_LEN bytes is enough.
; [_in] = pointer to input data
; [_len] = length of input data
; Return value:
; binary hash value in [_ctx] buffer.
crash.hash_oneshot: ; _id, _ctx, _in, _len
pop eax
xchg eax, [esp]
imul eax, sizeof.hash_item
lea eax, [crash._.hash_table+eax]
jmp [eax+hash_item.oneshot]
; Calculate MAC of data in the buffer.
; The function calculates a MAC of data in the specified buffer with the
; specified algorithm and key. The result is written to the very beginning of
; the specified context buffer in binary format.
; Parameters:
; [_id] = ID of a hash function to use.
; [_ctx] = buffer pointer for internal use, LIBCRASH_CTX_LEN bytes is enough.
; [_in] = pointer to input data
; [_len] = length of input data
; [_key] = key pointer, no NULL terminator is needed
; [_key_len] = length of the [_key] data, in bytes
; Return value:
; binary MAC value in [_ctx] buffer.
crash.mac_oneshot: ; _id, _ctx, _in, _len, _key, _key_len
pop eax
xchg eax, [esp]
imul eax, sizeof.mac_item
lea eax, [crash._.mac_table+eax]
jmp [eax+mac_item.oneshot]
; Encrypt or decrypt data in buffer.
; The function encrypts or decrypts data in the specified buffer using a
; specified algorithm, a key and an input vector. The result is written to
; another specified buffer.
; * The input and output buffers can sometimes be the same buffer depending on
; the cipher. If unsure, use different buffers.
; * The maximum difference in input/output data lengths is LIBCRASH_MAX_PAD_LEN.
; Parameters:
; [_id] = ID of a MAC function to use.
; [_ctx] = buffer pointer for internal use, LIBCRASH_CTX_LEN bytes is enough.
; [_key] = key pointer, NULL terminated
; [_iv] = input vector pointer, no NULL terminator is needed
; [_flags] = see LIBCRASH_CIPHER_* in libcrash.inc
; [_in] = pointer to input data
; [_len] = length of input data
; [_out] = pointer to output data
; Return value: none
crash.crypt_oneshot: ; _id, _ctx, _key, _iv, _flags, _in, _len, _out
pop eax
xchg eax, [esp]
imul eax, sizeof.cipher_item
lea eax, [crash._.cipher_table+eax]
jmp [eax+cipher_item.oneshot]
section '.data' writeable align 16
mem.alloc dd ?
mem.free dd ?
io_buf_size dd LIBCRASH_BUF_SIZE
; FIXME: IDs shouldn't be indexes, should they?
align 4
crash._.hash_table dd \
crc32.init, crc32.update, crc32.finish, crc32.oneshot, \
sizeof.ctx_crc32, CRC32_LEN/4, \
md5.init, md5.update, md5.finish, md5.oneshot, \
sizeof.ctx_md5, MD5_LEN/4, \
sha1.init, sha1.update, sha1.finish, sha1.oneshot, \
sizeof.ctx_sha1, SHA1_LEN/4, \
sha2_224.init, sha2_224.update, sha2_224.finish, sha2_224.oneshot, \
sizeof.ctx_sha2_224256, SHA2_224_LEN/4, \
sha2_256.init, sha2_256.update, sha2_256.finish, sha2_256.oneshot, \
sizeof.ctx_sha2_224256, SHA2_256_LEN/4, \
sha2_384.init, sha2_384.update, sha2_384.finish, sha2_384.oneshot, \
sizeof.ctx_sha2_384512, SHA2_384_LEN/4, \
sha2_512.init, sha2_512.update, sha2_512.finish, sha2_512.oneshot, \
sizeof.ctx_sha2_384512, SHA2_512_LEN/4, \
sha3_224.init, sha3.update, sha3.finish, sha3_224.oneshot, \
sizeof.ctx_sha3, SHA3_224_LEN/4, \
sha3_256.init, sha3.update, sha3.finish, sha3_256.oneshot, \
sizeof.ctx_sha3, SHA3_256_LEN/4, \
sha3_384.init, sha3.update, sha3.finish, sha3_384.oneshot, \
sizeof.ctx_sha3, SHA3_384_LEN/4, \
sha3_512.init, sha3.update, sha3.finish, sha3_512.oneshot, \
sizeof.ctx_sha3, SHA3_512_LEN/4, \
0
align 4
crash._.mac_table dd \
poly1305.init, poly1305.update, poly1305.finish, \
poly1305.oneshot, sizeof.ctx_poly1305, POLY1305_LEN/4, \
hmac_sha2_256.init, hmac_sha2_256.update, hmac_sha2_256.finish, \
hmac_sha2_256.oneshot, sizeof.ctx_hmac, HMAC_SHA2_256_LEN/4, \
hmac_sha2_512.init, hmac_sha2_512.update, hmac_sha2_512.finish, \
hmac_sha2_512.oneshot, sizeof.ctx_hmac, HMAC_SHA2_512_LEN/4, \
0
align 4
crash._.cipher_table dd \
chacha20.init, chacha20.update, chacha20.finish, chacha20.oneshot, \
sizeof.ctx_chacha20, 0, \
aes256ctr.init, aes256ctr.update, aes256ctr.finish, aes256ctr.oneshot, \
sizeof.ctx_aes_ctr, 0, \
aes256cbc.init, aes256cbc.update, aes256cbc.finish, aes256cbc.oneshot, \
sizeof.ctx_aes_cbc, 0, \
0
IncludeIGlobals
align 4
@EXPORT:
export \
crash.init, "lib_init", \
crash.hash, "crash_hash", \
crash.mac, "crash_mac", \
crash.crypt, "crash_crypt", \
crash.hash_oneshot, "crash_hash_oneshot", \
crash.mac_oneshot, "crash_mac_oneshot", \
crash.crypt_oneshot, "crash_crypt_oneshot", \
\
crc32.init, "crc32_init", \
crc32.update, "crc32_update", \
crc32.finish, "crc32_finish", \
crc32.oneshot, "crc32_oneshot", \
md5.init, "md5_init", \
md5.update, "md5_update", \
md5.finish, "md5_finish", \
md5.oneshot, "md5_oneshot", \
sha1.init, "sha1_init", \
sha1.update, "sha1_update", \
sha1.finish, "sha1_finish", \
sha1.oneshot, "sha1_oneshot", \
sha2_224.init, "sha2_224_init", \
sha2_224.update, "sha2_224_update", \
sha2_224.finish, "sha2_224_finish", \
sha2_224.oneshot, "sha2_224_oneshot", \
sha2_256.init, "sha2_256_init", \
sha2_256.update, "sha2_256_update", \
sha2_256.finish, "sha2_256_finish", \
sha2_256.oneshot, "sha2_256_oneshot", \
sha2_384.init, "sha2_384_init", \
sha2_384.update, "sha2_384_update", \
sha2_384.finish, "sha2_384_finish", \
sha2_384.oneshot, "sha2_384_oneshot", \
sha2_512.init, "sha2_512_init", \
sha2_512.update, "sha2_512_update", \
sha2_512.finish, "sha2_512_finish", \
sha2_512.oneshot, "sha2_512_oneshot", \
sha3_224.init, "sha3_224_init", \
sha3_224.update, "sha3_224_update", \
sha3_224.finish, "sha3_224_finish", \
sha3_224.oneshot, "sha3_224_oneshot", \
sha3_256.init, "sha3_256_init", \
sha3_256.update, "sha3_256_update", \
sha3_256.finish, "sha3_256_finish", \
sha3_256.oneshot, "sha3_256_oneshot", \
sha3_384.init, "sha3_384_init", \
sha3_384.update, "sha3_384_update", \
sha3_384.finish, "sha3_384_finish", \
sha3_384.oneshot, "sha3_384_oneshot", \
sha3_512.init, "sha3_512_init", \
sha3_512.update, "sha3_512_update", \
sha3_512.finish, "sha3_512_finish", \
sha3_512.oneshot, "sha3_512_oneshot", \
\
poly1305.init, "poly1305_init", \
poly1305.update, "poly1305_update", \
poly1305.finish, "poly1305_finish", \
poly1305.oneshot, "poly1305_oneshot", \
hmac_sha2_256.init, "hmac_sha2_256_init", \
hmac_sha2_256.update, "hmac_sha2_256_update", \
hmac_sha2_256.finish, "hmac_sha2_256_finish", \
hmac_sha2_256.oneshot, "hmac_sha2_256_oneshot", \
hmac_sha2_512.init, "hmac_sha2_512_init", \
hmac_sha2_512.update, "hmac_sha2_512_update", \
hmac_sha2_512.finish, "hmac_sha2_512_finish", \
hmac_sha2_512.oneshot, "hmac_sha2_512_oneshot", \
\
chacha20.init, "chacha20_init", \
chacha20.update, "chacha20_update", \
chacha20.finish, "chacha20_finish", \
chacha20.oneshot, "chacha20_oneshot", \
aes256ctr.init, "aes256ctr_init", \
aes256ctr.update, "aes256ctr_update", \
aes256ctr.finish, "aes256ctr_finish", \
aes256ctr.oneshot, "aes256ctr_oneshot", \
aes256cbc.init, "aes256cbc_init", \
aes256cbc.update, "aes256cbc_update", \
aes256cbc.finish, "aes256cbc_finish", \
aes256cbc.oneshot, "aes256cbc_oneshot"