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/>.
struct aes256_cbc_context aes256_context
vector rb 16
vector rb AES256_BLOCKSIZE
ends
@ -25,7 +25,7 @@ proc aes256_cbc_init _vector
mcall 68, 12, sizeof.aes256_cbc_context
; handle errors
mov ecx, 16/4
mov ecx, AES256_BLOCKSIZE/4
mov esi, [_vector]
lea edi, [eax + aes256_cbc_context.vector]
rep movsd
@ -39,24 +39,16 @@ proc aes256_cbc_encrypt _ctx, _in, _out
push ebx esi edi
DEBUGF 1,'plain : '
stdcall dump_128bit_hex, [_in]
DEBUGF 1,'\n'
stdcall dump_hex, [_in], 4
mov edi, [_ctx]
lea edi, [edi + aes256_cbc_context.vector]
mov esi, [_in]
repeat AES256_BLOCKSIZE/4
lodsd
xor eax, [edi]
stosd
lodsd
xor eax, [edi]
stosd
lodsd
xor eax, [edi]
stosd
lodsd
xor eax, [edi]
stosd
end repeat
mov esi, [_ctx]
lea eax, [esi + aes256_cbc_context.key]
@ -66,25 +58,33 @@ proc aes256_cbc_encrypt _ctx, _in, _out
mov esi, [_out]
mov eax, [_ctx]
lea edi, [eax + aes256_cbc_context.vector]
repeat AES256_BLOCKSIZE/4
movsd
movsd
movsd
movsd
end repeat
DEBUGF 1,'cipher : '
stdcall dump_128bit_hex, [_out]
DEBUGF 1,'\n\n'
stdcall dump_hex, [_out], 4
pop edi esi ebx
ret
endp
proc aes256_cbc_decrypt _ctx, _in, _out
locals
temp_iv rb AES256_BLOCKSIZE
endl
push ebx esi edi
DEBUGF 1,'cipher : '
stdcall dump_128bit_hex, [_in]
DEBUGF 1,'\n'
stdcall dump_hex, [_in], 4
mov esi, [_in]
lea edi, [temp_iv]
repeat AES256_BLOCKSIZE/4
movsd
end repeat
mov esi, [_ctx]
lea eax, [esi + aes256_cbc_context.key]
@ -93,30 +93,21 @@ proc aes256_cbc_decrypt _ctx, _in, _out
mov esi, [_ctx]
lea esi, [esi + aes256_cbc_context.vector]
mov edi, [_out]
repeat AES256_BLOCKSIZE/4
lodsd
xor eax, [edi]
stosd
lodsd
xor eax, [edi]
stosd
lodsd
xor eax, [edi]
stosd
lodsd
xor eax, [edi]
stosd
end repeat
mov esi, [_in]
lea esi, [temp_iv]
mov edi, [_ctx]
lea edi, [edi + aes256_cbc_context.vector]
repeat AES256_BLOCKSIZE/4
movsd
movsd
movsd
movsd
end repeat
DEBUGF 1,'plain : '
stdcall dump_128bit_hex, [_out]
DEBUGF 1,'\n\n'
stdcall dump_hex, [_out], 4
pop edi esi ebx
ret

View File

@ -16,8 +16,8 @@
; along with this program. If not, see <http://www.gnu.org/licenses/>.
struct aes256_ctr_context aes256_context
counter rb 16
output rb 16 ; counter after aes_crypt
counter rb AES256_BLOCKSIZE
output rb AES256_BLOCKSIZE ; counter after aes_crypt
ends
@ -26,7 +26,7 @@ proc aes256_ctr_init _counter
mcall 68, 12, sizeof.aes256_ctr_context
; handle errors
mov ecx, 16/4
mov ecx, AES256_BLOCKSIZE/4
mov esi, [_counter]
lea edi, [eax + aes256_ctr_context.counter]
rep movsd
@ -42,8 +42,7 @@ proc aes256_ctr_crypt _ctx, _in, _out
push ebx esi edi
DEBUGF 1,'plain : '
stdcall dump_128bit_hex, [_in]
DEBUGF 1,'\n'
stdcall dump_hex, [_in], 4
mov esi, [_ctx]
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
DEBUGF 1,'cipher : '
stdcall dump_128bit_hex, [_out]
DEBUGF 1,'\n\n'
stdcall dump_hex, [_out], 4
pop edi esi ebx
ret

View File

