Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 6469 → Rev 6468

/programs/network/ssh/hmac_sha256.inc
File deleted
/programs/network/ssh/mpint.inc
541,13 → 541,13
ret
 
.mod_zero:
DEBUGF 3, "modexp with modulo 0\n"
DEBUGF 1, "modexp with modulo 0\n"
; if mod is zero, result = 0
stdcall mpint_zero, [dst]
ret
 
.exp_zero:
DEBUGF 3, "modexp with exponent 0\n"
DEBUGF 1, "modexp with exponent 0\n"
; if exponent is zero, result = 1
stdcall mpint_zero, [dst]
mov eax, [dst]
556,7 → 556,7
ret
 
.invalid:
DEBUGF 3, "modexp: Invalid input!\n"
DEBUGF 1, "modexp: Invalid input!\n"
ret
 
endp
/programs/network/ssh/aes256-cbc.inc
16,7 → 16,7
; along with this program. If not, see <http://www.gnu.org/licenses/>.
 
struct aes256_cbc_context aes256_context
vector rb AES256_BLOCKSIZE
vector rb 16
ends
 
 
25,7 → 25,7
 
mcall 68, 12, sizeof.aes256_cbc_context
; handle errors
mov ecx, AES256_BLOCKSIZE/4
mov ecx, 16/4
mov esi, [_vector]
lea edi, [eax + aes256_cbc_context.vector]
rep movsd
39,16 → 39,24
push ebx esi edi
 
DEBUGF 1,'plain : '
stdcall dump_hex, [_in], 4
stdcall dump_128bit_hex, [_in]
DEBUGF 1,'\n'
 
mov edi, [_ctx]
lea edi, [edi + aes256_cbc_context.vector]
mov esi, [_in]
repeat AES256_BLOCKSIZE/4
lodsd
xor eax, [edi]
stosd
end repeat
lodsd
xor eax, [edi]
stosd
lodsd
xor eax, [edi]
stosd
lodsd
xor eax, [edi]
stosd
 
mov esi, [_ctx]
lea eax, [esi + aes256_cbc_context.key]
58,12 → 66,14
mov esi, [_out]
mov eax, [_ctx]
lea edi, [eax + aes256_cbc_context.vector]
repeat AES256_BLOCKSIZE/4
movsd
end repeat
movsd
movsd
movsd
 
DEBUGF 1,'cipher : '
stdcall dump_hex, [_out], 4
stdcall dump_128bit_hex, [_out]
DEBUGF 1,'\n\n'
 
pop edi esi ebx
ret
70,22 → 80,12
endp
 
proc aes256_cbc_decrypt _ctx, _in, _out
 
locals
temp_iv rb AES256_BLOCKSIZE
endl
 
push ebx esi edi
 
DEBUGF 1,'cipher : '
stdcall dump_hex, [_in], 4
stdcall dump_128bit_hex, [_in]
DEBUGF 1,'\n'
 
mov esi, [_in]
lea edi, [temp_iv]
repeat AES256_BLOCKSIZE/4
movsd
end repeat
 
mov esi, [_ctx]
lea eax, [esi + aes256_cbc_context.key]
stdcall aes256_decrypt, eax, [_in], [_out] ; Key, in, out
93,21 → 93,30
mov esi, [_ctx]
lea esi, [esi + aes256_cbc_context.vector]
mov edi, [_out]
repeat AES256_BLOCKSIZE/4
lodsd
xor eax, [edi]
stosd
end repeat
lodsd
xor eax, [edi]
stosd
lodsd
xor eax, [edi]
stosd
lodsd
xor eax, [edi]
stosd
 
lea esi, [temp_iv]
mov esi, [_in]
mov edi, [_ctx]
lea edi, [edi + aes256_cbc_context.vector]
repeat AES256_BLOCKSIZE/4
movsd
end repeat
movsd
movsd
movsd
 
DEBUGF 1,'plain : '
stdcall dump_hex, [_out], 4
stdcall dump_128bit_hex, [_out]
DEBUGF 1,'\n\n'
 
pop edi esi ebx
ret
/programs/network/ssh/aes256-ctr.inc
16,8 → 16,8
; along with this program. If not, see <http://www.gnu.org/licenses/>.
 
