diff --git a/programs/network/ssh/aes256-cbc.inc b/programs/network/ssh/aes256-cbc.inc
index cc1c5550f..88532c9ca 100644
--- a/programs/network/ssh/aes256-cbc.inc
+++ b/programs/network/ssh/aes256-cbc.inc
@@ -16,7 +16,7 @@
; along with this program. If not, see .
struct aes256_cbc_context aes256_context
- vector rb 16
+ vector rb AES256_BLOCKSIZE
ends
@@ -25,10 +25,10 @@ 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
+ rep movsd
; rep movsd is slow, but we don't care while init
pop edi esi ebx
@@ -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
diff --git a/programs/network/ssh/aes256-ctr.inc b/programs/network/ssh/aes256-ctr.inc
index 8db1379a6..17e79a5db 100644
--- a/programs/network/ssh/aes256-ctr.inc
+++ b/programs/network/ssh/aes256-ctr.inc
@@ -16,8 +16,8 @@
; along with this program. If not, see .
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,10 +26,10 @@ 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
+ rep movsd
; rep movsd is slow, but we don't care while init
pop edi esi ebx
@@ -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
diff --git a/programs/network/ssh/aes256.inc b/programs/network/ssh/aes256.inc
index 85aa74789..3d949fb8a 100644
--- a/programs/network/ssh/aes256.inc
+++ b/programs/network/ssh/aes256.inc
@@ -16,26 +16,13 @@
; You should have received a copy of the GNU General Public License
; along with this program. If not, see .
-AES256_ROUNDS = 14
+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
diff --git a/programs/network/ssh/dh_gex.inc b/programs/network/ssh/dh_gex.inc
index 434bc9071..35db9154d 100644
--- a/programs/network/ssh/dh_gex.inc
+++ b/programs/network/ssh/dh_gex.inc
@@ -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,352 +71,300 @@ 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 ?
if ((MAX_BITS-DH_PRIVATE_KEY_SIZE) > 0)
mov ecx, (MAX_BITS-DH_PRIVATE_KEY_SIZE)/8/4
xor eax, eax
- rep stosd
+ rep stosd
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
+; HASH: string K_S, the host key
+ 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
+; 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
;----------------------------
-; HASH: mpint p, safe prime
- mov esi, dh_p
+; HASH: mpint p, safe prime
+ 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
+; HASH: mpint g, generator for subgroup
+ 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
+; HASH: mpint e, exchange value sent by the client
+ 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
+; HASH: mpint f, exchange value sent by the server
mov esi, [esp]
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]
+; HASH: mpint K, the shared secret
+ 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
\ No newline at end of file
diff --git a/programs/network/ssh/hmac_sha256.inc b/programs/network/ssh/hmac_sha256.inc
new file mode 100644
index 000000000..61c2d0ffb
--- /dev/null
+++ b/programs/network/ssh/hmac_sha256.inc
@@ -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 .
+
+; 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
diff --git a/programs/network/ssh/mpint.inc b/programs/network/ssh/mpint.inc
index 4ae0aaaeb..3b729581f 100644
--- a/programs/network/ssh/mpint.inc
+++ b/programs/network/ssh/mpint.inc
@@ -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
\ No newline at end of file
diff --git a/programs/network/ssh/ssh.asm b/programs/network/ssh/ssh.asm
index 70f39fbcb..c8b3ddf1f 100644
--- a/programs/network/ssh/ssh.asm
+++ b/programs/network/ssh/ssh.asm
@@ -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, ':'
@@ -130,21 +228,21 @@ resolve:
jb hostname_error
cmp al, 9
ja hostname_error
- lea ebx, [ebx*4 + ebx]
+ lea ebx, [ebx*4+ebx]
shl ebx, 1
add ebx, eax
jmp .portloop
.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:
@@ -479,9 +692,9 @@ ssh_kex:
ssh_gex_req:
db SSH_MSG_KEX_DH_GEX_REQUEST
- dd_n 128 ; DH GEX min
- dd_n 256 ; DH GEX number of bits
- dd_n 512 ; DH GEX Max
+ dd_n 128 ; DH GEX min
+ dd_n 256 ; DH GEX number of bits
+ dd_n 512 ; DH GEX Max
.length = $ - ssh_gex_req
@@ -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:
diff --git a/programs/network/ssh/ssh_transport.inc b/programs/network/ssh/ssh_transport.inc
index a6bd7995e..6c1b8cf3d 100644
--- a/programs/network/ssh/ssh_transport.inc
+++ b/programs/network/ssh/ssh_transport.inc
@@ -15,120 +15,181 @@
; You should have received a copy of the GNU General Public License
; along with this program. If not, see .
-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]
- inc eax ; padding length byte
-
- lea edx, [eax+4] ; total packet size (without padding)
- mov [size], edx
- mov ebx, [tx_blocksize]
+; Pad the packet with random data
+ mov eax, [payload_size]
+ 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]
dec ebx
and edx, ebx
neg edx
- add edx, [tx_blocksize]
- cmp edx, 4 ; minimum padding size
+ 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
\ No newline at end of file
+endp
+