@ -17,25 +17,12 @@
; along with this program. If not, see <http://www.gnu.org/licenses/>.
AES256_ROUNDS = 14
AES256_BLOCKSIZE = 16
struct aes256_context
key rd 4*(AES256_ROUNDS+1)
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
locals
@ -48,30 +35,11 @@ endl
mov esi, [_userkey]
lea edi, [ebx + aes256_context.key]
repeat 8
lodsd
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
lodsd
bswap eax
stosd
end repeat
lea esi, [ebx + aes256_context.key]
@ -176,7 +144,6 @@ endl
jmp .while
.done:
DEBUGF 1,' \n'
pop edi esi ebx
ret
endp
@ -266,8 +233,7 @@ endl
push ebx esi edi
DEBUGF 1,'input : '
stdcall dump_128bit_hex, [_in]
DEBUGF 1,'\n'
stdcall dump_hex, [_in], 4
mov ebx, [_key]
mov esi, [_in]
@ -663,8 +629,7 @@ endl
stosd
DEBUGF 1,'output : '
stdcall dump_128bit_hex, [_out]
DEBUGF 1,'\n'
stdcall dump_hex, [_out], 4
pop edi esi ebx
ret
@ -679,8 +644,7 @@ endl
push ebx esi edi
DEBUGF 1,'input : '
stdcall dump_128bit_hex, [_in]
DEBUGF 1,'\n'
stdcall dump_hex, [_in], 4
mov ebx, [_key]
mov esi, [_in]
@ -1073,8 +1037,7 @@ endl
stosd
DEBUGF 1,'output : '
stdcall dump_128bit_hex, [_out]
DEBUGF 1,'\n'
stdcall dump_hex, [_out], 4
pop edi esi ebx
ret

View File