struct aes256_ctr_context aes256_context
counter rb AES256_BLOCKSIZE
output rb AES256_BLOCKSIZE ; counter after aes_crypt
counter rb 16
output rb 16 ; counter after aes_crypt
ends
 
 
26,7 → 26,7
 
mcall 68, 12, sizeof.aes256_ctr_context
; handle errors
mov ecx, AES256_BLOCKSIZE/4
mov ecx, 16/4
mov esi, [_counter]
lea edi, [eax + aes256_ctr_context.counter]
rep movsd
42,7 → 42,8
push ebx esi edi
 
DEBUGF 1,'plain : '
stdcall dump_hex, [_in], 4
stdcall dump_128bit_hex, [_in]
DEBUGF 1,'\n'
 
mov esi, [_ctx]
lea eax, [esi + aes256_ctr_context.key]
100,7 → 101,8
mov dword[esi + aes256_ctr_context.counter + 4*3], edx
 
DEBUGF 1,'cipher : '
stdcall dump_hex, [_out], 4
stdcall dump_128bit_hex, [_out]
DEBUGF 1,'\n\n'
 
pop edi esi ebx
ret
/programs/network/ssh/aes256.inc
17,13 → 17,26
; 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
i dd ?
35,11 → 48,30
 
mov esi, [_userkey]
lea edi, [ebx + aes256_context.key]
repeat 8
lodsd
bswap eax
stosd
end repeat
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
 
lea esi, [ebx + aes256_context.key]
 
144,6 → 176,7
jmp .while
 
.done:
DEBUGF 1,' \n'
pop edi esi ebx
ret
endp
233,7 → 266,8
push ebx esi edi
 
DEBUGF 1,'input : '
stdcall dump_hex, [_in], 4
stdcall dump_128bit_hex, [_in]
DEBUGF 1,'\n'
 
mov ebx, [_key]
mov esi, [_in]
629,7 → 663,8
stosd
 
DEBUGF 1,'output : '
stdcall dump_hex, [_out], 4
stdcall dump_128bit_hex, [_out]
DEBUGF 1,'\n'
 
pop edi esi ebx
ret
644,7 → 679,8
push ebx esi edi
 
DEBUGF 1,'input : '
stdcall dump_hex, [_in], 4
stdcall dump_128bit_hex, [_in]
DEBUGF 1,'\n'
 
mov ebx, [_key]
mov esi, [_in]
1037,7 → 1073,8
stosd
 
DEBUGF 1,'output : '
stdcall dump_hex, [_out], 4
stdcall dump_128bit_hex, [_out]
DEBUGF 1,'\n'
 
pop edi esi ebx
ret
/programs/network/ssh/dh_gex.inc
25,8 → 25,8
;----------------------------------------------
; >> Send Diffie-Hellman Group Exchange Request
 
DEBUGF 2, "Sending GEX\n"
stdcall ssh_send_packet, con, ssh_gex_req, ssh_gex_req.length, 0
DEBUGF 1, "Sending GEX\n"
stdcall ssh_send_packet, [socketnum], ssh_gex_req, ssh_gex_req.length, 0
cmp eax, -1
je .socket_err
 
33,31 → 33,31
;---------------------------------------------
; << Parse Diffie-Hellman Group Exchange Group
 
stdcall ssh_recv_packet, con, 0
stdcall ssh_recv_packet, [socketnum], rx_buffer, BUFFERSIZE, 0
cmp eax, -1
je .socket_err
 
cmp [con.rx_buffer.message_code], SSH_MSG_KEX_DH_GEX_GROUP
cmp [rx_buffer+ssh_header.message_code], SSH_MSG_KEX_DH_GEX_GROUP
jne proto_err
DEBUGF 2, "Received GEX group\n"
DEBUGF 1, "Received GEX group\n"
 
mov esi, con.rx_buffer+sizeof.ssh_packet_header
mov edi, con.dh_p
mov esi, rx_buffer+sizeof.ssh_header
mov edi, dh_p
DEBUGF 1, "DH modulus (p): "
call mpint_to_little_endian
stdcall mpint_print, con.dh_p
stdcall mpint_print, dh_p
 
