Working encryption and HMAC for transport, use libcrash for sha256 (and more to come), placed connection variables in separate struct, fixed bug in aes256_cbc_decode where IV was wrong when in- and output buffer were the same.

git-svn-id: svn://kolibrios.org@6469 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
hidnplayr 2016-08-10 16:20:49 +00:00
parent 1048443a57
commit a70850fad6
8 changed files with 934 additions and 517 deletions

View File

@ -16,7 +16,7 @@
; along with this program. If not, see <http://www.gnu.org/licenses/>. ; along with this program. If not, see <http://www.gnu.org/licenses/>.
struct aes256_cbc_context aes256_context struct aes256_cbc_context aes256_context
vector rb 16 vector rb AES256_BLOCKSIZE
ends ends
@ -25,10 +25,10 @@ proc aes256_cbc_init _vector
mcall 68, 12, sizeof.aes256_cbc_context mcall 68, 12, sizeof.aes256_cbc_context
; handle errors ; handle errors
mov ecx, 16/4 mov ecx, AES256_BLOCKSIZE/4
mov esi, [_vector] mov esi, [_vector]
lea edi, [eax + aes256_cbc_context.vector] lea edi, [eax + aes256_cbc_context.vector]
rep movsd rep movsd
; rep movsd is slow, but we don't care while init ; rep movsd is slow, but we don't care while init
pop edi esi ebx pop edi esi ebx
@ -39,24 +39,16 @@ proc aes256_cbc_encrypt _ctx, _in, _out
push ebx esi edi push ebx esi edi
DEBUGF 1,'plain : ' DEBUGF 1,'plain : '
stdcall dump_128bit_hex, [_in] stdcall dump_hex, [_in], 4
DEBUGF 1,'\n'
mov edi, [_ctx] mov edi, [_ctx]
lea edi, [edi + aes256_cbc_context.vector] lea edi, [edi + aes256_cbc_context.vector]
mov esi, [_in] mov esi, [_in]
repeat AES256_BLOCKSIZE/4
lodsd lodsd
xor eax, [edi] xor eax, [edi]
stosd stosd
lodsd end repeat
xor eax, [edi]
stosd
lodsd
xor eax, [edi]
stosd
lodsd
xor eax, [edi]
stosd
mov esi, [_ctx] mov esi, [_ctx]
lea eax, [esi + aes256_cbc_context.key] lea eax, [esi + aes256_cbc_context.key]
@ -66,25 +58,33 @@ proc aes256_cbc_encrypt _ctx, _in, _out
mov esi, [_out] mov esi, [_out]
mov eax, [_ctx] mov eax, [_ctx]
lea edi, [eax + aes256_cbc_context.vector] lea edi, [eax + aes256_cbc_context.vector]
repeat AES256_BLOCKSIZE/4
movsd movsd
movsd end repeat
movsd
movsd
DEBUGF 1,'cipher : ' DEBUGF 1,'cipher : '
stdcall dump_128bit_hex, [_out] stdcall dump_hex, [_out], 4
DEBUGF 1,'\n\n'
pop edi esi ebx pop edi esi ebx
ret ret
endp endp
proc aes256_cbc_decrypt _ctx, _in, _out proc aes256_cbc_decrypt _ctx, _in, _out
locals
temp_iv rb AES256_BLOCKSIZE
endl
push ebx esi edi push ebx esi edi
DEBUGF 1,'cipher : ' DEBUGF 1,'cipher : '
stdcall dump_128bit_hex, [_in] stdcall dump_hex, [_in], 4
DEBUGF 1,'\n'
mov esi, [_in]
lea edi, [temp_iv]
repeat AES256_BLOCKSIZE/4
movsd
end repeat
mov esi, [_ctx] mov esi, [_ctx]
lea eax, [esi + aes256_cbc_context.key] lea eax, [esi + aes256_cbc_context.key]
@ -93,30 +93,21 @@ proc aes256_cbc_decrypt _ctx, _in, _out
mov esi, [_ctx] mov esi, [_ctx]
lea esi, [esi + aes256_cbc_context.vector] lea esi, [esi + aes256_cbc_context.vector]
mov edi, [_out] mov edi, [_out]
repeat AES256_BLOCKSIZE/4
lodsd lodsd
xor eax, [edi] xor eax, [edi]
stosd stosd
lodsd end repeat
xor eax, [edi]
stosd
lodsd
xor eax, [edi]
stosd
lodsd
xor eax, [edi]
stosd
mov esi, [_in] lea esi, [temp_iv]
mov edi, [_ctx] mov edi, [_ctx]
lea edi, [edi + aes256_cbc_context.vector] lea edi, [edi + aes256_cbc_context.vector]
repeat AES256_BLOCKSIZE/4
movsd movsd
movsd end repeat
movsd
movsd
DEBUGF 1,'plain : ' DEBUGF 1,'plain : '
stdcall dump_128bit_hex, [_out] stdcall dump_hex, [_out], 4
DEBUGF 1,'\n\n'
pop edi esi ebx pop edi esi ebx
ret ret

View File

@ -16,8 +16,8 @@
; along with this program. If not, see <http://www.gnu.org/licenses/>. ; along with this program. If not, see <http://www.gnu.org/licenses/>.
struct aes256_ctr_context aes256_context struct aes256_ctr_context aes256_context
counter rb 16 counter rb AES256_BLOCKSIZE
output rb 16 ; counter after aes_crypt output rb AES256_BLOCKSIZE ; counter after aes_crypt
ends ends
@ -26,10 +26,10 @@ proc aes256_ctr_init _counter
mcall 68, 12, sizeof.aes256_ctr_context mcall 68, 12, sizeof.aes256_ctr_context
; handle errors ; handle errors
mov ecx, 16/4 mov ecx, AES256_BLOCKSIZE/4
mov esi, [_counter] mov esi, [_counter]
lea edi, [eax + aes256_ctr_context.counter] lea edi, [eax + aes256_ctr_context.counter]
rep movsd rep movsd
; rep movsd is slow, but we don't care while init ; rep movsd is slow, but we don't care while init
pop edi esi ebx pop edi esi ebx
@ -42,8 +42,7 @@ proc aes256_ctr_crypt _ctx, _in, _out
push ebx esi edi push ebx esi edi
DEBUGF 1,'plain : ' DEBUGF 1,'plain : '
stdcall dump_128bit_hex, [_in] stdcall dump_hex, [_in], 4
DEBUGF 1,'\n'
mov esi, [_ctx] mov esi, [_ctx]
lea eax, [esi + aes256_ctr_context.key] lea eax, [esi + aes256_ctr_context.key]
@ -101,8 +100,7 @@ proc aes256_ctr_crypt _ctx, _in, _out
mov dword[esi + aes256_ctr_context.counter + 4*3], edx mov dword[esi + aes256_ctr_context.counter + 4*3], edx
DEBUGF 1,'cipher : ' DEBUGF 1,'cipher : '
stdcall dump_128bit_hex, [_out] stdcall dump_hex, [_out], 4
DEBUGF 1,'\n\n'
pop edi esi ebx pop edi esi ebx
ret ret

View File

@ -16,26 +16,13 @@
; You should have received a copy of the GNU General Public License ; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>. ; along with this program. If not, see <http://www.gnu.org/licenses/>.
AES256_ROUNDS = 14 AES256_ROUNDS = 14
AES256_BLOCKSIZE = 16
struct aes256_context struct aes256_context
key rd 4*(AES256_ROUNDS+1) key rd 4*(AES256_ROUNDS+1)
ends ends
proc dump_128bit_hex _ptr
pushad
mov esi, [_ptr]
mov ecx, 4
.next_dword:
lodsd
bswap eax
DEBUGF 1,'%x',eax
loop .next_dword
popad
ret
endp
proc aes256_set_encrypt_key _ctx, _userkey proc aes256_set_encrypt_key _ctx, _userkey
locals locals
@ -48,30 +35,11 @@ endl
mov esi, [_userkey] mov esi, [_userkey]
lea edi, [ebx + aes256_context.key] lea edi, [ebx + aes256_context.key]
repeat 8
lodsd lodsd
bswap eax bswap eax
stosd stosd
lodsd end repeat
bswap eax
stosd
lodsd
bswap eax
stosd
lodsd
bswap eax
stosd
lodsd
bswap eax
stosd
lodsd
bswap eax
stosd
lodsd
bswap eax
stosd
lodsd
bswap eax
stosd
lea esi, [ebx + aes256_context.key] lea esi, [ebx + aes256_context.key]
@ -176,7 +144,6 @@ endl
jmp .while jmp .while
.done: .done:
DEBUGF 1,' \n'
pop edi esi ebx pop edi esi ebx
ret ret
endp endp
@ -266,8 +233,7 @@ endl
push ebx esi edi push ebx esi edi
DEBUGF 1,'input : ' DEBUGF 1,'input : '
stdcall dump_128bit_hex, [_in] stdcall dump_hex, [_in], 4
DEBUGF 1,'\n'
mov ebx, [_key] mov ebx, [_key]
mov esi, [_in] mov esi, [_in]
@ -663,8 +629,7 @@ endl
stosd stosd
DEBUGF 1,'output : ' DEBUGF 1,'output : '
stdcall dump_128bit_hex, [_out] stdcall dump_hex, [_out], 4
DEBUGF 1,'\n'
pop edi esi ebx pop edi esi ebx
ret ret
@ -679,8 +644,7 @@ endl
push ebx esi edi push ebx esi edi
DEBUGF 1,'input : ' DEBUGF 1,'input : '
stdcall dump_128bit_hex, [_in] stdcall dump_hex, [_in], 4
DEBUGF 1,'\n'
mov ebx, [_key] mov ebx, [_key]
mov esi, [_in] mov esi, [_in]
@ -1073,8 +1037,7 @@ endl
stosd stosd
DEBUGF 1,'output : ' DEBUGF 1,'output : '
stdcall dump_128bit_hex, [_out] stdcall dump_hex, [_out], 4
DEBUGF 1,'\n'
pop edi esi ebx pop edi esi ebx
ret ret