@ -25,39 +25,39 @@ proc dh_gex
;----------------------------------------------
; >> Send Diffie-Hellman Group Exchange Request
DEBUGF 1, "Sending GEX\n"
stdcall ssh_send_packet, [socketnum], ssh_gex_req, ssh_gex_req.length, 0
DEBUGF 2, "Sending GEX\n"
stdcall ssh_send_packet, con, ssh_gex_req, ssh_gex_req.length, 0
cmp eax, -1
je .socket_err
;---------------------------------------------
; << Parse Diffie-Hellman Group Exchange Group
stdcall ssh_recv_packet, [socketnum], rx_buffer, BUFFERSIZE, 0
stdcall ssh_recv_packet, con, 0
cmp eax, -1
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
DEBUGF 1, "Received GEX group\n"
DEBUGF 2, "Received GEX group\n"
mov esi, rx_buffer+sizeof.ssh_header
mov edi, dh_p
mov esi, con.rx_buffer+sizeof.ssh_packet_header
mov edi, con.dh_p
DEBUGF 1, "DH modulus (p): "
call mpint_to_little_endian
stdcall mpint_print, dh_p
stdcall mpint_print, con.dh_p
DEBUGF 1, "DH base (g): "
mov edi, dh_g
mov edi, con.dh_g
call mpint_to_little_endian
stdcall mpint_print, dh_g
stdcall mpint_print, con.dh_g
;-------------------------------------------
; >> Send Diffie-Hellman Group Exchange Init
; generate a random number x, where 1 < x < (p-1)/2
mov edi, dh_x+4
mov [dh_x], DH_PRIVATE_KEY_SIZE/8
mov edi, con.dh_x+4
mov [con.dh_x], DH_PRIVATE_KEY_SIZE/8
mov ecx, DH_PRIVATE_KEY_SIZE/8/4
@@:
push ecx
@ -71,7 +71,7 @@ proc dh_gex
shl eax, 1
jnc @f
mov byte[edi], 0
inc dword[dh_x]
inc dword[con.dh_x]
@@:
; Fill remaining bytes with zeros ; TO BE REMOVED ?
@ -82,86 +82,82 @@ if ((MAX_BITS-DH_PRIVATE_KEY_SIZE) > 0)
end if
DEBUGF 1, "DH x: "
stdcall mpint_length, dh_x;;;;;;;;;;;;;
stdcall mpint_print, dh_x
stdcall mpint_length, con.dh_x;;;;;;;;;;;;;
stdcall mpint_print, con.dh_x
; Compute e = g^x mod p
stdcall mpint_modexp, dh_e, dh_g, dh_x, dh_p
stdcall mpint_length, dh_e
stdcall mpint_modexp, con.dh_e, con.dh_g, con.dh_x, con.dh_p
stdcall mpint_length, con.dh_e
DEBUGF 1, "DH e: "
stdcall mpint_print, dh_e
stdcall mpint_print, con.dh_e
; 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
stosb
mov esi, dh_e
mov esi, con.dh_e
call mpint_to_big_endian
DEBUGF 1, "Sending GEX init\n"
mov ecx, dword[tx_buffer+ssh_header.message_code+1]
DEBUGF 2, "Sending GEX init\n"
mov ecx, dword[con.tx_buffer.message_code+1]
bswap ecx
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
je .socket_err
;---------------------------------------------
; << Parse Diffie-Hellman Group Exchange Reply
stdcall ssh_recv_packet, [socketnum], rx_buffer, BUFFERSIZE, 0
stdcall ssh_recv_packet, con, 0
cmp eax, -1
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
DEBUGF 1, "Received GEX Reply\n"
DEBUGF 2, "Received GEX Reply\n"
;--------------------------------
; 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]
bswap edx
add edx, 4
lea ebx, [esi+edx]
push ebx
call sha256_update
invoke sha256_update, con.temp_ctx, esi, edx
;--------------------------------------------------------------------------
; 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 max, maximal size in bits of an acceptable group
mov esi, ssh_gex_req+sizeof.ssh_header-ssh_header.message_code
mov edx, 12
call sha256_update
invoke sha256_update, con.temp_ctx, ssh_gex_req+sizeof.ssh_packet_header-ssh_packet_header.message_code, 12
;----------------------------
; HASH: mpint p, safe prime
mov esi, dh_p
mov esi, con.dh_p
mov edi, mpint_tmp
call mpint_to_big_endian
lea edx, [eax+4]
mov esi, mpint_tmp
call sha256_update
invoke sha256_update, con.temp_ctx, mpint_tmp, edx
;----------------------------------------
; HASH: mpint g, generator for subgroup
mov esi, dh_g
mov esi, con.dh_g
mov edi, mpint_tmp
call mpint_to_big_endian
lea edx, [eax+4]
mov esi, mpint_tmp
call sha256_update
invoke sha256_update, con.temp_ctx, mpint_tmp, edx
;---------------------------------------------------
; 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]
bswap edx
add edx, 4
call sha256_update
invoke sha256_update, con.temp_ctx, esi, edx
;---------------------------------------------------
; HASH: mpint f, exchange value sent by the server
@ -169,254 +165,206 @@ end if
mov edx, [esi]
bswap edx
add edx, 4
call sha256_update
invoke sha256_update, con.temp_ctx, esi, edx
pop esi
mov edi, dh_f
mov edi, con.dh_f
call mpint_to_little_endian
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
DEBUGF 1, "DH signature: "
stdcall mpint_print, dh_signature
stdcall mpint_print, con.dh_signature
;--------------------------------------
; Calculate shared secret K = f^x mod p
stdcall mpint_modexp, rx_buffer, dh_f, dh_x, dh_p
stdcall mpint_length, rx_buffer
stdcall mpint_modexp, con.rx_buffer, con.dh_f, con.dh_x, con.dh_p
stdcall mpint_length, con.rx_buffer
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.
mov edi, dh_K
mov esi, rx_buffer
mov edi, con.dh_K
mov esi, con.rx_buffer
call mpint_to_big_endian
mov [dh_K.length], eax
mov [con.dh_K_length], eax
;-----------------------------------
; HASH: mpint K, the shared secret
mov edx, [dh_K.length]
mov edx, [con.dh_K_length]
add edx, 4
mov esi, dh_K
call sha256_update
invoke sha256_update, con.temp_ctx, con.dh_K, edx
;-------------------------------
; Finalize the exchange hash (H)
mov edi, dh_H
call sha256_final
invoke sha256_final, con.temp_ctx
mov esi, con.temp_ctx.hash
mov edi, con.dh_H
mov ecx, SHA256_HASH_SIZE/4
rep movsd
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
mov esi, dh_H
mov edi, session_id
mov ecx, 32/4
mov esi, con.dh_H
mov edi, con.session_id
mov ecx, SHA256_HASH_SIZE/4
rep movsd
;---------------
; 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)
call sha256_init
mov edx, [dh_K.length]
add edx, 4
mov esi, dh_K
call sha256_update
mov edx, 32
mov esi, dh_H
call sha256_update
mov edx, 1
mov esi, str_A
call sha256_update
mov edx, 32
mov esi, session_id
call sha256_update
mov edi, tx_iv
call sha256_final
mov esi, con.k_h_ctx
mov edi, con.temp_ctx
mov ecx, sizeof.ctx_sha224256/4
rep movsd
mov [con.session_id_prefix], 'A'
invoke sha256_update, con.temp_ctx, con.session_id_prefix, 32+1
invoke sha256_final, con.temp_ctx.hash
mov edi, con.tx_iv
mov esi, con.temp_ctx
mov ecx, SHA256_HASH_SIZE/4
rep movsd
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)
call sha256_init
mov edx, [dh_K.length]
add edx, 4
mov esi, dh_K
call sha256_update
mov edx, 32
mov esi, dh_H
call sha256_update
mov edx, 1
mov esi, str_B
call sha256_update
mov edx, 32
mov esi, session_id
call sha256_update
mov edi, rx_iv
call sha256_final
mov esi, con.k_h_ctx
mov edi, con.temp_ctx
mov ecx, sizeof.ctx_sha224256/4
rep movsd
inc [con.session_id_prefix]
invoke sha256_update, con.temp_ctx, con.session_id_prefix, 32+1
invoke sha256_final, con.temp_ctx
mov edi, con.rx_iv
mov esi, con.temp_ctx
mov ecx, SHA256_HASH_SIZE/4
rep movsd
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)
call sha256_init
mov edx, [dh_K.length]
add edx, 4
mov esi, dh_K
call sha256_update
mov edx, 32
mov esi, dh_H
call sha256_update
mov edx, 1
mov esi, str_C
call sha256_update
mov edx, 32
mov esi, session_id
call sha256_update
mov edi, tx_enc_key
call sha256_final
mov esi, con.k_h_ctx
mov edi, con.temp_ctx
mov ecx, sizeof.ctx_sha224256/4
rep movsd
inc [con.session_id_prefix]
invoke sha256_update, con.temp_ctx, con.session_id_prefix, 32+1
invoke sha256_final, con.temp_ctx
mov edi, con.tx_enc_key
mov esi, con.temp_ctx
mov ecx, SHA256_HASH_SIZE/4
rep movsd
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)
call sha256_init
mov edx, [dh_K.length]
add edx, 4
mov esi, dh_K
call sha256_update
mov edx, 32
mov esi, dh_H
call sha256_update
mov edx, 1
mov esi, str_D
call sha256_update
mov edx, 32
mov esi, session_id
call sha256_update
mov edi, rx_enc_key
call sha256_final
mov esi, con.k_h_ctx
mov edi, con.temp_ctx
mov ecx, sizeof.ctx_sha224256/4
rep movsd
inc [con.session_id_prefix]
invoke sha256_update, con.temp_ctx, con.session_id_prefix, 32+1
invoke sha256_final, con.temp_ctx
mov edi, con.rx_enc_key
mov esi, con.temp_ctx
mov ecx, SHA256_HASH_SIZE/4
rep movsd
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)
call sha256_init
mov edx, [dh_K.length]
add edx, 4
mov esi, dh_K
call sha256_update
mov edx, 32
mov esi, dh_H
call sha256_update
mov edx, 1
mov esi, str_E
call sha256_update
mov edx, 32
mov esi, session_id
call sha256_update
mov edi, tx_int_key
call sha256_final
mov esi, con.k_h_ctx
mov edi, con.temp_ctx
mov ecx, sizeof.ctx_sha224256/4
rep movsd
inc [con.session_id_prefix]
invoke sha256_update, con.temp_ctx, con.session_id_prefix, 32+1
invoke sha256_final, con.temp_ctx
mov edi, con.tx_int_key
mov esi, con.temp_ctx
mov ecx, SHA256_HASH_SIZE/4
rep movsd
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)
call sha256_init
mov edx, [dh_K.length]
add edx, 4
mov esi, dh_K
call sha256_update
mov edx, 32
mov esi, dh_H
call sha256_update
mov edx, 1
mov esi, str_F
call sha256_update
mov edx, 32
mov esi, session_id
call sha256_update
mov edi, rx_int_key
call sha256_final
mov esi, con.k_h_ctx
mov edi, con.temp_ctx
mov ecx, sizeof.ctx_sha224256/4
rep movsd
inc [con.session_id_prefix]
invoke sha256_update, con.temp_ctx, con.session_id_prefix, 32+1
invoke sha256_final, con.temp_ctx
mov edi, con.rx_int_key
mov esi, con.temp_ctx
mov ecx, SHA256_HASH_SIZE/4
rep movsd
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
stdcall ssh_recv_packet, [socketnum], rx_buffer, BUFFERSIZE, 0
stdcall ssh_recv_packet, con, 0
cmp eax, -1
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
DEBUGF 1, "Received New Keys\n"
DEBUGF 2, "Received New Keys\n"
;-------------------------------
; >> 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
ret
.socket_err:
DEBUGF 2, "Socket error during key exchange!\n"
DEBUGF 3, "Socket error during key exchange!\n"
mov eax, 1
ret
.proto_err:
DEBUGF 2, "Protocol error during key exchange!\n"
DEBUGF 3, "Protocol error during key exchange!\n"
mov eax, 2
ret
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
.mod_zero:
DEBUGF 1, "modexp with modulo 0\n"
DEBUGF 3, "modexp with modulo 0\n"
; if mod is zero, result = 0
stdcall mpint_zero, [dst]
ret
.exp_zero:
DEBUGF 1, "modexp with exponent 0\n"
DEBUGF 3, "modexp with exponent 0\n"
; if exponent is zero, result = 1
stdcall mpint_zero, [dst]
mov eax, [dst]
@ -556,7 +556,7 @@ proc mpint_modexp uses edi eax ebx ecx, dst, base, exp, mod
ret
.invalid:
DEBUGF 1, "modexp: Invalid input!\n"
DEBUGF 3, "modexp: Invalid input!\n"
ret
endp

