Ivan Baravy
553742f877
* Implement new algorithms: - MACs: Poly1305, HMAC (SHA2_256, SHA2_512), - ciphers: ChaCha20, AES256CTR, AES256CBC. * Remove MD4 hash. * Change API (it happens). * Update crashtest example. git-svn-id: svn://kolibrios.org@9216 a494cfbc-eb01-0410-851d-a64ba20cac60
469 lines
17 KiB
NASM
469 lines
17 KiB
NASM
; 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 <http://www.gnu.org/licenses/>.
|
|
|
|
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 <hash_name>.oneshot,
|
|
; <mac_name>.oneshot and <cipher_name>.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 <hash_name/mac_name/cipher_name>.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"
|