DEBUGF 1, "DH base (g): "
mov edi, con.dh_g
mov edi, dh_g
call mpint_to_little_endian
stdcall mpint_print, con.dh_g
stdcall mpint_print, dh_g
 
;-------------------------------------------
; >> Send Diffie-Hellman Group Exchange Init
 
; generate a random number x, where 1 < x < (p-1)/2
mov edi, con.dh_x+4
mov [con.dh_x], DH_PRIVATE_KEY_SIZE/8
mov edi, dh_x+4
mov [dh_x], DH_PRIVATE_KEY_SIZE/8
mov ecx, DH_PRIVATE_KEY_SIZE/8/4
@@:
push ecx
71,7 → 71,7
shl eax, 1
jnc @f
mov byte[edi], 0
inc dword[con.dh_x]
inc dword[dh_x]
@@:
 
; Fill remaining bytes with zeros ; TO BE REMOVED ?
82,28 → 82,28
end if
 
DEBUGF 1, "DH x: "
stdcall mpint_length, con.dh_x;;;;;;;;;;;;;
stdcall mpint_print, con.dh_x
stdcall mpint_length, dh_x;;;;;;;;;;;;;
stdcall mpint_print, dh_x
 
; Compute e = g^x mod p
stdcall mpint_modexp, con.dh_e, con.dh_g, con.dh_x, con.dh_p
stdcall mpint_length, con.dh_e
stdcall mpint_modexp, dh_e, dh_g, dh_x, dh_p
stdcall mpint_length, dh_e
 
DEBUGF 1, "DH e: "
stdcall mpint_print, con.dh_e
stdcall mpint_print, dh_e
 
; Create group exchange init packet
mov edi, con.tx_buffer.message_code
mov edi, tx_buffer+ssh_header.message_code
mov al, SSH_MSG_KEX_DH_GEX_INIT
stosb
mov esi, con.dh_e
mov esi, dh_e
call mpint_to_big_endian
 
DEBUGF 2, "Sending GEX init\n"
mov ecx, dword[con.tx_buffer.message_code+1]
DEBUGF 1, "Sending GEX init\n"
mov ecx, dword[tx_buffer+ssh_header.message_code+1]
bswap ecx
add ecx, 5
stdcall ssh_send_packet, con, con.tx_buffer.message_code, ecx, 0
stdcall ssh_send_packet, [socketnum], tx_buffer+ssh_header.message_code, ecx, 0
cmp eax, -1
je .socket_err
 
110,54 → 110,58
;---------------------------------------------
; << Parse Diffie-Hellman Group Exchange Reply
 
stdcall ssh_recv_packet, con, 0
stdcall ssh_recv_packet, [socketnum], rx_buffer, BUFFERSIZE, 0
cmp eax, -1
je .socket_err
 
cmp [con.rx_buffer.message_code], SSH_MSG_KEX_DH_GEX_REPLY
cmp [rx_buffer+ssh_header.message_code], SSH_MSG_KEX_DH_GEX_REPLY
jne .proto_err
 
DEBUGF 2, "Received GEX Reply\n"
DEBUGF 1, "Received GEX Reply\n"
 
;--------------------------------
; HASH: string K_S, the host key
mov esi, con.rx_buffer+sizeof.ssh_packet_header
mov esi, rx_buffer+sizeof.ssh_header
mov edx, [esi]
bswap edx
add edx, 4
lea ebx, [esi+edx]
push ebx
invoke sha256_update, con.temp_ctx, esi, edx
call sha256_update
 
;--------------------------------------------------------------------------
; 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
invoke sha256_update, con.temp_ctx, ssh_gex_req+sizeof.ssh_packet_header-ssh_packet_header.message_code, 12
mov esi, ssh_gex_req+sizeof.ssh_header-ssh_header.message_code
mov edx, 12
call sha256_update
 
;----------------------------
; HASH: mpint p, safe prime
mov esi, con.dh_p
mov esi, dh_p
mov edi, mpint_tmp
call mpint_to_big_endian
lea edx, [eax+4]
invoke sha256_update, con.temp_ctx, mpint_tmp, edx
mov esi, mpint_tmp
call sha256_update
 
