forked from KolibriOS/kolibrios
Working encryption and HMAC for transport, use libcrash for sha256 (and more to come), placed connection variables in separate struct, fixed bug in aes256_cbc_decode where IV was wrong when in- and output buffer were the same.
git-svn-id: svn://kolibrios.org@6469 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
parent
1048443a57
commit
a70850fad6
@ -16,7 +16,7 @@
|
||||
; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
struct aes256_cbc_context aes256_context
|
||||
vector rb 16
|
||||
vector rb AES256_BLOCKSIZE
|
||||
ends
|
||||
|
||||
|
||||
@ -25,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
|
||||
|
@ -16,8 +16,8 @@
|
||||
; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
struct aes256_ctr_context aes256_context
|
||||
counter rb 16
|
||||
output rb 16 ; counter after aes_crypt
|
||||
counter rb AES256_BLOCKSIZE
|
||||
output rb AES256_BLOCKSIZE ; counter after aes_crypt
|
||||
ends
|
||||
|
||||
|
||||
@ -26,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
|
||||
|
@ -16,26 +16,13 @@
|
||||
; You should have received a copy of the GNU General Public License
|
||||
; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
|
@ -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
|
171
programs/network/ssh/hmac_sha256.inc
Normal file
171
programs/network/ssh/hmac_sha256.inc
Normal file
@ -0,0 +1,171 @@
|
||||
; hmac.inc - HMAC: Keyed-Hashing for Message Authentication
|
||||
;
|
||||
; Copyright (C) 2016 Denis Karpenko
|
||||
; Copyright (C) 2016 Jeffrey Amelynck
|
||||
;
|
||||
; This program is free software: you can redistribute it and/or modify
|
||||
; it under the terms of the GNU General Public License as published by
|
||||
; the Free Software Foundation, either version 3 of the License, or
|
||||
; (at your option) any later version.
|
||||
;
|
||||
; This program is distributed in the hope that it will be useful,
|
||||
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
; GNU General Public License for more details.
|
||||
;
|
||||
; You should have received a copy of the GNU General Public License
|
||||
; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
; Main concept:
|
||||
; To compute HMAC over the data `text' we perform
|
||||
; H(K XOR opad, H(K XOR ipad, text))
|
||||
|
||||
struct hmac_sha256_context
|
||||
hash rb SHA256_HASH_SIZE
|
||||
ipad_ctx ctx_sha224256
|
||||
opad_ctx ctx_sha224256
|
||||
ends
|
||||
|
||||
; We will precompute partial hashes of K XOR ipad and K XOR opad,
|
||||
; and store them in the context structure.
|
||||
|
||||
proc hmac_sha256_setkey ctx, key, key_length
|
||||
|
||||
locals
|
||||
k_temp rb SHA224256_BLOCK_SIZE
|
||||
endl
|
||||
|
||||
pusha
|
||||
|
||||
; input esi = key, ecx=key_length
|
||||
mov ecx, [key_length]
|
||||
cmp ecx, SHA224256_BLOCK_SIZE
|
||||
ja .hash_it
|
||||
; Key is smaller then or equal to blocksize,
|
||||
; copy key to ipad
|
||||
mov esi, [key]
|
||||
lea edi, [k_temp]
|
||||
rep movsb
|
||||
mov ecx, SHA224256_BLOCK_SIZE
|
||||
sub ecx, [key_length]
|
||||
jz .finish
|
||||
; append zeros to the key
|
||||
xor al, al
|
||||
rep stosb
|
||||
jmp .finish
|
||||
|
||||
; Given key is larger then key size, hash it
|
||||
.hash_it:
|
||||
invoke sha256_init, [ctx]
|
||||
invoke sha256_update, [ctx], [key], [key_length]
|
||||
invoke sha256_final, [ctx]
|
||||
mov esi, [ctx]
|
||||
lea edi, [k_temp]
|
||||
mov ecx, SHA256_HASH_SIZE/4
|
||||
rep movsd
|
||||
xor eax, eax
|
||||
mov ecx, (SHA224256_BLOCK_SIZE-SHA256_HASH_SIZE)/4
|
||||
rep stosd
|
||||
|
||||
.finish:
|
||||
; xor ipad buffer with 0x36363...
|
||||
lea esi, [k_temp]
|
||||
mov ecx, SHA224256_BLOCK_SIZE/4
|
||||
@@:
|
||||
xor dword[esi], 0x36363636 ; ipad constant
|
||||
add esi, 4
|
||||
dec ecx
|
||||
jnz @r
|
||||
|
||||
; Init our hash with k_xor_ipad
|
||||
mov ebx, [ctx]
|
||||
lea edi, [ebx+hmac_sha256_context.ipad_ctx]
|
||||
invoke sha256_init, edi
|
||||
|
||||
lea esi, [k_temp]
|
||||
DEBUGF 1, "HASH: "
|
||||
stdcall dump_hex, esi, SHA224256_BLOCK_SIZE/4
|
||||
|
||||
mov ebx, [ctx]
|
||||
lea edi, [ebx+hmac_sha256_context.ipad_ctx]
|
||||
invoke sha256_update, edi, esi, SHA224256_BLOCK_SIZE
|
||||
|
||||
; xor opad buffer with 0x5c5c5...
|
||||
lea esi, [k_temp]
|
||||
mov ecx, SHA224256_BLOCK_SIZE/4
|
||||
@@:
|
||||
xor dword[esi], 0x36363636 xor 0x5c5c5c5c ; opad constant
|
||||
add esi, 4
|
||||
dec ecx
|
||||
jnz @r
|
||||
|
||||
; Init our hash with k_xor_opad
|
||||
mov ebx, [ctx]
|
||||
lea edi, [ebx+hmac_sha256_context.opad_ctx]
|
||||
invoke sha256_init, edi
|
||||
|
||||
lea esi, [k_temp]
|
||||
DEBUGF 1, "HASH: "
|
||||
stdcall dump_hex, esi, SHA224256_BLOCK_SIZE/4
|
||||
|
||||
mov ebx, [ctx]
|
||||
lea edi, [ebx+hmac_sha256_context.opad_ctx]
|
||||
invoke sha256_update, edi, esi, SHA224256_BLOCK_SIZE
|
||||
|
||||
popa
|
||||
ret
|
||||
|
||||
endp
|
||||
|
||||
; Copy our pre-computed partial hashes to the stack, complete and finalize them.
|
||||
; TODO: prevent unnescessary copying of output hash
|
||||
; TODO: remove unnescessary pushing/popping
|
||||
|
||||
proc hmac_sha256 ctx, _data, _length
|
||||
|
||||
locals
|
||||
inner_ctx ctx_sha224256
|
||||
outer_ctx ctx_sha224256
|
||||
endl
|
||||
|
||||
pusha
|
||||
DEBUGF 1, "HMAC: "
|
||||
mov ebx, [_length]
|
||||
shr ebx, 2
|
||||
stdcall dump_hex, [_data], ebx
|
||||
|
||||
; Copy partial hashes of ipad and opad to our temporary buffers
|
||||
mov esi, [ctx]
|
||||
lea esi, [esi+hmac_sha256_context.ipad_ctx]
|
||||
lea edi, [inner_ctx]
|
||||
repeat (sizeof.ctx_sha224256)/4*2
|
||||
movsd
|
||||
end repeat
|
||||
|
||||
; Append provided data to inner hash and finalize
|
||||
lea ebx, [inner_ctx]
|
||||
invoke sha256_update, ebx, [_data], [_length]
|
||||
lea ebx, [inner_ctx]
|
||||
invoke sha256_final, ebx
|
||||
|
||||
DEBUGF 1, "Inner Hash: "
|
||||
lea esi, [inner_ctx.hash]
|
||||
stdcall dump_hex, esi, SHA256_HASH_SIZE/4
|
||||
|
||||
; Calculate outer hash
|
||||
lea ebx, [outer_ctx]
|
||||
lea esi, [inner_ctx.hash]
|
||||
invoke sha256_update, ebx, esi, SHA256_HASH_SIZE
|
||||
lea ebx, [outer_ctx]
|
||||
invoke sha256_final, ebx
|
||||
; Copy output hash to ctx structure ; FIXME
|
||||
lea esi, [outer_ctx.hash]
|
||||
mov edi, [ctx]
|
||||
repeat SHA256_HASH_SIZE/4
|
||||
movsd
|
||||
end repeat
|
||||
|
||||
popa
|
||||
ret
|
||||
|
||||
endp
|
@ -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
|
@ -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:
|
||||
|
@ -15,120 +15,181 @@
|
||||
; You should have received a copy of the GNU General Public License
|
||||
; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
struct ssh_header
|
||||
length dd ?
|
||||
padding db ?
|
||||
message_code db ?
|
||||
|
||||
struct ssh_packet_header
|
||||
packet_length dd ? ; The length of the packet in bytes, not including 'mac' or the
|
||||
; 'packet_length' field itself.
|
||||
padding_length db ? ; Length of 'random padding' (bytes).
|
||||
|
||||
message_code db ? ; First byte of payload
|
||||
ends
|
||||
|
||||
proc dummy_encrypt _key, _in, _out
|
||||
|
||||
ret
|
||||
endp
|
||||
|
||||
proc ssh_recv_packet sock, buf, size, flags
|
||||
proc ssh_recv_packet connection, flags
|
||||
|
||||
locals
|
||||
bufferptr dd ?
|
||||
remaining dd ?
|
||||
padding dd ?
|
||||
data_length dd ? ; Total length of packet without MAC
|
||||
endl
|
||||
|
||||
DEBUGF 1, "ssh_recv_packet\n"
|
||||
DEBUGF 2, "> "
|
||||
; Receive first block (Read length, padding length, message code)
|
||||
mcall recv, [sock], [buf], [rx_blocksize], [flags]
|
||||
DEBUGF 1, "chunk = %u\n", eax
|
||||
cmp eax, [rx_blocksize]
|
||||
jne .fail ;;;;
|
||||
mov ebx, [connection]
|
||||
mov ecx, [ebx+ssh_connection.socketnum]
|
||||
mov esi, [ebx+ssh_connection.rx_crypt_blocksize]
|
||||
lea edx, [ebx+ssh_connection.rx_buffer]
|
||||
mov edi, [flags]
|
||||
mcall recv
|
||||
DEBUGF 1, "chunk = %u ", eax
|
||||
mov ebx, [connection]
|
||||
cmp eax, [ebx+ssh_connection.rx_crypt_blocksize]
|
||||
jne .fail
|
||||
|
||||
; stdcall [decrypt_proc], [rx_context], [buf], [buf]
|
||||
; Decrypt first block
|
||||
cmp [ebx+ssh_connection.rx_crypt_proc], 0
|
||||
je @f
|
||||
pusha
|
||||
lea esi, [ebx+ssh_connection.rx_buffer]
|
||||
stdcall [ebx+ssh_connection.rx_crypt_proc], [ebx+ssh_connection.rx_crypt_ctx_ptr], esi, esi
|
||||
popa
|
||||
@@:
|
||||
|
||||
mov ebx, [buf]
|
||||
movzx eax, [ebx+ssh_header.padding]
|
||||
mov [padding], eax
|
||||
mov eax, [ebx+ssh_header.length]
|
||||
bswap eax ; length to little endian
|
||||
mov [ebx+ssh_header.length], eax
|
||||
DEBUGF 1, "ssh_recv_packet length = %u\n", eax
|
||||
; Check data length
|
||||
mov esi, [ebx+ssh_connection.rx_buffer.packet_length]
|
||||
bswap esi ; convert length to little endian
|
||||
mov [ebx+ssh_connection.rx_buffer.packet_length], esi
|
||||
DEBUGF 1, "packet length=%u ", esi
|
||||
cmp esi, BUFFERSIZE
|
||||
ja .fail ; packet is too large
|
||||
|
||||
cmp eax, [size]
|
||||
ja .fail ;;;;
|
||||
; Calculate amount of remaining data
|
||||
add esi, 4 ; Packet length field itself is not included in the count
|
||||
sub esi, [ebx+ssh_connection.rx_crypt_blocksize] ; Already received this amount of data
|
||||
add esi, [ebx+ssh_connection.rx_mac_length]
|
||||
jz .got_all_data
|
||||
|
||||
sub eax, [rx_blocksize]
|
||||
add eax, 4
|
||||
mov [remaining], eax
|
||||
add ebx, [rx_blocksize]
|
||||
mov [bufferptr], ebx
|
||||
; Receive remaining data
|
||||
lea edx, [ebx+ssh_connection.rx_buffer]
|
||||
add edx, [ebx+ssh_connection.rx_crypt_blocksize]
|
||||
mov ecx, [ebx+ssh_connection.socketnum]
|
||||
mov edi, [flags]
|
||||
.receive_loop:
|
||||
mcall recv, [sock], [bufferptr], [remaining], 0
|
||||
DEBUGF 1, "chunk = %u\n", eax
|
||||
mcall recv
|
||||
DEBUGF 1, "chunk = %u ", eax
|
||||
cmp eax, 0
|
||||
jbe .fail
|
||||
add [bufferptr], eax
|
||||
sub [remaining], eax
|
||||
ja .receive_loop
|
||||
add edx, eax
|
||||
sub esi, eax
|
||||
jnz .receive_loop
|
||||
|
||||
; .decrypt_loop:
|
||||
; stdcall [decrypt_proc], [rx_context], [buf], [buf]
|
||||
; ja .decrypt_loop
|
||||
; Decrypt data
|
||||
mov ebx, [connection]
|
||||
cmp [ebx+ssh_connection.rx_crypt_proc], 0
|
||||
je .decrypt_complete
|
||||
mov ecx, [ebx+ssh_connection.rx_buffer.packet_length]
|
||||
add ecx, 4 ; Packet_length field itself
|
||||
sub ecx, [ebx+ssh_connection.rx_crypt_blocksize] ; Already decrypted this amount of data
|
||||
jz .decrypt_complete
|
||||
|
||||
; .hmac_loop:
|
||||
; TODO
|
||||
; ja .hmac_loop
|
||||
lea esi, [ebx+ssh_connection.rx_buffer]
|
||||
add esi, [ebx+ssh_connection.rx_crypt_blocksize]
|
||||
.decrypt_loop:
|
||||
pusha
|
||||
stdcall [ebx+ssh_connection.rx_crypt_proc], [ebx+ssh_connection.rx_crypt_ctx_ptr], esi, esi
|
||||
popa
|
||||
add esi, [ebx+ssh_connection.rx_crypt_blocksize]
|
||||
sub ecx, [ebx+ssh_connection.rx_crypt_blocksize]
|
||||
jnz .decrypt_loop
|
||||
.decrypt_complete:
|
||||
|
||||
; Return usefull data length in eax
|
||||
mov eax, [buf]
|
||||
movzx ebx, [eax+ssh_header.padding]
|
||||
mov eax, [eax+ssh_header.length]
|
||||
; Authenticate message
|
||||
cmp [ebx+ssh_connection.rx_mac_proc], 0
|
||||
je .mac_complete
|
||||
lea esi, [ebx+ssh_connection.rx_seq]
|
||||
mov ecx, [ebx+ssh_connection.rx_buffer.packet_length]
|
||||
add ecx, 8 ; packet_length field itself + sequence number
|
||||
lea eax, [ebx+ssh_connection.rx_mac_ctx]
|
||||
mov edx, [ebx+ssh_connection.rx_buffer.packet_length]
|
||||
bswap edx ; convert length to big endian
|
||||
mov [ebx+ssh_connection.rx_buffer.packet_length], edx
|
||||
stdcall [ebx+ssh_connection.rx_mac_proc], eax, esi, ecx
|
||||
mov edx, [ebx+ssh_connection.rx_buffer.packet_length]
|
||||
bswap edx ; convert length to little endian
|
||||
mov [ebx+ssh_connection.rx_buffer.packet_length], edx
|
||||
|
||||
lea esi, [ebx+ssh_connection.rx_mac_ctx]
|
||||
lea edi, [ebx+ssh_connection.rx_buffer]
|
||||
add edi, [ebx+ssh_connection.rx_buffer.packet_length]
|
||||
add edi, 4
|
||||
mov ecx, [ebx+ssh_connection.rx_mac_length]
|
||||
shr ecx, 2
|
||||
repe cmpsd
|
||||
jne .mac_failed
|
||||
.mac_complete:
|
||||
inc byte[ebx+ssh_connection.rx_seq+3] ; Update sequence counter
|
||||
jnc @f
|
||||
inc byte[ebx+ssh_connection.rx_seq+2]
|
||||
jnc @f
|
||||
inc byte[ebx+ssh_connection.rx_seq+1]
|
||||
jnc @f
|
||||
inc byte[ebx+ssh_connection.rx_seq+0]
|
||||
@@:
|
||||
|
||||
; Return useful data length to the caller via eax register
|
||||
.got_all_data:
|
||||
mov eax, [ebx+ssh_connection.rx_buffer.packet_length]
|
||||
movzx ebx, [ebx+ssh_connection.rx_buffer.padding_length]
|
||||
sub eax, ebx
|
||||
DEBUGF 1, "ssh_recv_packet complete, usefull data length=%u\n", eax
|
||||
DEBUGF 1, "useful data length=%u\n", eax
|
||||
ret
|
||||
|
||||
.fail:
|
||||
DEBUGF 1, "ssh_recv_packet failed!\n"
|
||||
DEBUGF 3, "ssh_recv_packet failed!\n"
|
||||
mov eax, -1
|
||||
ret
|
||||
|
||||
.mac_failed:
|
||||
DEBUGF 3, "ssh_recv_packet MAC failed!\n"
|
||||
mov eax, -1
|
||||
ret
|
||||
|
||||
endp
|
||||
|
||||
|
||||
proc ssh_send_packet sock, buf, payloadsize, flags
|
||||
proc ssh_send_packet connection, buf, payload_size, flags
|
||||
|
||||
locals
|
||||
size dd ?
|
||||
packet_size dd ?
|
||||
endl
|
||||
DEBUGF 1, "ssh_send_packet: size=%u\n", [payloadsize]
|
||||
DEBUGF 2, "< "
|
||||
|
||||
mov eax, [payloadsize]
|
||||
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
|
||||
endp
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user