View File

@ -18,7 +18,7 @@
format binary as ""
__DEBUG__ = 1
__DEBUG_LEVEL__ = 1
__DEBUG_LEVEL__ = 2 ; 1: Extreme debugging, 2: Debugging, 3: Errors only
BUFFERSIZE = 4096
MAX_BITS = 8192
@ -33,16 +33,17 @@ use32
dd i_end ; initialized size
dd mem+4096 ; required memory
dd mem+4096 ; stack pointer
dd hostname ; parameters
dd params ; parameters
dd 0 ; path
include '../../macros.inc'
;include '../../struct.inc'
purge mov,add,sub
include '../../proc32.inc'
include '../../dll.inc'
include '../../debug-fdo.inc'
include '../../network.inc'
;include '../../develop/libraries/libcrash/trunk/libcrash.inc'
include '../../develop/libraries/libcrash/trunk/libcrash.inc'
include 'mcodes.inc'
include 'ssh_transport.inc'
@ -53,7 +54,7 @@ include 'random.inc'
include 'aes256.inc'
include 'aes256-ctr.inc'
include 'aes256-cbc.inc'
include '../../fs/kfar/trunk/kfar_arc/sha256.inc'
include 'hmac_sha256.inc'
; macros for network byte order
macro dd_n op {
@ -68,24 +69,120 @@ macro dw_n op {
(((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:
mcall 68, 11 ; Init heap
DEBUGF 1, "SSH: Loading libraries\n"
DEBUGF 2, "SSH: Loading libraries\n"
stdcall dll.Load, @IMPORT
test eax, eax
jnz exit
DEBUGF 1, "SSH: Init PRNG\n"
DEBUGF 2, "SSH: Init PRNG\n"
call init_random
DEBUGF 1, "SSH: Init Console\n"
DEBUGF 2, "SSH: Init Console\n"
invoke con_start, 1
invoke con_init, 80, 25, 80, 25, title
; Check for parameters
cmp byte[hostname], 0
jne resolve
; Check for parameters TODO
; cmp byte[params], 0
; jne resolve
main:
invoke con_cls
@ -96,7 +193,7 @@ prompt:
; write prompt
invoke con_write_asciiz, str2
; read string
mov esi, hostname
mov esi, con.hostname
invoke con_gets, esi, 256
; check for exit
test eax, eax
@ -105,10 +202,11 @@ prompt:
jz done
resolve:
mov [sockaddr1.port], 22 shl 8
mov [con.sockaddr], AF_INET4
mov [con.port], 22 shl 8
; delete terminating '\n'
mov esi, hostname
mov esi, con.hostname
@@:
lodsb
cmp al, ':'
@ -137,14 +235,14 @@ resolve:
.port_done:
xchg bl, bh
mov [sockaddr1.port], bx
mov [con.port], bx
.done:
; resolve name
push esp ; reserve stack place
push esp
invoke getaddrinfo, hostname, 0, 0
invoke getaddrinfo, con.hostname, 0, 0
pop esi
; test for error
test eax, eax
@ -152,7 +250,7 @@ resolve:
invoke con_cls
invoke con_write_asciiz, str3
invoke con_write_asciiz, hostname
invoke con_write_asciiz, con.hostname
; write results
invoke con_write_asciiz, str8
@ -160,7 +258,7 @@ resolve:
; convert IP address to decimal notation
mov eax, [esi+addrinfo.ai_addr]
mov eax, [eax+sockaddr_in.sin_addr]
mov [sockaddr1.ip], eax
mov [con.ip], eax
invoke inet_ntoa, eax
; write result
invoke con_write_asciiz, eax
@ -176,47 +274,56 @@ resolve:
mcall socket, AF_INET4, SOCK_STREAM, 0
cmp eax, -1
jz socket_err
mov [socketnum], eax
mov [con.socketnum], eax
; Connect
mcall connect, [socketnum], sockaddr1, 18
DEBUGF 2, "Connecting to server\n"
mcall connect, [con.socketnum], con.sockaddr, 18
test eax, eax
jnz socket_err
; Start calculating hash meanwhile
call sha256_init
; Start calculating hash
invoke sha256_init, con.temp_ctx
; HASH: string V_C, the client's version string (CR and NL excluded)
mov esi, ssh_ident_ha
mov edx, ssh_ident.length+4-2
call sha256_update
invoke sha256_update, con.temp_ctx, ssh_ident_ha, ssh_ident.length+4-2
; Send our identification string
DEBUGF 1, "Sending ID string\n"
mcall send, [socketnum], ssh_ident, ssh_ident.length, 0
; >> Send our identification string
DEBUGF 2, "Sending ID string\n"
mcall send, [con.socketnum], ssh_ident, ssh_ident.length, 0
cmp eax, -1
je socket_err
; Check protocol version of server
mcall recv, [socketnum], rx_buffer, BUFFERSIZE, 0
; << Check protocol version of server
mcall recv, [con.socketnum], con.rx_buffer, BUFFERSIZE, 0
cmp eax, -1
je socket_err
DEBUGF 1, "Received ID string\n"
cmp dword[rx_buffer], "SSH-"
DEBUGF 2, "Received ID string\n"
cmp dword[con.rx_buffer], "SSH-"
jne proto_err
cmp dword[rx_buffer+4], "2.0-"
cmp dword[con.rx_buffer+4], "2.0-"
jne proto_err
; HASH: string V_S, the server's version string (CR and NL excluded)
lea edx, [eax+2]
sub eax, 2
bswap eax
mov [rx_buffer-4], eax
mov esi, rx_buffer-4
call sha256_update
mov dword[con.rx_buffer-4], eax
invoke sha256_update, con.temp_ctx, con.rx_buffer-4, edx
; Key Exchange init
DEBUGF 1, "Sending KEX init\n"
; >> Key Exchange init
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
call MBRandom
stosd
@ -226,32 +333,31 @@ resolve:
stosd
call MBRandom
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
je socket_err
; 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
movzx ebx, [tx_buffer+ssh_header.padding]
movzx ebx, [con.tx_buffer+ssh_packet_header.padding_length]
sub eax, ebx
dec eax
lea edx, [eax+4]
bswap eax
mov [tx_buffer+1], eax
mov esi, tx_buffer+1
call sha256_update
mov dword[con.tx_buffer+1], eax
invoke sha256_update, con.temp_ctx, con.tx_buffer+1, edx
; Check key exchange init of server
stdcall ssh_recv_packet, [socketnum], rx_buffer, BUFFERSIZE, 0
; << Check key exchange init of server
stdcall ssh_recv_packet, con, 0
cmp eax, -1
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
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
bswap eax
DEBUGF 1, "kex_algorithms: %s\n", esi
@ -295,38 +401,144 @@ resolve:
lodsb
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
mov eax, [rx_buffer+ssh_header.length]
movzx ebx, [rx_buffer+ssh_header.padding]
mov eax, dword[con.rx_buffer+ssh_packet_header.packet_length]
movzx ebx, [con.rx_buffer+ssh_packet_header.padding_length]
sub eax, ebx
dec eax
lea edx, [eax+4]
bswap eax
mov [rx_buffer+sizeof.ssh_header-5], eax
mov esi, rx_buffer+sizeof.ssh_header-5
call sha256_update
mov dword[con.rx_buffer+sizeof.ssh_packet_header-5], eax
invoke sha256_update, con.temp_ctx, con.rx_buffer+sizeof.ssh_packet_header-5, edx
; Exchange keys with the server
stdcall dh_gex
test eax, eax
jnz exit
; 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"
stdcall aes256_cbc_init, tx_iv
mov [tx_context], eax
stdcall aes256_set_decrypt_key, [tx_context], tx_enc_key
mov [encrypt_proc], aes256_cbc_encrypt
mov [tx_blocksize], 32
DEBUGF 2, "SSH: Setting encryption keys\n"
stdcall aes256_cbc_init, con.rx_iv
mov [con.rx_crypt_ctx_ptr], eax
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
mcall 18, 7
@ -340,13 +552,26 @@ mainloop:
test eax, 0x200 ; con window closed?
jnz exit
stdcall ssh_recv_packet, [socketnum], rx_buffer, BUFFERSIZE, 0
cmp eax, -1
je closed
stdcall ssh_recv_packet, con, 0
cmp eax, 0
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
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
pusha
@@:
@ -355,23 +580,22 @@ mainloop:
dec ecx
jnz @r
popa
lea edi, [esi + eax]
mov byte [edi], 0
invoke con_write_asciiz, esi
DEBUGF 1, "\n"
jmp mainloop
proto_err:
DEBUGF 1, "SSH: protocol error\n"
DEBUGF 3, "SSH: protocol error\n"
invoke con_write_asciiz, str7
jmp prompt
socket_err:
DEBUGF 1, "SSH: socket error %d\n", ebx
DEBUGF 3, "SSH: socket error %d\n", ebx
invoke con_write_asciiz, str6
jmp prompt
dns_error:
DEBUGF 1, "SSH: DNS error %d\n", eax
DEBUGF 3, "SSH: DNS error %d\n", eax
invoke con_write_asciiz, str5
jmp prompt
@ -386,8 +610,8 @@ closed:
done:
invoke con_exit, 1
exit:
DEBUGF 1, "SSH: Exiting\n"
mcall close, [socketnum]
DEBUGF 3, "SSH: Exiting\n"
mcall close, [con.socketnum]
mcall -1
@ -395,14 +619,8 @@ thread:
mcall 40, 0
.loop:
invoke con_getch2
mov [send_data], ax
xor esi, esi
inc esi
test al, al
jnz @f
inc esi
@@:
stdcall ssh_send_packet, [socketnum], send_data, 0
mov [ssh_channel_data+9], al
stdcall ssh_send_packet, con, ssh_channel_data, ssh_channel_data.length, 0
invoke con_get_flags
test eax, 0x200 ; con window closed?
@ -423,17 +641,12 @@ str8 db ' (',0
str9 db ')',10,0
str10 db 'Invalid hostname.',10,10,0
str11 db 10,'Remote host closed the connection.',10,10,0
sockaddr1:
dw AF_INET4
.port dw 0
.ip dd 0
rb 10
str12 db 'Enter username: ',0
ssh_ident_ha:
dd_n (ssh_ident.length-2)
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
ssh_kex:
@ -490,16 +703,75 @@ 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
; import
align 4
@IMPORT:
library network, 'network.obj', \
console, 'console.obj';, \
; libcrash, 'libcrash.obj'
console, 'console.obj', \
libcrash, 'libcrash.obj'
import network, \
getaddrinfo, 'getaddrinfo', \
@ -518,61 +790,23 @@ import console, \
con_write_string, 'con_write_string', \
con_get_flags, 'con_get_flags'
;import libcrash, \
; crash.hash, 'crash_hash'
import libcrash, \
sha256_init, 'sha256_init', \
sha256_update, 'sha256_update', \
sha256_final, 'sha256_final'
IncludeIGlobals
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
socketnum dd ?
rx_packet_length dd ? ;;;;;
rx_buffer: rb BUFFERSIZE+1
tx_buffer: rb BUFFERSIZE+1
params rb 1024
send_data dw ?
con ssh_connection
hostname rb 1024
; 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
; Temporary values ; To be removed FIXME
mpint_tmp rb MPINT_MAX_LEN+4
mem:

View File

@ -15,120 +15,181 @@
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>.
struct ssh_header
length dd ?
padding db ?
message_code db ?
struct ssh_packet_header
packet_length dd ? ; The length of the packet in bytes, not including 'mac' or the
; 'packet_length' field itself.
padding_length db ? ; Length of 'random padding' (bytes).
message_code db ? ; First byte of payload
ends
proc dummy_encrypt _key, _in, _out
ret
endp
proc ssh_recv_packet sock, buf, size, flags
proc ssh_recv_packet connection, flags
locals
bufferptr dd ?
remaining dd ?
padding dd ?
data_length dd ? ; Total length of packet without MAC
endl
DEBUGF 1, "ssh_recv_packet\n"
DEBUGF 2, "> "
; Receive first block (Read length, padding length, message code)
mcall recv, [sock], [buf], [rx_blocksize], [flags]
DEBUGF 1, "chunk = %u\n", eax
cmp eax, [rx_blocksize]
jne .fail ;;;;
mov ebx, [connection]
mov ecx, [ebx+ssh_connection.socketnum]
mov esi, [ebx+ssh_connection.rx_crypt_blocksize]
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]
movzx eax, [ebx+ssh_header.padding]
mov [padding], eax
mov eax, [ebx+ssh_header.length]
bswap eax ; length to little endian
mov [ebx+ssh_header.length], eax
DEBUGF 1, "ssh_recv_packet length = %u\n", eax
; Check data length
mov esi, [ebx+ssh_connection.rx_buffer.packet_length]
bswap esi ; convert length to little endian
mov [ebx+ssh_connection.rx_buffer.packet_length], esi
DEBUGF 1, "packet length=%u ", esi
cmp esi, BUFFERSIZE
ja .fail ; packet is too large
cmp eax, [size]
ja .fail ;;;;
; Calculate amount of remaining data
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]
add eax, 4
mov [remaining], eax
add ebx, [rx_blocksize]
mov [bufferptr], ebx
; Receive remaining data
lea edx, [ebx+ssh_connection.rx_buffer]
add edx, [ebx+ssh_connection.rx_crypt_blocksize]
mov ecx, [ebx+ssh_connection.socketnum]
mov edi, [flags]
.receive_loop:
mcall recv, [sock], [bufferptr], [remaining], 0
DEBUGF 1, "chunk = %u\n", eax
mcall recv
DEBUGF 1, "chunk = %u ", eax
cmp eax, 0
jbe .fail
add [bufferptr], eax
sub [remaining], eax
ja .receive_loop
add edx, eax
sub esi, eax
jnz .receive_loop
; .decrypt_loop:
; stdcall [decrypt_proc], [rx_context], [buf], [buf]
; ja .decrypt_loop
; Decrypt data
mov ebx, [connection]
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:
; TODO
; ja .hmac_loop
lea esi, [ebx+ssh_connection.rx_buffer]
add esi, [ebx+ssh_connection.rx_crypt_blocksize]
.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
mov eax, [buf]
movzx ebx, [eax+ssh_header.padding]
mov eax, [eax+ssh_header.length]
; Authenticate message
cmp [ebx+ssh_connection.rx_mac_proc], 0
je .mac_complete
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
DEBUGF 1, "ssh_recv_packet complete, usefull data length=%u\n", eax
DEBUGF 1, "useful data length=%u\n", eax
ret
.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
ret
endp
proc ssh_send_packet sock, buf, payloadsize, flags
proc ssh_send_packet connection, buf, payload_size, flags
locals
size dd ?
packet_size dd ?
endl
DEBUGF 1, "ssh_send_packet: size=%u\n", [payloadsize]
DEBUGF 2, "< "
mov eax, [payloadsize]
; Pad the packet with random data
mov eax, [payload_size]
inc eax ; padding length byte
lea edx, [eax+4] ; total packet size (without padding)
mov [size], edx
mov ebx, [tx_blocksize]
lea edx, [eax+4] ; total packet size (without padding and MAC)
mov [packet_size], edx
mov ecx, [connection]
mov ebx, [ecx+ssh_connection.tx_crypt_blocksize]
dec ebx
and edx, ebx
neg edx
add edx, [tx_blocksize]
add edx, [ecx+ssh_connection.tx_crypt_blocksize]
cmp edx, 4 ; minimum padding size
jae @f
add edx, [tx_blocksize]
add edx, [ecx+ssh_connection.tx_crypt_blocksize]
@@:
DEBUGF 1, "Padding %u bytes\n", edx
add [size], edx
DEBUGF 1, "padding %u bytes ", edx
add [packet_size], edx
add eax, edx
DEBUGF 1, "Total size: %u\n", eax
DEBUGF 1, "total size: %u ", eax
bswap eax
mov edi, tx_buffer
stosd
lea edi, [ecx+ssh_connection.tx_buffer]
stosd ; packet_length
mov al, dl
stosb
stosb ; padding_length
mov esi, [buf]
; cmp esi, edi
; je @f
mov ecx, [payloadsize]
mov ecx, [payload_size]
rep movsb
; @@:
mov ebx, edx
mov esi, edx
@ -146,8 +207,59 @@ endl
dec esi
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
endp