;----------------------------------------
; HASH: mpint g, generator for subgroup
mov esi, con.dh_g
mov esi, dh_g
mov edi, mpint_tmp
call mpint_to_big_endian
lea edx, [eax+4]
invoke sha256_update, con.temp_ctx, mpint_tmp, edx
mov esi, mpint_tmp
call sha256_update
 
;---------------------------------------------------
; HASH: mpint e, exchange value sent by the client
mov esi, con.tx_buffer+sizeof.ssh_packet_header
mov esi, tx_buffer+sizeof.ssh_header
mov edx, [esi]
bswap edx
add edx, 4
invoke sha256_update, con.temp_ctx, esi, edx
call sha256_update
 
;---------------------------------------------------
; HASH: mpint f, exchange value sent by the server
165,206 → 169,254
mov edx, [esi]
bswap edx
add edx, 4
invoke sha256_update, con.temp_ctx, esi, edx
call sha256_update
pop esi
 
mov edi, con.dh_f
mov edi, dh_f
call mpint_to_little_endian
 
DEBUGF 1, "DH f: "
stdcall mpint_print, con.dh_f
stdcall mpint_print, dh_f
 
mov edi, con.dh_signature
mov edi, dh_signature
call mpint_to_little_endian
 
DEBUGF 1, "DH signature: "
stdcall mpint_print, con.dh_signature
stdcall mpint_print, dh_signature
 
;--------------------------------------
; Calculate shared secret K = f^x mod p
stdcall mpint_modexp, con.rx_buffer, con.dh_f, con.dh_x, con.dh_p
stdcall mpint_length, con.rx_buffer
stdcall mpint_modexp, rx_buffer, dh_f, dh_x, dh_p
stdcall mpint_length, rx_buffer
 
DEBUGF 1, "DH K: "
stdcall mpint_print, con.rx_buffer
stdcall mpint_print, rx_buffer
 
; We always need it in big endian order, so store it as such.
mov edi, con.dh_K
mov esi, con.rx_buffer
mov edi, dh_K
mov esi, rx_buffer
call mpint_to_big_endian
mov [con.dh_K_length], eax
mov [dh_K.length], eax
 
;-----------------------------------
; HASH: mpint K, the shared secret
mov edx, [con.dh_K_length]
mov edx, [dh_K.length]
add edx, 4
invoke sha256_update, con.temp_ctx, con.dh_K, edx
mov esi, dh_K
call sha256_update
 
;-------------------------------
; Finalize the exchange hash (H)
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
mov edi, dh_H
call sha256_final
 
DEBUGF 1, "Exchange hash H: "
stdcall dump_hex, con.dh_H, 8
stdcall dump_256bit_hex, dh_H
 
; TODO: skip this block when re-keying
mov esi, con.dh_H
mov edi, con.session_id
mov ecx, SHA256_HASH_SIZE/4
mov esi, dh_H
mov edi, session_id
mov ecx, 32/4
rep movsd
 
;---------------
; Calculate keys
 
; First, calculate partial hash of K and H so we can re-use it for every key.
; TODO: re-use partial hash of K and H
 
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)
 
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
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
 
DEBUGF 1, "Remote IV: "
stdcall dump_hex, con.tx_iv, 8
stdcall dump_256bit_hex, tx_iv
 
;---------------------------------------------------------------
; Initial IV server to client: HASH(K || H || "B" || session_id)
 
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
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
 
DEBUGF 1, "Local IV: "
stdcall dump_hex, con.rx_iv, 8
stdcall dump_256bit_hex, rx_iv
 
;-------------------------------------------------------------------
; Encryption key client to server: HASH(K || H || "C" || session_id)
 
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
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
 
DEBUGF 1, "Remote key: "
stdcall dump_hex, con.tx_enc_key, 8
stdcall dump_256bit_hex, tx_enc_key
 
;-------------------------------------------------------------------
; Encryption key server to client: HASH(K || H || "D" || session_id)
 
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
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
 
DEBUGF 1, "Local key: "
stdcall dump_hex, con.rx_enc_key, 8
stdcall dump_256bit_hex, rx_enc_key
 