View File

@ -25,39 +25,39 @@ proc dh_gex
;---------------------------------------------- ;----------------------------------------------
; >> Send Diffie-Hellman Group Exchange Request ; >> Send Diffie-Hellman Group Exchange Request
DEBUGF 1, "Sending GEX\n" DEBUGF 2, "Sending GEX\n"
stdcall ssh_send_packet, [socketnum], ssh_gex_req, ssh_gex_req.length, 0 stdcall ssh_send_packet, con, ssh_gex_req, ssh_gex_req.length, 0
cmp eax, -1 cmp eax, -1
je .socket_err je .socket_err
;--------------------------------------------- ;---------------------------------------------
; << Parse Diffie-Hellman Group Exchange Group ; << Parse Diffie-Hellman Group Exchange Group
stdcall ssh_recv_packet, [socketnum], rx_buffer, BUFFERSIZE, 0 stdcall ssh_recv_packet, con, 0
cmp eax, -1 cmp eax, -1
je .socket_err je .socket_err
cmp [rx_buffer+ssh_header.message_code], SSH_MSG_KEX_DH_GEX_GROUP cmp [con.rx_buffer.message_code], SSH_MSG_KEX_DH_GEX_GROUP
jne proto_err jne proto_err
DEBUGF 1, "Received GEX group\n" DEBUGF 2, "Received GEX group\n"
mov esi, rx_buffer+sizeof.ssh_header mov esi, con.rx_buffer+sizeof.ssh_packet_header
mov edi, dh_p mov edi, con.dh_p
DEBUGF 1, "DH modulus (p): " DEBUGF 1, "DH modulus (p): "
call mpint_to_little_endian call mpint_to_little_endian
stdcall mpint_print, dh_p stdcall mpint_print, con.dh_p
DEBUGF 1, "DH base (g): " DEBUGF 1, "DH base (g): "
mov edi, dh_g mov edi, con.dh_g
call mpint_to_little_endian call mpint_to_little_endian
stdcall mpint_print, dh_g stdcall mpint_print, con.dh_g
;------------------------------------------- ;-------------------------------------------
; >> Send Diffie-Hellman Group Exchange Init ; >> Send Diffie-Hellman Group Exchange Init
; generate a random number x, where 1 < x < (p-1)/2 ; generate a random number x, where 1 < x < (p-1)/2
mov edi, dh_x+4 mov edi, con.dh_x+4
mov [dh_x], DH_PRIVATE_KEY_SIZE/8 mov [con.dh_x], DH_PRIVATE_KEY_SIZE/8
mov ecx, DH_PRIVATE_KEY_SIZE/8/4 mov ecx, DH_PRIVATE_KEY_SIZE/8/4
@@: @@:
push ecx push ecx
@ -71,352 +71,300 @@ proc dh_gex
shl eax, 1 shl eax, 1
jnc @f jnc @f
mov byte[edi], 0 mov byte[edi], 0
inc dword[dh_x] inc dword[con.dh_x]
@@: @@:
; Fill remaining bytes with zeros ; TO BE REMOVED ? ; Fill remaining bytes with zeros ; TO BE REMOVED ?
if ((MAX_BITS-DH_PRIVATE_KEY_SIZE) > 0) if ((MAX_BITS-DH_PRIVATE_KEY_SIZE) > 0)
mov ecx, (MAX_BITS-DH_PRIVATE_KEY_SIZE)/8/4 mov ecx, (MAX_BITS-DH_PRIVATE_KEY_SIZE)/8/4
xor eax, eax xor eax, eax
rep stosd rep stosd
end if end if
DEBUGF 1, "DH x: " DEBUGF 1, "DH x: "
stdcall mpint_length, dh_x;;;;;;;;;;;;; stdcall mpint_length, con.dh_x;;;;;;;;;;;;;
stdcall mpint_print, dh_x stdcall mpint_print, con.dh_x
; Compute e = g^x mod p ; Compute e = g^x mod p
stdcall mpint_modexp, dh_e, dh_g, dh_x, dh_p stdcall mpint_modexp, con.dh_e, con.dh_g, con.dh_x, con.dh_p
stdcall mpint_length, dh_e stdcall mpint_length, con.dh_e
DEBUGF 1, "DH e: " DEBUGF 1, "DH e: "
stdcall mpint_print, dh_e stdcall mpint_print, con.dh_e
; Create group exchange init packet ; Create group exchange init packet
mov edi, tx_buffer+ssh_header.message_code mov edi, con.tx_buffer.message_code
mov al, SSH_MSG_KEX_DH_GEX_INIT mov al, SSH_MSG_KEX_DH_GEX_INIT
stosb stosb
mov esi, dh_e mov esi, con.dh_e
call mpint_to_big_endian call mpint_to_big_endian
DEBUGF 1, "Sending GEX init\n" DEBUGF 2, "Sending GEX init\n"
mov ecx, dword[tx_buffer+ssh_header.message_code+1] mov ecx, dword[con.tx_buffer.message_code+1]
bswap ecx bswap ecx
add ecx, 5 add ecx, 5
stdcall ssh_send_packet, [socketnum], tx_buffer+ssh_header.message_code, ecx, 0 stdcall ssh_send_packet, con, con.tx_buffer.message_code, ecx, 0
cmp eax, -1 cmp eax, -1
je .socket_err je .socket_err
;--------------------------------------------- ;---------------------------------------------
; << Parse Diffie-Hellman Group Exchange Reply ; << Parse Diffie-Hellman Group Exchange Reply
stdcall ssh_recv_packet, [socketnum], rx_buffer, BUFFERSIZE, 0 stdcall ssh_recv_packet, con, 0
cmp eax, -1 cmp eax, -1
je .socket_err je .socket_err
cmp [rx_buffer+ssh_header.message_code], SSH_MSG_KEX_DH_GEX_REPLY cmp [con.rx_buffer.message_code], SSH_MSG_KEX_DH_GEX_REPLY
jne .proto_err jne .proto_err
DEBUGF 1, "Received GEX Reply\n" DEBUGF 2, "Received GEX Reply\n"
;-------------------------------- ;--------------------------------
; HASH: string K_S, the host key ; HASH: string K_S, the host key
mov esi, rx_buffer+sizeof.ssh_header mov esi, con.rx_buffer+sizeof.ssh_packet_header
mov edx, [esi] mov edx, [esi]
bswap edx bswap edx
add edx, 4 add edx, 4
lea ebx, [esi+edx] lea ebx, [esi+edx]
push ebx push ebx
call sha256_update invoke sha256_update, con.temp_ctx, esi, edx
;-------------------------------------------------------------------------- ;--------------------------------------------------------------------------
; HASH: uint32 min, minimal size in bits of an acceptable group ; HASH: uint32 min, minimal size in bits of an acceptable group
; uint32 n, preferred size in bits of the group the server will send ; uint32 n, preferred size in bits of the group the server will send
; uint32 max, maximal size in bits of an acceptable group ; uint32 max, maximal size in bits of an acceptable group
mov esi, ssh_gex_req+sizeof.ssh_header-ssh_header.message_code invoke sha256_update, con.temp_ctx, ssh_gex_req+sizeof.ssh_packet_header-ssh_packet_header.message_code, 12
mov edx, 12
call sha256_update
;---------------------------- ;----------------------------
; HASH: mpint p, safe prime ; HASH: mpint p, safe prime
mov esi, dh_p mov esi, con.dh_p
mov edi, mpint_tmp mov edi, mpint_tmp
call mpint_to_big_endian call mpint_to_big_endian
lea edx, [eax+4] lea edx, [eax+4]
mov esi, mpint_tmp invoke sha256_update, con.temp_ctx, mpint_tmp, edx
call sha256_update
;---------------------------------------- ;----------------------------------------
; HASH: mpint g, generator for subgroup ; HASH: mpint g, generator for subgroup
mov esi, dh_g mov esi, con.dh_g
mov edi, mpint_tmp mov edi, mpint_tmp
call mpint_to_big_endian call mpint_to_big_endian
lea edx, [eax+4] lea edx, [eax+4]
mov esi, mpint_tmp invoke sha256_update, con.temp_ctx, mpint_tmp, edx
call sha256_update
;--------------------------------------------------- ;---------------------------------------------------
; HASH: mpint e, exchange value sent by the client ; HASH: mpint e, exchange value sent by the client
mov esi, tx_buffer+sizeof.ssh_header mov esi, con.tx_buffer+sizeof.ssh_packet_header
mov edx, [esi] mov edx, [esi]
bswap edx bswap edx
add edx, 4 add edx, 4
call sha256_update invoke sha256_update, con.temp_ctx, esi, edx
;--------------------------------------------------- ;---------------------------------------------------
; HASH: mpint f, exchange value sent by the server ; HASH: mpint f, exchange value sent by the server
mov esi, [esp] mov esi, [esp]
mov edx, [esi] mov edx, [esi]
bswap edx bswap edx
add edx, 4 add edx, 4
call sha256_update invoke sha256_update, con.temp_ctx, esi, edx
pop esi pop esi
mov edi, dh_f mov edi, con.dh_f
call mpint_to_little_endian call mpint_to_little_endian
DEBUGF 1, "DH f: " DEBUGF 1, "DH f: "
stdcall mpint_print, dh_f stdcall mpint_print, con.dh_f
mov edi, dh_signature mov edi, con.dh_signature
call mpint_to_little_endian call mpint_to_little_endian
DEBUGF 1, "DH signature: " DEBUGF 1, "DH signature: "
stdcall mpint_print, dh_signature stdcall mpint_print, con.dh_signature
;-------------------------------------- ;--------------------------------------
; Calculate shared secret K = f^x mod p ; Calculate shared secret K = f^x mod p
stdcall mpint_modexp, rx_buffer, dh_f, dh_x, dh_p stdcall mpint_modexp, con.rx_buffer, con.dh_f, con.dh_x, con.dh_p
stdcall mpint_length, rx_buffer stdcall mpint_length, con.rx_buffer
DEBUGF 1, "DH K: " DEBUGF 1, "DH K: "
stdcall mpint_print, rx_buffer stdcall mpint_print, con.rx_buffer
; We always need it in big endian order, so store it as such. ; We always need it in big endian order, so store it as such.
mov edi, dh_K mov edi, con.dh_K
mov esi, rx_buffer mov esi, con.rx_buffer
call mpint_to_big_endian call mpint_to_big_endian
mov [dh_K.length], eax mov [con.dh_K_length], eax
;----------------------------------- ;-----------------------------------
; HASH: mpint K, the shared secret ; HASH: mpint K, the shared secret
mov edx, [dh_K.length] mov edx, [con.dh_K_length]
add edx, 4 add edx, 4
mov esi, dh_K invoke sha256_update, con.temp_ctx, con.dh_K, edx
call sha256_update
;------------------------------- ;-------------------------------
; Finalize the exchange hash (H) ; Finalize the exchange hash (H)
mov edi, dh_H invoke sha256_final, con.temp_ctx
call sha256_final mov esi, con.temp_ctx.hash
mov edi, con.dh_H
mov ecx, SHA256_HASH_SIZE/4
rep movsd
DEBUGF 1, "Exchange hash H: " DEBUGF 1, "Exchange hash H: "
stdcall dump_256bit_hex, dh_H stdcall dump_hex, con.dh_H, 8
; TODO: skip this block when re-keying ; TODO: skip this block when re-keying
mov esi, dh_H mov esi, con.dh_H
mov edi, session_id mov edi, con.session_id
mov ecx, 32/4 mov ecx, SHA256_HASH_SIZE/4
rep movsd rep movsd
;--------------- ;---------------
; Calculate keys ; Calculate keys
; TODO: re-use partial hash of K and H ; First, calculate partial hash of K and H so we can re-use it for every key.
invoke sha256_init, con.k_h_ctx
mov edx, [con.dh_K_length]
add edx, 4
invoke sha256_update, con.k_h_ctx, con.dh_K, edx
invoke sha256_update, con.k_h_ctx, con.dh_H, 32
;--------------------------------------------------------------- ;---------------------------------------------------------------
; Initial IV client to server: HASH(K || H || "A" || session_id) ; Initial IV client to server: HASH(K || H || "A" || session_id)
call sha256_init mov esi, con.k_h_ctx
mov edx, [dh_K.length] mov edi, con.temp_ctx
add edx, 4 mov ecx, sizeof.ctx_sha224256/4
mov esi, dh_K rep movsd
call sha256_update mov [con.session_id_prefix], 'A'
mov edx, 32 invoke sha256_update, con.temp_ctx, con.session_id_prefix, 32+1
mov esi, dh_H invoke sha256_final, con.temp_ctx.hash
call sha256_update mov edi, con.tx_iv
mov edx, 1 mov esi, con.temp_ctx
mov esi, str_A mov ecx, SHA256_HASH_SIZE/4
call sha256_update rep movsd
mov edx, 32
mov esi, session_id
call sha256_update
mov edi, tx_iv
call sha256_final
DEBUGF 1, "Remote IV: " DEBUGF 1, "Remote IV: "
stdcall dump_256bit_hex, tx_iv stdcall dump_hex, con.tx_iv, 8
;--------------------------------------------------------------- ;---------------------------------------------------------------
; Initial IV server to client: HASH(K || H || "B" || session_id) ; Initial IV server to client: HASH(K || H || "B" || session_id)
call sha256_init mov esi, con.k_h_ctx
mov edx, [dh_K.length] mov edi, con.temp_ctx
add edx, 4 mov ecx, sizeof.ctx_sha224256/4
mov esi, dh_K rep movsd
call sha256_update inc [con.session_id_prefix]
mov edx, 32 invoke sha256_update, con.temp_ctx, con.session_id_prefix, 32+1
mov esi, dh_H invoke sha256_final, con.temp_ctx
call sha256_update mov edi, con.rx_iv
mov edx, 1 mov esi, con.temp_ctx
mov esi, str_B mov ecx, SHA256_HASH_SIZE/4
call sha256_update rep movsd
mov edx, 32
mov esi, session_id
call sha256_update
mov edi, rx_iv
call sha256_final
DEBUGF 1, "Local IV: " DEBUGF 1, "Local IV: "
stdcall dump_256bit_hex, rx_iv stdcall dump_hex, con.rx_iv, 8
;------------------------------------------------------------------- ;-------------------------------------------------------------------
; Encryption key client to server: HASH(K || H || "C" || session_id) ; Encryption key client to server: HASH(K || H || "C" || session_id)
call sha256_init mov esi, con.k_h_ctx
mov edx, [dh_K.length] mov edi, con.temp_ctx
add edx, 4 mov ecx, sizeof.ctx_sha224256/4
mov esi, dh_K rep movsd
call sha256_update inc [con.session_id_prefix]
mov edx, 32 invoke sha256_update, con.temp_ctx, con.session_id_prefix, 32+1
mov esi, dh_H invoke sha256_final, con.temp_ctx
call sha256_update mov edi, con.tx_enc_key
mov edx, 1 mov esi, con.temp_ctx
mov esi, str_C mov ecx, SHA256_HASH_SIZE/4
call sha256_update rep movsd
mov edx, 32
mov esi, session_id
call sha256_update
mov edi, tx_enc_key
call sha256_final
DEBUGF 1, "Remote key: " DEBUGF 1, "Remote key: "
stdcall dump_256bit_hex, tx_enc_key stdcall dump_hex, con.tx_enc_key, 8
;------------------------------------------------------------------- ;-------------------------------------------------------------------
; Encryption key server to client: HASH(K || H || "D" || session_id) ; Encryption key server to client: HASH(K || H || "D" || session_id)
call sha256_init mov esi, con.k_h_ctx
mov edx, [dh_K.length] mov edi, con.temp_ctx
add edx, 4 mov ecx, sizeof.ctx_sha224256/4
mov esi, dh_K rep movsd
call sha256_update inc [con.session_id_prefix]
mov edx, 32 invoke sha256_update, con.temp_ctx, con.session_id_prefix, 32+1
mov esi, dh_H invoke sha256_final, con.temp_ctx
call sha256_update mov edi, con.rx_enc_key
mov edx, 1 mov esi, con.temp_ctx
mov esi, str_D mov ecx, SHA256_HASH_SIZE/4
call sha256_update rep movsd
mov edx, 32
mov esi, session_id
call sha256_update
mov edi, rx_enc_key
call sha256_final
DEBUGF 1, "Local key: " DEBUGF 1, "Local key: "
stdcall dump_256bit_hex, rx_enc_key stdcall dump_hex, con.rx_enc_key, 8
;------------------------------------------------------------------ ;------------------------------------------------------------------
; Integrity key client to server: HASH(K || H || "E" || session_id) ; Integrity key client to server: HASH(K || H || "E" || session_id)
call sha256_init mov esi, con.k_h_ctx
mov edx, [dh_K.length] mov edi, con.temp_ctx
add edx, 4 mov ecx, sizeof.ctx_sha224256/4
mov esi, dh_K rep movsd
call sha256_update inc [con.session_id_prefix]
mov edx, 32 invoke sha256_update, con.temp_ctx, con.session_id_prefix, 32+1
mov esi, dh_H invoke sha256_final, con.temp_ctx
call sha256_update mov edi, con.tx_int_key
mov edx, 1 mov esi, con.temp_ctx
mov esi, str_E mov ecx, SHA256_HASH_SIZE/4
call sha256_update rep movsd
mov edx, 32
mov esi, session_id
call sha256_update
mov edi, tx_int_key
call sha256_final
DEBUGF 1, "Remote Integrity key: " DEBUGF 1, "Remote Integrity key: "
stdcall dump_256bit_hex, tx_int_key stdcall dump_hex, con.tx_int_key, 8
;------------------------------------------------------------------ ;------------------------------------------------------------------
; Integrity key server to client: HASH(K || H || "F" || session_id) ; Integrity key server to client: HASH(K || H || "F" || session_id)
call sha256_init mov esi, con.k_h_ctx
mov edx, [dh_K.length] mov edi, con.temp_ctx
add edx, 4 mov ecx, sizeof.ctx_sha224256/4
mov esi, dh_K rep movsd
call sha256_update inc [con.session_id_prefix]
mov edx, 32 invoke sha256_update, con.temp_ctx, con.session_id_prefix, 32+1
mov esi, dh_H invoke sha256_final, con.temp_ctx
call sha256_update mov edi, con.rx_int_key
mov edx, 1 mov esi, con.temp_ctx
mov esi, str_F mov ecx, SHA256_HASH_SIZE/4
call sha256_update rep movsd
mov edx, 32
mov esi, session_id
call sha256_update
mov edi, rx_int_key
call sha256_final
DEBUGF 1, "Local Integrity key: " DEBUGF 1, "Local Integrity key: "
stdcall dump_256bit_hex, rx_int_key stdcall dump_hex, con.rx_int_key, 8
;------------------------------------- ;-------------------------------------
; << Parse Diffie-Hellman New Keys MSG ; << Parse Diffie-Hellman New Keys MSG
stdcall ssh_recv_packet, [socketnum], rx_buffer, BUFFERSIZE, 0 stdcall ssh_recv_packet, con, 0
cmp eax, -1 cmp eax, -1
je .socket_err je .socket_err
cmp [rx_buffer+ssh_header.message_code], SSH_MSG_NEWKEYS cmp [con.rx_buffer.message_code], SSH_MSG_NEWKEYS
jne .proto_err jne .proto_err
DEBUGF 1, "Received New Keys\n" DEBUGF 2, "Received New Keys\n"
;------------------------------- ;-------------------------------
; >> Reply with New Keys message ; >> Reply with New Keys message
stdcall ssh_send_packet, [socketnum], ssh_new_keys, ssh_new_keys.length, 0 stdcall ssh_send_packet, con, ssh_new_keys, ssh_new_keys.length, 0
xor eax, eax xor eax, eax
ret ret
.socket_err: .socket_err:
DEBUGF 2, "Socket error during key exchange!\n" DEBUGF 3, "Socket error during key exchange!\n"
mov eax, 1 mov eax, 1
ret ret
.proto_err: .proto_err:
DEBUGF 2, "Protocol error during key exchange!\n" DEBUGF 3, "Protocol error during key exchange!\n"
mov eax, 2 mov eax, 2
ret ret
endp endp
proc dump_256bit_hex _ptr
pushad
mov esi, [_ptr]
mov ecx, 8
.next_dword:
lodsd
bswap eax
DEBUGF 1,'%x',eax
loop .next_dword
DEBUGF 1,'\n'
popad
ret
endp
iglobal
str_A db 'A'
str_B db 'B'
str_C db 'C'
str_D db 'D'
str_E db 'E'
str_F db 'F'
endg