;------------------------------------------------------------------
; Integrity key client to server: HASH(K || H || "E" || session_id)
 
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
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
 
DEBUGF 1, "Remote Integrity key: "
stdcall dump_hex, con.tx_int_key, 8
stdcall dump_256bit_hex, tx_int_key
 
;------------------------------------------------------------------
; Integrity key server to client: HASH(K || H || "F" || session_id)
 
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
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
 
DEBUGF 1, "Local Integrity key: "
stdcall dump_hex, con.rx_int_key, 8
stdcall dump_256bit_hex, rx_int_key
 
;-------------------------------------
; << Parse Diffie-Hellman New Keys MSG
 
stdcall ssh_recv_packet, con, 0
stdcall ssh_recv_packet, [socketnum], rx_buffer, BUFFERSIZE, 0
cmp eax, -1
je .socket_err
 
cmp [con.rx_buffer.message_code], SSH_MSG_NEWKEYS
cmp [rx_buffer+ssh_header.message_code], SSH_MSG_NEWKEYS
jne .proto_err
 
DEBUGF 2, "Received New Keys\n"
DEBUGF 1, "Received New Keys\n"
 
;-------------------------------
; >> Reply with New Keys message
 
stdcall ssh_send_packet, con, ssh_new_keys, ssh_new_keys.length, 0
stdcall ssh_send_packet, [socketnum], ssh_new_keys, ssh_new_keys.length, 0
 
xor eax, eax
ret
 
.socket_err:
DEBUGF 3, "Socket error during key exchange!\n"
DEBUGF 2, "Socket error during key exchange!\n"
mov eax, 1
ret
 
.proto_err:
DEBUGF 3, "Protocol error during key exchange!\n"
DEBUGF 2, "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
/programs/network/ssh/ssh.asm
18,7 → 18,7
format binary as ""
 
__DEBUG__ = 1
__DEBUG_LEVEL__ = 2 ; 1: Extreme debugging, 2: Debugging, 3: Errors only
__DEBUG_LEVEL__ = 1
 
BUFFERSIZE = 4096
MAX_BITS = 8192
33,17 → 33,16
dd i_end ; initialized size
dd mem+4096 ; required memory
dd mem+4096 ; stack pointer
dd params ; parameters
dd hostname ; 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'
54,7 → 53,7
include 'aes256.inc'
include 'aes256-ctr.inc'
include 'aes256-cbc.inc'
include 'hmac_sha256.inc'
include '../../fs/kfar/trunk/kfar_arc/sha256.inc'
 
; macros for network byte order
macro dd_n op {
69,120 → 68,24
(((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 2, "SSH: Loading libraries\n"
DEBUGF 1, "SSH: Loading libraries\n"
stdcall dll.Load, @IMPORT
test eax, eax
jnz exit
 
DEBUGF 2, "SSH: Init PRNG\n"
DEBUGF 1, "SSH: Init PRNG\n"
call init_random
 
DEBUGF 2, "SSH: Init Console\n"
DEBUGF 1, "SSH: Init Console\n"
invoke con_start, 1
invoke con_init, 80, 25, 80, 25, title
 
; Check for parameters TODO
; cmp byte[params], 0
; jne resolve
; Check for parameters
cmp byte[hostname], 0
jne resolve
 
main:
invoke con_cls
193,7 → 96,7
; write prompt
invoke con_write_asciiz, str2
; read string
mov esi, con.hostname
mov esi, hostname
invoke con_gets, esi, 256
; check for exit
test eax, eax
202,11 → 105,10
jz done
 
resolve:
mov [con.sockaddr], AF_INET4
mov [con.port], 22 shl 8
mov [sockaddr1.port], 22 shl 8
 
; delete terminating '\n'
mov esi, con.hostname
mov esi, hostname
@@:
lodsb
cmp al, ':'
235,7 → 137,7
 
.port_done:
xchg bl, bh
mov [con.port], bx
mov [sockaddr1.port], bx
 
.done:
 
242,7 → 144,7
; resolve name
push esp ; reserve stack place
push esp
invoke getaddrinfo, con.hostname, 0, 0
invoke getaddrinfo, hostname, 0, 0
pop esi
; test for error
test eax, eax
250,7 → 152,7
 
invoke con_cls
invoke con_write_asciiz, str3
invoke con_write_asciiz, con.hostname
invoke con_write_asciiz, hostname
 
; write results
invoke con_write_asciiz, str8
258,7 → 160,7
; convert IP address to decimal notation
mov eax, [esi+addrinfo.ai_addr]
mov eax, [eax+sockaddr_in.sin_addr]
mov [con.ip], eax
mov [sockaddr1.ip], eax
invoke inet_ntoa, eax
; write result
invoke con_write_asciiz, eax
274,34 → 176,35
mcall socket, AF_INET4, SOCK_STREAM, 0
cmp eax, -1
jz socket_err
mov [con.socketnum], eax
mov [socketnum], eax
 
; Connect
DEBUGF 2, "Connecting to server\n"
mcall connect, [con.socketnum], con.sockaddr, 18
mcall connect, [socketnum], sockaddr1, 18
test eax, eax
jnz socket_err
 
; Start calculating hash
invoke sha256_init, con.temp_ctx
; Start calculating hash meanwhile
call sha256_init
; HASH: string V_C, the client's version string (CR and NL excluded)
invoke sha256_update, con.temp_ctx, ssh_ident_ha, ssh_ident.length+4-2
mov esi, ssh_ident_ha
mov edx, ssh_ident.length+4-2
call sha256_update
 
; >> Send our identification string
DEBUGF 2, "Sending ID string\n"
mcall send, [con.socketnum], ssh_ident, ssh_ident.length, 0
; Send our identification string
DEBUGF 1, "Sending ID string\n"
mcall send, [socketnum], ssh_ident, ssh_ident.length, 0
cmp eax, -1
je socket_err
 
; << Check protocol version of server
mcall recv, [con.socketnum], con.rx_buffer, BUFFERSIZE, 0
; Check protocol version of server
mcall recv, [socketnum], rx_buffer, BUFFERSIZE, 0
cmp eax, -1
je socket_err
 
DEBUGF 2, "Received ID string\n"
cmp dword[con.rx_buffer], "SSH-"
DEBUGF 1, "Received ID string\n"
cmp dword[rx_buffer], "SSH-"
jne proto_err
cmp dword[con.rx_buffer+4], "2.0-"
cmp dword[rx_buffer+4], "2.0-"
jne proto_err
 
; HASH: string V_S, the server's version string (CR and NL excluded)
308,22 → 211,12
lea edx, [eax+2]
sub eax, 2
bswap eax
mov dword[con.rx_buffer-4], eax
invoke sha256_update, con.temp_ctx, con.rx_buffer-4, edx
mov [rx_buffer-4], eax
mov esi, rx_buffer-4
call sha256_update
 
; >> 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"
; Key Exchange init
DEBUGF 1, "Sending KEX init\n"
mov edi, ssh_kex.cookie
call MBRandom
stosd
333,31 → 226,32
stosd
call MBRandom
stosd
stdcall ssh_send_packet, con, ssh_kex, ssh_kex.length, 0
stdcall ssh_send_packet, [socketnum], 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, dword[con.tx_buffer+ssh_packet_header.packet_length]
mov eax, [tx_buffer+ssh_header.length]
bswap eax
movzx ebx, [con.tx_buffer+ssh_packet_header.padding_length]
movzx ebx, [tx_buffer+ssh_header.padding]
sub eax, ebx
dec eax
lea edx, [eax+4]
bswap eax
mov dword[con.tx_buffer+1], eax
invoke sha256_update, con.temp_ctx, con.tx_buffer+1, edx
mov [tx_buffer+1], eax
mov esi, tx_buffer+1
call sha256_update
 
; << Check key exchange init of server
stdcall ssh_recv_packet, con, 0
; Check key exchange init of server
stdcall ssh_recv_packet, [socketnum], rx_buffer, BUFFERSIZE, 0
cmp eax, -1
je socket_err
 
cmp [con.rx_buffer.message_code], SSH_MSG_KEXINIT
cmp [rx_buffer+ssh_header.message_code], SSH_MSG_KEXINIT
jne proto_err
DEBUGF 2, "Received KEX init\n"
DEBUGF 1, "Received KEX init\n"
 
lea esi, [con.rx_buffer+sizeof.ssh_packet_header+16]
lea esi, [rx_buffer+sizeof.ssh_header+16]
lodsd
bswap eax
DEBUGF 1, "kex_algorithms: %s\n", esi
401,145 → 295,39
lodsb
DEBUGF 1, "KEX First Packet Follows: %u\n", al
 
; TODO: parse this structure and init procedures accordingly
; TODO
 
; HASH: string I_S, the payload of the servers's SSH_MSG_KEXINIT
mov eax, dword[con.rx_buffer+ssh_packet_header.packet_length]
movzx ebx, [con.rx_buffer+ssh_packet_header.padding_length]
mov eax, [rx_buffer+ssh_header.length]
movzx ebx, [rx_buffer+ssh_header.padding]
sub eax, ebx
dec eax
lea edx, [eax+4]
bswap eax
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
mov [rx_buffer+sizeof.ssh_header-5], eax
mov esi, rx_buffer+sizeof.ssh_header-5
call sha256_update
 
; 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 2, "SSH: Setting encryption keys\n"
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
 
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
push eax
552,27 → 340,14
test eax, 0x200 ; con window closed?
jnz exit
 
stdcall ssh_recv_packet, con, 0
cmp eax, 0
jbe closed
stdcall ssh_recv_packet, [socketnum], rx_buffer, BUFFERSIZE, 0
cmp eax, -1
je 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
 
lea esi, [con.rx_buffer.message_code+5+4]
mov esi, rx_buffer
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
@@:
lodsb
580,22 → 355,23
dec ecx
jnz @r
popa
DEBUGF 1, "\n"
lea edi, [esi + eax]
mov byte [edi], 0
invoke con_write_asciiz, esi
jmp mainloop
 
 
proto_err:
DEBUGF 3, "SSH: protocol error\n"
DEBUGF 1, "SSH: protocol error\n"
invoke con_write_asciiz, str7
jmp prompt
 
socket_err:
DEBUGF 3, "SSH: socket error %d\n", ebx
DEBUGF 1, "SSH: socket error %d\n", ebx
invoke con_write_asciiz, str6
jmp prompt
 
dns_error:
DEBUGF 3, "SSH: DNS error %d\n", eax
DEBUGF 1, "SSH: DNS error %d\n", eax
invoke con_write_asciiz, str5
jmp prompt
 
610,8 → 386,8
done:
invoke con_exit, 1
exit:
DEBUGF 3, "SSH: Exiting\n"
mcall close, [con.socketnum]
DEBUGF 1, "SSH: Exiting\n"
mcall close, [socketnum]
mcall -1
 
 
619,8 → 395,14
mcall 40, 0
.loop:
invoke con_getch2
mov [ssh_channel_data+9], al
stdcall ssh_send_packet, con, ssh_channel_data, ssh_channel_data.length, 0
mov [send_data], ax
xor esi, esi
inc esi
test al, al
jnz @f
inc esi
@@:
stdcall ssh_send_packet, [socketnum], send_data, 0
 
invoke con_get_flags
test eax, 0x200 ; con window closed?
641,12 → 423,17
str9 db ')',10,0
str10 db 'Invalid hostname.',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:
dd_n (ssh_ident.length-2)
ssh_ident:
db "SSH-2.0-KolibriOS_SSH_0.02",13,10
db "SSH-2.0-KolibriOS_SSH_0.01",13,10
.length = $ - ssh_ident
 
ssh_kex:
703,75 → 490,16
.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
include_debug_strings
 
 
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', \
790,23 → 518,61
con_write_string, 'con_write_string', \
con_get_flags, 'con_get_flags'
 
import libcrash, \
sha256_init, 'sha256_init', \
sha256_update, 'sha256_update', \
sha256_final, 'sha256_final'
;import libcrash, \
; crash.hash, 'crash_hash'
 
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
 
params rb 1024
socketnum dd ?
rx_packet_length dd ? ;;;;;
rx_buffer: rb BUFFERSIZE+1
tx_buffer: rb BUFFERSIZE+1
 
con ssh_connection
send_data dw ?
 
; Temporary values ; To be removed FIXME
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
mpint_tmp rb MPINT_MAX_LEN+4
 
 
mem:
/programs/network/ssh/ssh_transport.inc
15,181 → 15,120
; 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 ?
ends
 
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).
proc dummy_encrypt _key, _in, _out
 
message_code db ? ; First byte of payload
ends
ret
endp
 
proc ssh_recv_packet sock, buf, size, flags
 
proc ssh_recv_packet connection, flags
 
locals
data_length dd ? ; Total length of packet without MAC
bufferptr dd ?
remaining dd ?
padding dd ?
endl
 
DEBUGF 2, "> "
DEBUGF 1, "ssh_recv_packet\n"
; Receive first block (Read length, padding length, message code)
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
mcall recv, [sock], [buf], [rx_blocksize], [flags]
DEBUGF 1, "chunk = %u\n", eax
cmp eax, [rx_blocksize]
jne .fail ;;;;
 
; 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
@@:
; stdcall [decrypt_proc], [rx_context], [buf], [buf]
 
; 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
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
 
; 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
cmp eax, [size]
ja .fail ;;;;
 
; 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]
sub eax, [rx_blocksize]
add eax, 4
mov [remaining], eax
add ebx, [rx_blocksize]
mov [bufferptr], ebx
.receive_loop:
mcall recv
DEBUGF 1, "chunk = %u ", eax
mcall recv, [sock], [bufferptr], [remaining], 0
DEBUGF 1, "chunk = %u\n", eax
cmp eax, 0
jbe .fail
add edx, eax
sub esi, eax
jnz .receive_loop
add [bufferptr], eax
sub [remaining], eax
ja .receive_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
; .decrypt_loop:
; stdcall [decrypt_proc], [rx_context], [buf], [buf]
; ja .decrypt_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:
; .hmac_loop:
; TODO
; ja .hmac_loop
 
; 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]
; Return usefull data length in eax
mov eax, [buf]
movzx ebx, [eax+ssh_header.padding]
mov eax, [eax+ssh_header.length]
sub eax, ebx
DEBUGF 1, "useful data length=%u\n", eax
DEBUGF 1, "ssh_recv_packet complete, usefull data length=%u\n", eax
ret
 
.fail:
DEBUGF 3, "ssh_recv_packet failed!\n"
DEBUGF 1, "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 connection, buf, payload_size, flags
proc ssh_send_packet sock, buf, payloadsize, flags
 
locals
packet_size dd ?
size dd ?
endl
DEBUGF 2, "< "
DEBUGF 1, "ssh_send_packet: size=%u\n", [payloadsize]
 
; Pad the packet with random data
mov eax, [payload_size]
mov eax, [payloadsize]
inc eax ; padding length byte
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]
 