View File

@ -0,0 +1,171 @@
; hmac.inc - HMAC: Keyed-Hashing for Message Authentication
;
; Copyright (C) 2016 Denis Karpenko
; Copyright (C) 2016 Jeffrey Amelynck
;
; 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 3 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/>.
; Main concept:
; To compute HMAC over the data `text' we perform
; H(K XOR opad, H(K XOR ipad, text))
struct hmac_sha256_context
hash rb SHA256_HASH_SIZE
ipad_ctx ctx_sha224256
opad_ctx ctx_sha224256
ends
; We will precompute partial hashes of K XOR ipad and K XOR opad,
; and store them in the context structure.
proc hmac_sha256_setkey ctx, key, key_length
locals
k_temp rb SHA224256_BLOCK_SIZE
endl
pusha
; input esi = key, ecx=key_length
mov ecx, [key_length]
cmp ecx, SHA224256_BLOCK_SIZE
ja .hash_it
; Key is smaller then or equal to blocksize,
; copy key to ipad
mov esi, [key]
lea edi, [k_temp]
rep movsb
mov ecx, SHA224256_BLOCK_SIZE
sub ecx, [key_length]
jz .finish
; append zeros to the key
xor al, al
rep stosb
jmp .finish
; Given key is larger then key size, hash it
.hash_it:
invoke sha256_init, [ctx]
invoke sha256_update, [ctx], [key], [key_length]
invoke sha256_final, [ctx]
mov esi, [ctx]
lea edi, [k_temp]
mov ecx, SHA256_HASH_SIZE/4
rep movsd
xor eax, eax
mov ecx, (SHA224256_BLOCK_SIZE-SHA256_HASH_SIZE)/4
rep stosd
.finish:
; xor ipad buffer with 0x36363...
lea esi, [k_temp]
mov ecx, SHA224256_BLOCK_SIZE/4
@@:
xor dword[esi], 0x36363636 ; ipad constant
add esi, 4
dec ecx
jnz @r
; Init our hash with k_xor_ipad
mov ebx, [ctx]
lea edi, [ebx+hmac_sha256_context.ipad_ctx]
invoke sha256_init, edi
lea esi, [k_temp]
DEBUGF 1, "HASH: "
stdcall dump_hex, esi, SHA224256_BLOCK_SIZE/4
mov ebx, [ctx]
lea edi, [ebx+hmac_sha256_context.ipad_ctx]
invoke sha256_update, edi, esi, SHA224256_BLOCK_SIZE
; xor opad buffer with 0x5c5c5...
lea esi, [k_temp]
mov ecx, SHA224256_BLOCK_SIZE/4
@@:
xor dword[esi], 0x36363636 xor 0x5c5c5c5c ; opad constant
add esi, 4
dec ecx
jnz @r
; Init our hash with k_xor_opad
mov ebx, [ctx]
lea edi, [ebx+hmac_sha256_context.opad_ctx]
invoke sha256_init, edi
lea esi, [k_temp]
DEBUGF 1, "HASH: "
stdcall dump_hex, esi, SHA224256_BLOCK_SIZE/4
mov ebx, [ctx]
lea edi, [ebx+hmac_sha256_context.opad_ctx]
invoke sha256_update, edi, esi, SHA224256_BLOCK_SIZE
popa
ret
endp
; Copy our pre-computed partial hashes to the stack, complete and finalize them.
; TODO: prevent unnescessary copying of output hash
; TODO: remove unnescessary pushing/popping
proc hmac_sha256 ctx, _data, _length
locals
inner_ctx ctx_sha224256
outer_ctx ctx_sha224256
endl
pusha
DEBUGF 1, "HMAC: "
mov ebx, [_length]
shr ebx, 2
stdcall dump_hex, [_data], ebx
; Copy partial hashes of ipad and opad to our temporary buffers
mov esi, [ctx]
lea esi, [esi+hmac_sha256_context.ipad_ctx]
lea edi, [inner_ctx]
repeat (sizeof.ctx_sha224256)/4*2
movsd
end repeat
; Append provided data to inner hash and finalize
lea ebx, [inner_ctx]
invoke sha256_update, ebx, [_data], [_length]
lea ebx, [inner_ctx]
invoke sha256_final, ebx
DEBUGF 1, "Inner Hash: "
lea esi, [inner_ctx.hash]
stdcall dump_hex, esi, SHA256_HASH_SIZE/4
; Calculate outer hash
lea ebx, [outer_ctx]
lea esi, [inner_ctx.hash]
invoke sha256_update, ebx, esi, SHA256_HASH_SIZE
lea ebx, [outer_ctx]
invoke sha256_final, ebx
; Copy output hash to ctx structure ; FIXME
lea esi, [outer_ctx.hash]
mov edi, [ctx]
repeat SHA256_HASH_SIZE/4
movsd
end repeat
popa
ret
endp

View File

@ -541,13 +541,13 @@ proc mpint_modexp uses edi eax ebx ecx, dst, base, exp, mod
ret ret
.mod_zero: .mod_zero:
DEBUGF 1, "modexp with modulo 0\n" DEBUGF 3, "modexp with modulo 0\n"
; if mod is zero, result = 0 ; if mod is zero, result = 0
stdcall mpint_zero, [dst] stdcall mpint_zero, [dst]
ret ret
.exp_zero: .exp_zero:
DEBUGF 1, "modexp with exponent 0\n" DEBUGF 3, "modexp with exponent 0\n"
; if exponent is zero, result = 1 ; if exponent is zero, result = 1
stdcall mpint_zero, [dst] stdcall mpint_zero, [dst]
mov eax, [dst] mov eax, [dst]
@ -556,7 +556,7 @@ proc mpint_modexp uses edi eax ebx ecx, dst, base, exp, mod
ret ret
.invalid: .invalid:
DEBUGF 1, "modexp: Invalid input!\n" DEBUGF 3, "modexp: Invalid input!\n"
ret ret
endp endp

View File

@ -18,7 +18,7 @@
format binary as "" format binary as ""
__DEBUG__ = 1 __DEBUG__ = 1
__DEBUG_LEVEL__ = 1 __DEBUG_LEVEL__ = 2 ; 1: Extreme debugging, 2: Debugging, 3: Errors only
BUFFERSIZE = 4096 BUFFERSIZE = 4096
MAX_BITS = 8192 MAX_BITS = 8192
@ -33,16 +33,17 @@ use32
dd i_end ; initialized size dd i_end ; initialized size
dd mem+4096 ; required memory dd mem+4096 ; required memory
dd mem+4096 ; stack pointer dd mem+4096 ; stack pointer
dd hostname ; parameters dd params ; parameters
dd 0 ; path dd 0 ; path
include '../../macros.inc' include '../../macros.inc'
;include '../../struct.inc'
purge mov,add,sub purge mov,add,sub
include '../../proc32.inc' include '../../proc32.inc'
include '../../dll.inc' include '../../dll.inc'
include '../../debug-fdo.inc' include '../../debug-fdo.inc'
include '../../network.inc' include '../../network.inc'
;include '../../develop/libraries/libcrash/trunk/libcrash.inc' include '../../develop/libraries/libcrash/trunk/libcrash.inc'
include 'mcodes.inc' include 'mcodes.inc'
include 'ssh_transport.inc' include 'ssh_transport.inc'
@ -53,7 +54,7 @@ include 'random.inc'
include 'aes256.inc' include 'aes256.inc'
include 'aes256-ctr.inc' include 'aes256-ctr.inc'
include 'aes256-cbc.inc' include 'aes256-cbc.inc'
include '../../fs/kfar/trunk/kfar_arc/sha256.inc' include 'hmac_sha256.inc'
; macros for network byte order ; macros for network byte order
macro dd_n op { macro dd_n op {
@ -68,24 +69,120 @@ macro dw_n op {
(((op) and 000FFh) shl 8) (((op) and 000FFh) shl 8)
} }
proc dump_hex _ptr, _length
if __DEBUG_LEVEL__ <= 1
pushad
mov esi, [_ptr]
mov ecx, [_length]
.next_dword:
lodsd
bswap eax
DEBUGF 1,'%x',eax
loop .next_dword
DEBUGF 1,'\n'
popad
ret
end if
endp
struct ssh_connection
; Connection
hostname rb 1024
socketnum dd ?
sockaddr dw ? ; Address family
port dw ?
ip dd ?
rb 10
; Encryption/Decryption
rx_crypt_proc dd ?
tx_crypt_proc dd ?
rx_crypt_ctx_ptr dd ?
tx_crypt_ctx_ptr dd ?
rx_crypt_blocksize dd ?
tx_crypt_blocksize dd ?
; Message authentication
rx_mac_proc dd ?
tx_mac_proc dd ?
rx_mac_ctx hmac_sha256_context
tx_mac_ctx hmac_sha256_context
rx_mac_length dd ?
tx_mac_length dd ?
; Buffers
rx_seq dd ? ; Packet sequence number for MAC
rx_buffer ssh_packet_header
rb BUFFERSIZE-sizeof.ssh_packet_header
tx_seq dd ? ; Packet sequence number for MAC
tx_buffer ssh_packet_header
rb BUFFERSIZE-sizeof.ssh_packet_header
send_data dw ?
; Output from key exchange
dh_K dd ? ; Shared Secret (Big endian)
rb MAX_BITS/8
dh_K_length dd ? ; Length in little endian
dh_H rb 32 ; Exchange Hash
session_id_prefix db ?
session_id rb 32
rx_iv rb 32 ; Rx initialisation vector
tx_iv rb 32 ; Tx initialisation vector
rx_enc_key rb 32 ; Rx encryption key
tx_enc_key rb 32 ; Tx encryption key
rx_int_key rb 32 ; Rx integrity key
tx_int_key rb 32 ; Tx integrity key
; Diffie Hellman
dh_p dd ?
rb MAX_BITS/8
dh_g dd ?
rb MAX_BITS/8
dh_x dd ?
rb MAX_BITS/8
dh_e dd ?
rb MAX_BITS/8
dh_f dd ?
rb MAX_BITS/8
dh_signature dd ?
rb MAX_BITS/8
temp_ctx ctx_sha224256
k_h_ctx ctx_sha224256
ends
start: start:
mcall 68, 11 ; Init heap mcall 68, 11 ; Init heap
DEBUGF 1, "SSH: Loading libraries\n" DEBUGF 2, "SSH: Loading libraries\n"
stdcall dll.Load, @IMPORT stdcall dll.Load, @IMPORT
test eax, eax test eax, eax
jnz exit jnz exit
DEBUGF 1, "SSH: Init PRNG\n" DEBUGF 2, "SSH: Init PRNG\n"
call init_random call init_random
DEBUGF 1, "SSH: Init Console\n" DEBUGF 2, "SSH: Init Console\n"
invoke con_start, 1 invoke con_start, 1
invoke con_init, 80, 25, 80, 25, title invoke con_init, 80, 25, 80, 25, title
; Check for parameters ; Check for parameters TODO
cmp byte[hostname], 0 ; cmp byte[params], 0
jne resolve ; jne resolve
main: main:
invoke con_cls invoke con_cls
@ -96,7 +193,7 @@ prompt:
; write prompt ; write prompt
invoke con_write_asciiz, str2 invoke con_write_asciiz, str2
; read string ; read string
mov esi, hostname mov esi, con.hostname
invoke con_gets, esi, 256 invoke con_gets, esi, 256
; check for exit ; check for exit
test eax, eax test eax, eax
@ -105,10 +202,11 @@ prompt:
jz done jz done
resolve: resolve:
mov [sockaddr1.port], 22 shl 8 mov [con.sockaddr], AF_INET4
mov [con.port], 22 shl 8
; delete terminating '\n' ; delete terminating '\n'
mov esi, hostname mov esi, con.hostname
@@: @@:
lodsb lodsb
cmp al, ':' cmp al, ':'
@ -130,21 +228,21 @@ resolve:
jb hostname_error jb hostname_error
cmp al, 9 cmp al, 9
ja hostname_error ja hostname_error
lea ebx, [ebx*4 + ebx] lea ebx, [ebx*4+ebx]
shl ebx, 1 shl ebx, 1
add ebx, eax add ebx, eax
jmp .portloop jmp .portloop
.port_done: .port_done:
xchg bl, bh xchg bl, bh
mov [sockaddr1.port], bx mov [con.port], bx
.done: .done:
; resolve name ; resolve name
push esp ; reserve stack place push esp ; reserve stack place
push esp push esp
invoke getaddrinfo, hostname, 0, 0 invoke getaddrinfo, con.hostname, 0, 0
pop esi pop esi
; test for error ; test for error
test eax, eax test eax, eax
@ -152,7 +250,7 @@ resolve:
invoke con_cls invoke con_cls
invoke con_write_asciiz, str3 invoke con_write_asciiz, str3
invoke con_write_asciiz, hostname invoke con_write_asciiz, con.hostname
; write results ; write results
invoke con_write_asciiz, str8 invoke con_write_asciiz, str8
@ -160,7 +258,7 @@ resolve:
; convert IP address to decimal notation ; convert IP address to decimal notation
mov eax, [esi+addrinfo.ai_addr] mov eax, [esi+addrinfo.ai_addr]
mov eax, [eax+sockaddr_in.sin_addr] mov eax, [eax+sockaddr_in.sin_addr]
mov [sockaddr1.ip], eax mov [con.ip], eax
invoke inet_ntoa, eax invoke inet_ntoa, eax
; write result ; write result
invoke con_write_asciiz, eax invoke con_write_asciiz, eax
@ -176,47 +274,56 @@ resolve:
mcall socket, AF_INET4, SOCK_STREAM, 0 mcall socket, AF_INET4, SOCK_STREAM, 0
cmp eax, -1 cmp eax, -1
jz socket_err jz socket_err
mov [socketnum], eax mov [con.socketnum], eax
; Connect ; Connect
mcall connect, [socketnum], sockaddr1, 18 DEBUGF 2, "Connecting to server\n"
mcall connect, [con.socketnum], con.sockaddr, 18
test eax, eax test eax, eax
jnz socket_err jnz socket_err
; Start calculating hash meanwhile ; Start calculating hash
call sha256_init invoke sha256_init, con.temp_ctx
; HASH: string V_C, the client's version string (CR and NL excluded) ; HASH: string V_C, the client's version string (CR and NL excluded)
mov esi, ssh_ident_ha invoke sha256_update, con.temp_ctx, ssh_ident_ha, ssh_ident.length+4-2
mov edx, ssh_ident.length+4-2
call sha256_update
; Send our identification string ; >> Send our identification string
DEBUGF 1, "Sending ID string\n" DEBUGF 2, "Sending ID string\n"
mcall send, [socketnum], ssh_ident, ssh_ident.length, 0 mcall send, [con.socketnum], ssh_ident, ssh_ident.length, 0
cmp eax, -1 cmp eax, -1
je socket_err je socket_err
; Check protocol version of server ; << Check protocol version of server
mcall recv, [socketnum], rx_buffer, BUFFERSIZE, 0 mcall recv, [con.socketnum], con.rx_buffer, BUFFERSIZE, 0
cmp eax, -1 cmp eax, -1
je socket_err je socket_err
DEBUGF 1, "Received ID string\n" DEBUGF 2, "Received ID string\n"
cmp dword[rx_buffer], "SSH-" cmp dword[con.rx_buffer], "SSH-"
jne proto_err jne proto_err
cmp dword[rx_buffer+4], "2.0-" cmp dword[con.rx_buffer+4], "2.0-"
jne proto_err jne proto_err
; HASH: string V_S, the server's version string (CR and NL excluded) ; HASH: string V_S, the server's version string (CR and NL excluded)
lea edx, [eax+2] lea edx, [eax+2]
sub eax, 2 sub eax, 2
bswap eax bswap eax
mov [rx_buffer-4], eax mov dword[con.rx_buffer-4], eax
mov esi, rx_buffer-4 invoke sha256_update, con.temp_ctx, con.rx_buffer-4, edx
call sha256_update
; Key Exchange init ; >> Key Exchange init
DEBUGF 1, "Sending KEX init\n" mov [con.rx_seq], 0
mov [con.tx_seq], 0
mov [con.rx_crypt_blocksize], 4 ; minimum blocksize
mov [con.tx_crypt_blocksize], 4
mov [con.rx_crypt_proc], 0
mov [con.tx_crypt_proc], 0
mov [con.rx_mac_proc], 0
mov [con.tx_mac_proc], 0
mov [con.rx_mac_length], 0
mov [con.tx_mac_length], 0
DEBUGF 2, "Sending KEX init\n"
mov edi, ssh_kex.cookie mov edi, ssh_kex.cookie
call MBRandom call MBRandom
stosd stosd
@ -226,32 +333,31 @@ resolve:
stosd stosd
call MBRandom call MBRandom
stosd stosd
stdcall ssh_send_packet, [socketnum], ssh_kex, ssh_kex.length, 0 stdcall ssh_send_packet, con, ssh_kex, ssh_kex.length, 0
cmp eax, -1 cmp eax, -1
je socket_err je socket_err
; HASH: string I_C, the payload of the client's SSH_MSG_KEXINIT ; HASH: string I_C, the payload of the client's SSH_MSG_KEXINIT
mov eax, [tx_buffer+ssh_header.length] mov eax, dword[con.tx_buffer+ssh_packet_header.packet_length]
bswap eax bswap eax
movzx ebx, [tx_buffer+ssh_header.padding] movzx ebx, [con.tx_buffer+ssh_packet_header.padding_length]
sub eax, ebx sub eax, ebx
dec eax dec eax
lea edx, [eax+4] lea edx, [eax+4]
bswap eax bswap eax
mov [tx_buffer+1], eax mov dword[con.tx_buffer+1], eax
mov esi, tx_buffer+1 invoke sha256_update, con.temp_ctx, con.tx_buffer+1, edx
call sha256_update
; Check key exchange init of server ; << Check key exchange init of server
stdcall ssh_recv_packet, [socketnum], rx_buffer, BUFFERSIZE, 0 stdcall ssh_recv_packet, con, 0
cmp eax, -1 cmp eax, -1
je socket_err je socket_err
cmp [rx_buffer+ssh_header.message_code], SSH_MSG_KEXINIT cmp [con.rx_buffer.message_code], SSH_MSG_KEXINIT
jne proto_err jne proto_err
DEBUGF 1, "Received KEX init\n" DEBUGF 2, "Received KEX init\n"
lea esi, [rx_buffer+sizeof.ssh_header+16] lea esi, [con.rx_buffer+sizeof.ssh_packet_header+16]
lodsd lodsd
bswap eax bswap eax
DEBUGF 1, "kex_algorithms: %s\n", esi DEBUGF 1, "kex_algorithms: %s\n", esi
@ -295,38 +401,144 @@ resolve:
lodsb lodsb
DEBUGF 1, "KEX First Packet Follows: %u\n", al DEBUGF 1, "KEX First Packet Follows: %u\n", al
; TODO ; TODO: parse this structure and init procedures accordingly
; HASH: string I_S, the payload of the servers's SSH_MSG_KEXINIT ; HASH: string I_S, the payload of the servers's SSH_MSG_KEXINIT
mov eax, [rx_buffer+ssh_header.length] mov eax, dword[con.rx_buffer+ssh_packet_header.packet_length]
movzx ebx, [rx_buffer+ssh_header.padding] movzx ebx, [con.rx_buffer+ssh_packet_header.padding_length]
sub eax, ebx sub eax, ebx
dec eax dec eax
lea edx, [eax+4] lea edx, [eax+4]
bswap eax bswap eax
mov [rx_buffer+sizeof.ssh_header-5], eax mov dword[con.rx_buffer+sizeof.ssh_packet_header-5], eax
mov esi, rx_buffer+sizeof.ssh_header-5 invoke sha256_update, con.temp_ctx, con.rx_buffer+sizeof.ssh_packet_header-5, edx
call sha256_update
; Exchange keys with the server ; Exchange keys with the server
stdcall dh_gex stdcall dh_gex
test eax, eax test eax, eax
jnz exit jnz exit
; Set keys ; Set keys
DEBUGF 1, "SSH: Init encryption\n"
stdcall aes256_cbc_init, rx_iv
mov [rx_context], eax
stdcall aes256_set_encrypt_key, [rx_context], rx_enc_key
mov [decrypt_proc], aes256_cbc_decrypt
mov [rx_blocksize], 32
DEBUGF 1, "SSH: Init decryption\n" DEBUGF 2, "SSH: Setting encryption keys\n"
stdcall aes256_cbc_init, tx_iv
mov [tx_context], eax stdcall aes256_cbc_init, con.rx_iv
stdcall aes256_set_decrypt_key, [tx_context], tx_enc_key mov [con.rx_crypt_ctx_ptr], eax
mov [encrypt_proc], aes256_cbc_encrypt
mov [tx_blocksize], 32 stdcall aes256_set_decrypt_key, eax, con.rx_enc_key
mov [con.rx_crypt_proc], aes256_cbc_decrypt
mov [con.rx_crypt_blocksize], AES256_BLOCKSIZE
stdcall aes256_cbc_init, con.tx_iv
mov [con.tx_crypt_ctx_ptr], eax
stdcall aes256_set_encrypt_key, eax, con.tx_enc_key
mov [con.tx_crypt_proc], aes256_cbc_encrypt
mov [con.tx_crypt_blocksize], AES256_BLOCKSIZE
stdcall hmac_sha256_setkey, con.rx_mac_ctx, con.rx_int_key, SHA256_HASH_SIZE
mov [con.rx_mac_proc], hmac_sha256
mov [con.rx_mac_length], SHA256_HASH_SIZE
stdcall hmac_sha256_setkey, con.tx_mac_ctx, con.tx_int_key, SHA256_HASH_SIZE
mov [con.tx_mac_proc], hmac_sha256
mov [con.tx_mac_length], SHA256_HASH_SIZE
; TODO: erase all keys from memory and free the memory
; >> Request service (user-auth)
DEBUGF 2, "SSH: Requesting service\n"
stdcall ssh_send_packet, con, ssh_request_service, ssh_request_service.length, 0
cmp eax, -1
je socket_err
; << Check for service acceptance
stdcall ssh_recv_packet, con, 0
cmp eax, -1
je socket_err
cmp [con.rx_buffer.message_code], SSH_MSG_SERVICE_ACCEPT
jne proto_err
; >> Request user authentication
; TODO: Request username from the user
; invoke con_write_asciiz, str12
; invoke con_gets, username, 256
; test eax, eax
; jz done
; TODO: implement password authentication
DEBUGF 2, "SSH: User authentication\n"
stdcall ssh_send_packet, con, ssh_request_userauth, ssh_request_userauth.length, 0
cmp eax, -1
je socket_err
; << Check for userauth acceptance
stdcall ssh_recv_packet, con, 0
cmp eax, -1
je socket_err
cmp [con.rx_buffer.message_code], SSH_MSG_USERAUTH_SUCCESS
jne proto_err
; >> Open channel
DEBUGF 2, "SSH: Open channel\n"
stdcall ssh_send_packet, con, ssh_channel_open, ssh_channel_open.length, 0
cmp eax, -1
je socket_err
; << Check for channel open confirmation
stdcall ssh_recv_packet, con, 0
cmp eax, -1
je socket_err
cmp [con.rx_buffer.message_code], SSH_MSG_CHANNEL_OPEN_CONFIRMATION
jne proto_err
; >> Channel request: pty
DEBUGF 2, "SSH: Request pty\n"
stdcall ssh_send_packet, con, ssh_channel_request, ssh_channel_request.length, 0
cmp eax, -1
je socket_err
; << Check for channel request confirmation
stdcall ssh_recv_packet, con, 0
cmp eax, -1
je socket_err
cmp [con.rx_buffer.message_code], SSH_MSG_CHANNEL_SUCCESS
jne proto_err
; >> Channel request: shell
DEBUGF 2, "SSH: Request shell\n"
stdcall ssh_send_packet, con, ssh_shell_request, ssh_shell_request.length, 0
cmp eax, -1
je socket_err
; << Check for channel request confirmation (FIXME: this may not be first packet!)
; stdcall ssh_recv_packet, con, 0
; cmp eax, -1
; je socket_err
; cmp [con.rx_buffer.message_code], SSH_MSG_CHANNEL_SUCCESS
; jne proto_err
; Launch network thread ; Launch network thread
mcall 18, 7 mcall 18, 7
@ -340,13 +552,26 @@ mainloop:
test eax, 0x200 ; con window closed? test eax, 0x200 ; con window closed?
jnz exit jnz exit
stdcall ssh_recv_packet, [socketnum], rx_buffer, BUFFERSIZE, 0 stdcall ssh_recv_packet, con, 0
cmp eax, -1 cmp eax, 0
je closed jbe closed
cmp [con.rx_buffer.message_code], SSH_MSG_CHANNEL_DATA
jne .dump
mov eax, dword[con.rx_buffer.message_code+5]
bswap eax
DEBUGF 1, 'SSH: got %u bytes of data !\n', eax DEBUGF 1, 'SSH: got %u bytes of data !\n', eax
mov esi, rx_buffer lea esi, [con.rx_buffer.message_code+5+4]
mov ecx, eax
lea edi, [esi + eax]
mov byte [edi], 0
invoke con_write_asciiz, esi
jmp mainloop
.dump:
lea esi, [con.rx_buffer]
mov ecx, eax mov ecx, eax
pusha pusha
@@: @@:
@ -355,23 +580,22 @@ mainloop:
dec ecx dec ecx
jnz @r jnz @r
popa popa
lea edi, [esi + eax] DEBUGF 1, "\n"
mov byte [edi], 0
invoke con_write_asciiz, esi
jmp mainloop jmp mainloop
proto_err: proto_err:
DEBUGF 1, "SSH: protocol error\n" DEBUGF 3, "SSH: protocol error\n"
invoke con_write_asciiz, str7 invoke con_write_asciiz, str7
jmp prompt jmp prompt
socket_err: socket_err:
DEBUGF 1, "SSH: socket error %d\n", ebx DEBUGF 3, "SSH: socket error %d\n", ebx
invoke con_write_asciiz, str6 invoke con_write_asciiz, str6
jmp prompt jmp prompt
dns_error: dns_error:
DEBUGF 1, "SSH: DNS error %d\n", eax DEBUGF 3, "SSH: DNS error %d\n", eax
invoke con_write_asciiz, str5 invoke con_write_asciiz, str5
jmp prompt jmp prompt
@ -386,8 +610,8 @@ closed:
done: done:
invoke con_exit, 1 invoke con_exit, 1
exit: exit:
DEBUGF 1, "SSH: Exiting\n" DEBUGF 3, "SSH: Exiting\n"
mcall close, [socketnum] mcall close, [con.socketnum]
mcall -1 mcall -1
@ -395,14 +619,8 @@ thread:
mcall 40, 0 mcall 40, 0
.loop: .loop:
invoke con_getch2 invoke con_getch2
mov [send_data], ax mov [ssh_channel_data+9], al
xor esi, esi stdcall ssh_send_packet, con, ssh_channel_data, ssh_channel_data.length, 0
inc esi
test al, al
jnz @f
inc esi
@@:
stdcall ssh_send_packet, [socketnum], send_data, 0
invoke con_get_flags invoke con_get_flags
test eax, 0x200 ; con window closed? test eax, 0x200 ; con window closed?
@ -423,17 +641,12 @@ str8 db ' (',0
str9 db ')',10,0 str9 db ')',10,0
str10 db 'Invalid hostname.',10,10,0 str10 db 'Invalid hostname.',10,10,0
str11 db 10,'Remote host closed the connection.',10,10,0 str11 db 10,'Remote host closed the connection.',10,10,0
str12 db 'Enter username: ',0
sockaddr1:
dw AF_INET4
.port dw 0
.ip dd 0
rb 10
ssh_ident_ha: ssh_ident_ha:
dd_n (ssh_ident.length-2) dd_n (ssh_ident.length-2)
ssh_ident: ssh_ident:
db "SSH-2.0-KolibriOS_SSH_0.01",13,10 db "SSH-2.0-KolibriOS_SSH_0.02",13,10
.length = $ - ssh_ident .length = $ - ssh_ident
ssh_kex: ssh_kex:
@ -479,9 +692,9 @@ ssh_kex:
ssh_gex_req: ssh_gex_req:
db SSH_MSG_KEX_DH_GEX_REQUEST db SSH_MSG_KEX_DH_GEX_REQUEST
dd_n 128 ; DH GEX min dd_n 128 ; DH GEX min
dd_n 256 ; DH GEX number of bits dd_n 256 ; DH GEX number of bits
dd_n 512 ; DH GEX Max dd_n 512 ; DH GEX Max
.length = $ - ssh_gex_req .length = $ - ssh_gex_req
@ -490,16 +703,75 @@ ssh_new_keys:
.length = $ - ssh_new_keys .length = $ - ssh_new_keys
ssh_request_service:
db SSH_MSG_SERVICE_REQUEST
dd_n 12 ; String length
db "ssh-userauth" ; Service name
.length = $ - ssh_request_service
ssh_request_userauth:
db SSH_MSG_USERAUTH_REQUEST
dd_n 12
dd_n 8
db "username" ; user name in ISO-10646 UTF-8 encoding [RFC3629]
dd_n 14
db "ssh-connection" ; service name in US-ASCII
dd_n 4
db "none" ; method name in US-ASCII
; Other options: publickey, password, hostbased
.length = $ - ssh_request_userauth
ssh_channel_open:
db SSH_MSG_CHANNEL_OPEN
dd_n 7
db "session"
dd_n 0 ; Sender channel
dd_n 1024 ; Initial window size
dd_n 1024 ; maximum packet size
.length = $ - ssh_channel_open
ssh_channel_request:
db SSH_MSG_CHANNEL_REQUEST
dd_n 0 ; Recipient channel
dd_n 7
db "pty-req"
db 1 ; Bool: want reply
dd_n 5
db "xterm"
dd_n 80 ; terminal width (rows)
dd_n 25 ; terminal height (rows)
dd_n 0 ; terminal width (pixels)
dd_n 0 ; terminal height (pixels)
dd_n 0 ; list of supported opcodes
.length = $ - ssh_channel_request
ssh_shell_request:
db SSH_MSG_CHANNEL_REQUEST
dd_n 0 ; Recipient channel
dd_n 5
db "shell"
db 1 ; Bool: want reply
.length = $ - ssh_shell_request
ssh_channel_data:
db SSH_MSG_CHANNEL_DATA
dd_n 0 ; Sender channel
dd_n 1
db ?
.length = $ - ssh_channel_data
include_debug_strings include_debug_strings
; import
align 4 align 4
@IMPORT: @IMPORT:
library network, 'network.obj', \ library network, 'network.obj', \
console, 'console.obj';, \ console, 'console.obj', \
; libcrash, 'libcrash.obj' libcrash, 'libcrash.obj'
import network, \ import network, \
getaddrinfo, 'getaddrinfo', \ getaddrinfo, 'getaddrinfo', \
@ -518,61 +790,23 @@ import console, \
con_write_string, 'con_write_string', \ con_write_string, 'con_write_string', \
con_get_flags, 'con_get_flags' con_get_flags, 'con_get_flags'
;import libcrash, \ import libcrash, \
; crash.hash, 'crash_hash' sha256_init, 'sha256_init', \
sha256_update, 'sha256_update', \
sha256_final, 'sha256_final'
IncludeIGlobals IncludeIGlobals
i_end: i_end:
decrypt_proc dd dummy_encrypt
encrypt_proc dd dummy_encrypt
rx_blocksize dd 4
tx_blocksize dd 4
rx_context dd ?
tx_context dd ?
IncludeUGlobals IncludeUGlobals
socketnum dd ? params rb 1024
rx_packet_length dd ? ;;;;;
rx_buffer: rb BUFFERSIZE+1
tx_buffer: rb BUFFERSIZE+1
send_data dw ? con ssh_connection
hostname rb 1024 ; Temporary values ; To be removed FIXME
; Diffie Hellman variables
dh_p dd ?
rb MAX_BITS/8
dh_g dd ?
rb MAX_BITS/8
dh_x dd ?
rb MAX_BITS/8
dh_e dd ?
rb MAX_BITS/8
dh_f dd ?
rb MAX_BITS/8
dh_signature dd ?
rb MAX_BITS/8
; Output from key exchange
dh_K dd ? ; Shared Secret (Big endian)
rb MAX_BITS/8
.length dd ? ; Length in little endian
dh_H rb 32 ; Exchange Hash
session_id rb 32
rx_iv rb 32 ; Rx initialisation vector
tx_iv rb 32 ; Tx initialisation vector
rx_enc_key rb 32 ; Rx encryption key
tx_enc_key rb 32 ; Tx encryption key
rx_int_key rb 32 ; Rx integrity key
tx_int_key rb 32 ; Tx integrity key
; Temporary values ; To be removed
mpint_tmp rb MPINT_MAX_LEN+4 mpint_tmp rb MPINT_MAX_LEN+4
mem: mem:

View File

@ -15,120 +15,181 @@
; You should have received a copy of the GNU General Public License ; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>. ; along with this program. If not, see <http://www.gnu.org/licenses/>.
struct ssh_header
length dd ? struct ssh_packet_header
padding db ? packet_length dd ? ; The length of the packet in bytes, not including 'mac' or the
message_code db ? ; 'packet_length' field itself.
padding_length db ? ; Length of 'random padding' (bytes).
message_code db ? ; First byte of payload
ends ends
proc dummy_encrypt _key, _in, _out
ret proc ssh_recv_packet connection, flags
endp
proc ssh_recv_packet sock, buf, size, flags
locals locals
bufferptr dd ? data_length dd ? ; Total length of packet without MAC
remaining dd ?
padding dd ?
endl endl
DEBUGF 1, "ssh_recv_packet\n" DEBUGF 2, "> "
; Receive first block (Read length, padding length, message code) ; Receive first block (Read length, padding length, message code)
mcall recv, [sock], [buf], [rx_blocksize], [flags] mov ebx, [connection]
DEBUGF 1, "chunk = %u\n", eax mov ecx, [ebx+ssh_connection.socketnum]
cmp eax, [rx_blocksize] mov esi, [ebx+ssh_connection.rx_crypt_blocksize]
jne .fail ;;;; lea edx, [ebx+ssh_connection.rx_buffer]
mov edi, [flags]
mcall recv
DEBUGF 1, "chunk = %u ", eax
mov ebx, [connection]
cmp eax, [ebx+ssh_connection.rx_crypt_blocksize]
jne .fail
; stdcall [decrypt_proc], [rx_context], [buf], [buf] ; Decrypt first block
cmp [ebx+ssh_connection.rx_crypt_proc], 0
je @f
pusha
lea esi, [ebx+ssh_connection.rx_buffer]
stdcall [ebx+ssh_connection.rx_crypt_proc], [ebx+ssh_connection.rx_crypt_ctx_ptr], esi, esi
popa
@@:
mov ebx, [buf] ; Check data length
movzx eax, [ebx+ssh_header.padding] mov esi, [ebx+ssh_connection.rx_buffer.packet_length]
mov [padding], eax bswap esi ; convert length to little endian
mov eax, [ebx+ssh_header.length] mov [ebx+ssh_connection.rx_buffer.packet_length], esi
bswap eax ; length to little endian DEBUGF 1, "packet length=%u ", esi
mov [ebx+ssh_header.length], eax cmp esi, BUFFERSIZE
DEBUGF 1, "ssh_recv_packet length = %u\n", eax ja .fail ; packet is too large
cmp eax, [size] ; Calculate amount of remaining data
ja .fail ;;;; add esi, 4 ; Packet length field itself is not included in the count
sub esi, [ebx+ssh_connection.rx_crypt_blocksize] ; Already received this amount of data
add esi, [ebx+ssh_connection.rx_mac_length]
jz .got_all_data
sub eax, [rx_blocksize] ; Receive remaining data
add eax, 4 lea edx, [ebx+ssh_connection.rx_buffer]
mov [remaining], eax add edx, [ebx+ssh_connection.rx_crypt_blocksize]
add ebx, [rx_blocksize] mov ecx, [ebx+ssh_connection.socketnum]
mov [bufferptr], ebx mov edi, [flags]
.receive_loop: .receive_loop:
mcall recv, [sock], [bufferptr], [remaining], 0 mcall recv
DEBUGF 1, "chunk = %u\n", eax DEBUGF 1, "chunk = %u ", eax
cmp eax, 0 cmp eax, 0
jbe .fail jbe .fail
add [bufferptr], eax add edx, eax
sub [remaining], eax sub esi, eax
ja .receive_loop jnz .receive_loop
; .decrypt_loop: ; Decrypt data
; stdcall [decrypt_proc], [rx_context], [buf], [buf] mov ebx, [connection]
; ja .decrypt_loop cmp [ebx+ssh_connection.rx_crypt_proc], 0
je .decrypt_complete
mov ecx, [ebx+ssh_connection.rx_buffer.packet_length]
add ecx, 4 ; Packet_length field itself
sub ecx, [ebx+ssh_connection.rx_crypt_blocksize] ; Already decrypted this amount of data
jz .decrypt_complete
; .hmac_loop: lea esi, [ebx+ssh_connection.rx_buffer]
; TODO add esi, [ebx+ssh_connection.rx_crypt_blocksize]
; ja .hmac_loop .decrypt_loop:
pusha
stdcall [ebx+ssh_connection.rx_crypt_proc], [ebx+ssh_connection.rx_crypt_ctx_ptr], esi, esi
popa
add esi, [ebx+ssh_connection.rx_crypt_blocksize]
sub ecx, [ebx+ssh_connection.rx_crypt_blocksize]
jnz .decrypt_loop
.decrypt_complete:
; Return usefull data length in eax ; Authenticate message
mov eax, [buf] cmp [ebx+ssh_connection.rx_mac_proc], 0
movzx ebx, [eax+ssh_header.padding] je .mac_complete
mov eax, [eax+ssh_header.length] lea esi, [ebx+ssh_connection.rx_seq]
mov ecx, [ebx+ssh_connection.rx_buffer.packet_length]
add ecx, 8 ; packet_length field itself + sequence number
lea eax, [ebx+ssh_connection.rx_mac_ctx]
mov edx, [ebx+ssh_connection.rx_buffer.packet_length]
bswap edx ; convert length to big endian
mov [ebx+ssh_connection.rx_buffer.packet_length], edx
stdcall [ebx+ssh_connection.rx_mac_proc], eax, esi, ecx
mov edx, [ebx+ssh_connection.rx_buffer.packet_length]
bswap edx ; convert length to little endian
mov [ebx+ssh_connection.rx_buffer.packet_length], edx
lea esi, [ebx+ssh_connection.rx_mac_ctx]
lea edi, [ebx+ssh_connection.rx_buffer]
add edi, [ebx+ssh_connection.rx_buffer.packet_length]
add edi, 4
mov ecx, [ebx+ssh_connection.rx_mac_length]
shr ecx, 2
repe cmpsd
jne .mac_failed
.mac_complete:
inc byte[ebx+ssh_connection.rx_seq+3] ; Update sequence counter
jnc @f
inc byte[ebx+ssh_connection.rx_seq+2]
jnc @f
inc byte[ebx+ssh_connection.rx_seq+1]
jnc @f
inc byte[ebx+ssh_connection.rx_seq+0]
@@:
; Return useful data length to the caller via eax register
.got_all_data:
mov eax, [ebx+ssh_connection.rx_buffer.packet_length]
movzx ebx, [ebx+ssh_connection.rx_buffer.padding_length]
sub eax, ebx sub eax, ebx
DEBUGF 1, "ssh_recv_packet complete, usefull data length=%u\n", eax DEBUGF 1, "useful data length=%u\n", eax
ret ret
.fail: .fail:
DEBUGF 1, "ssh_recv_packet failed!\n" DEBUGF 3, "ssh_recv_packet failed!\n"
mov eax, -1
ret
.mac_failed:
DEBUGF 3, "ssh_recv_packet MAC failed!\n"
mov eax, -1 mov eax, -1
ret ret
endp endp
proc ssh_send_packet sock, buf, payloadsize, flags proc ssh_send_packet connection, buf, payload_size, flags
locals locals
size dd ? packet_size dd ?
endl endl
DEBUGF 1, "ssh_send_packet: size=%u\n", [payloadsize] DEBUGF 2, "< "
mov eax, [payloadsize] ; Pad the packet with random data
inc eax ; padding length byte mov eax, [payload_size]
inc eax ; padding length byte
lea edx, [eax+4] ; total packet size (without padding) lea edx, [eax+4] ; total packet size (without padding and MAC)
mov [size], edx mov [packet_size], edx
mov ebx, [tx_blocksize] mov ecx, [connection]
mov ebx, [ecx+ssh_connection.tx_crypt_blocksize]
dec ebx dec ebx
and edx, ebx and edx, ebx
neg edx neg edx
add edx, [tx_blocksize] add edx, [ecx+ssh_connection.tx_crypt_blocksize]
cmp edx, 4 ; minimum padding size cmp edx, 4 ; minimum padding size
jae @f jae @f
add edx, [tx_blocksize] add edx, [ecx+ssh_connection.tx_crypt_blocksize]
@@: @@:
DEBUGF 1, "Padding %u bytes\n", edx DEBUGF 1, "padding %u bytes ", edx
add [size], edx add [packet_size], edx
add eax, edx add eax, edx
DEBUGF 1, "Total size: %u\n", eax DEBUGF 1, "total size: %u ", eax
bswap eax bswap eax
mov edi, tx_buffer lea edi, [ecx+ssh_connection.tx_buffer]
stosd stosd ; packet_length
mov al, dl mov al, dl
stosb stosb ; padding_length
mov esi, [buf] mov esi, [buf]
; cmp esi, edi mov ecx, [payload_size]
; je @f
mov ecx, [payloadsize]
rep movsb rep movsb
; @@:
mov ebx, edx mov ebx, edx
mov esi, edx mov esi, edx
@ -146,8 +207,59 @@ endl
dec esi dec esi
jnz @r jnz @r
mcall send, [sock], tx_buffer, [size], [flags] ; Message authentication
mov edx, [connection]
cmp [edx+ssh_connection.tx_mac_proc], 0
je .mac_complete
; DEBUGF 1, "MAC sequence number: 0x%x\n", [edx+ssh_connection.tx_seq]
lea esi, [edx+ssh_connection.tx_seq]
mov ecx, [packet_size]
add ecx, 4 ; Sequence number length
lea eax, [edx+ssh_connection.tx_mac_ctx]
stdcall [edx+ssh_connection.tx_mac_proc], eax, esi, ecx
lea esi, [edx+ssh_connection.tx_mac_ctx]
lea edi, [edx+ssh_connection.tx_buffer]
add edi, [packet_size]
mov ecx, [edx+ssh_connection.tx_mac_length]
shr ecx, 2
rep movsd
.mac_complete:
inc byte[edx+ssh_connection.tx_seq+3] ; Update sequence counter
jnc @f
inc byte[edx+ssh_connection.tx_seq+2]
jnc @f
inc byte[edx+ssh_connection.tx_seq+1]
jnc @f
inc byte[edx+ssh_connection.tx_seq+0]
@@:
; Encrypt data
cmp [edx+ssh_connection.tx_crypt_proc], 0
je .encrypt_complete
lea esi, [edx+ssh_connection.tx_buffer]
mov ecx, [packet_size]
.encrypt_loop:
pusha
stdcall [edx+ssh_connection.tx_crypt_proc], [edx+ssh_connection.tx_crypt_ctx_ptr], esi, esi
popa
add esi, [edx+ssh_connection.tx_crypt_blocksize]
sub ecx, [edx+ssh_connection.tx_crypt_blocksize]
jnz .encrypt_loop
.encrypt_complete:
; Send the packet
mov ebx, [connection]
mov ecx, [ebx+ssh_connection.socketnum]
lea edx, [ebx+ssh_connection.tx_buffer]
mov esi, [packet_size]
add esi, [ebx+ssh_connection.tx_mac_length]
mov edi, [flags]
mcall send
DEBUGF 1, "\n"
ret ret
endp endp