lea edx, [eax+4] ; total packet size (without padding)
mov [size], edx
mov ebx, [tx_blocksize]
dec ebx
and edx, ebx
neg edx
add edx, [ecx+ssh_connection.tx_crypt_blocksize]
add edx, [tx_blocksize]
cmp edx, 4 ; minimum padding size
jae @f
add edx, [ecx+ssh_connection.tx_crypt_blocksize]
add edx, [tx_blocksize]
@@:
DEBUGF 1, "padding %u bytes ", edx
add [packet_size], edx
DEBUGF 1, "Padding %u bytes\n", edx
add [size], edx
 
add eax, edx
DEBUGF 1, "total size: %u ", eax
DEBUGF 1, "Total size: %u\n", eax
bswap eax
lea edi, [ecx+ssh_connection.tx_buffer]
stosd ; packet_length
mov edi, tx_buffer
stosd
mov al, dl
stosb ; padding_length
stosb
mov esi, [buf]
mov ecx, [payload_size]
; cmp esi, edi
; je @f
mov ecx, [payloadsize]
rep movsb
; @@:
 
mov ebx, edx
mov esi, edx
207,59 → 146,8
dec esi
jnz @r
 
; 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
mcall send, [sock], tx_buffer, [size], [flags]
 
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
 
endp