/programs/network/ssh/aes256-cbc.inc |
---|
16,7 → 16,7 |
; along with this program. If not, see <http://www.gnu.org/licenses/>. |
struct aes256_cbc_context aes256_context |
vector rb 16 |
vector rb AES256_BLOCKSIZE |
ends |
25,7 → 25,7 |
mcall 68, 12, sizeof.aes256_cbc_context |
; handle errors |
mov ecx, 16/4 |
mov ecx, AES256_BLOCKSIZE/4 |
mov esi, [_vector] |
lea edi, [eax + aes256_cbc_context.vector] |
rep movsd |
39,24 → 39,16 |
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,14 → 58,12 |
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 |
80,12 → 70,22 |
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] |
stdcall aes256_decrypt, eax, [_in], [_out] ; Key, in, out |
93,30 → 93,21 |
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 |
/programs/network/ssh/aes256-ctr.inc |
---|
16,8 → 16,8 |
; along with this program. If not, see <http://www.gnu.org/licenses/>. |
struct aes256_ctr_context aes256_context |
counter rb 16 |
output rb 16 ; counter after aes_crypt |
counter rb AES256_BLOCKSIZE |
output rb AES256_BLOCKSIZE ; counter after aes_crypt |
ends |
26,7 → 26,7 |
mcall 68, 12, sizeof.aes256_ctr_context |
; handle errors |
mov ecx, 16/4 |
mov ecx, AES256_BLOCKSIZE/4 |
mov esi, [_counter] |
lea edi, [eax + aes256_ctr_context.counter] |
rep movsd |
42,8 → 42,7 |
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 |
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 |
/programs/network/ssh/aes256.inc |
---|
17,26 → 17,13 |
; along with this program. If not, see <http://www.gnu.org/licenses/>. |
AES256_ROUNDS = 14 |
AES256_BLOCKSIZE = 16 |
struct aes256_context |
key rd 4*(AES256_ROUNDS+1) |
ends |
proc dump_128bit_hex _ptr |
pushad |
mov esi, [_ptr] |
mov ecx, 4 |
.next_dword: |
lodsd |
bswap eax |
DEBUGF 1,'%x',eax |
loop .next_dword |
popad |
ret |
endp |
proc aes256_set_encrypt_key _ctx, _userkey |
locals |
i dd ? |
48,30 → 35,11 |
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 |
jmp .while |
.done: |
DEBUGF 1,' \n' |
pop edi esi ebx |
ret |
endp |
266,8 → 233,7 |
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 |
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 |
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 |
stosd |
DEBUGF 1,'output : ' |
stdcall dump_128bit_hex, [_out] |
DEBUGF 1,'\n' |
stdcall dump_hex, [_out], 4 |
pop edi esi ebx |
ret |
/programs/network/ssh/dh_gex.inc |
---|
25,8 → 25,8 |
;---------------------------------------------- |
; >> 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 |
33,31 → 33,31 |
;--------------------------------------------- |
; << Parse Diffie-Hellman Group Exchange Group |
stdcall ssh_recv_packet, [socketnum], rx_buffer, BUFFERSIZE, 0 |
stdcall ssh_recv_packet, con, 0 |
cmp eax, -1 |
je .socket_err |
cmp [rx_buffer+ssh_header.message_code], SSH_MSG_KEX_DH_GEX_GROUP |
cmp [con.rx_buffer.message_code], SSH_MSG_KEX_DH_GEX_GROUP |
jne proto_err |
DEBUGF 1, "Received GEX group\n" |
DEBUGF 2, "Received GEX group\n" |
mov esi, rx_buffer+sizeof.ssh_header |
mov edi, dh_p |
mov esi, con.rx_buffer+sizeof.ssh_packet_header |
mov edi, con.dh_p |
DEBUGF 1, "DH modulus (p): " |
call mpint_to_little_endian |
stdcall mpint_print, dh_p |
stdcall mpint_print, con.dh_p |
DEBUGF 1, "DH base (g): " |
mov edi, dh_g |
mov edi, con.dh_g |
call mpint_to_little_endian |
stdcall mpint_print, dh_g |
stdcall mpint_print, con.dh_g |
;------------------------------------------- |
; >> Send Diffie-Hellman Group Exchange Init |
; generate a random number x, where 1 < x < (p-1)/2 |
mov edi, dh_x+4 |
mov [dh_x], DH_PRIVATE_KEY_SIZE/8 |
mov edi, con.dh_x+4 |
mov [con.dh_x], DH_PRIVATE_KEY_SIZE/8 |
mov ecx, DH_PRIVATE_KEY_SIZE/8/4 |
@@: |
push ecx |
71,7 → 71,7 |
shl eax, 1 |
jnc @f |
mov byte[edi], 0 |
inc dword[dh_x] |
inc dword[con.dh_x] |
@@: |
; Fill remaining bytes with zeros ; TO BE REMOVED ? |
82,28 → 82,28 |
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 |
110,58 → 110,54 |
;--------------------------------------------- |
; << Parse Diffie-Hellman Group Exchange Reply |
stdcall ssh_recv_packet, [socketnum], rx_buffer, BUFFERSIZE, 0 |
stdcall ssh_recv_packet, con, 0 |
cmp eax, -1 |
je .socket_err |
cmp [rx_buffer+ssh_header.message_code], SSH_MSG_KEX_DH_GEX_REPLY |
cmp [con.rx_buffer.message_code], SSH_MSG_KEX_DH_GEX_REPLY |
jne .proto_err |
DEBUGF 1, "Received GEX Reply\n" |
DEBUGF 2, "Received GEX Reply\n" |
;-------------------------------- |
; HASH: string K_S, the host key |
mov esi, rx_buffer+sizeof.ssh_header |
mov esi, con.rx_buffer+sizeof.ssh_packet_header |
mov edx, [esi] |
bswap edx |
add edx, 4 |
lea ebx, [esi+edx] |
push ebx |
call sha256_update |
invoke sha256_update, con.temp_ctx, esi, edx |
;-------------------------------------------------------------------------- |
; HASH: uint32 min, minimal size in bits of an acceptable group |
; uint32 n, preferred size in bits of the group the server will send |
; uint32 max, maximal size in bits of an acceptable group |
mov esi, ssh_gex_req+sizeof.ssh_header-ssh_header.message_code |
mov edx, 12 |
call sha256_update |
invoke sha256_update, con.temp_ctx, ssh_gex_req+sizeof.ssh_packet_header-ssh_packet_header.message_code, 12 |
;---------------------------- |
; HASH: mpint p, safe prime |
mov esi, dh_p |
mov esi, con.dh_p |
mov edi, mpint_tmp |
call mpint_to_big_endian |
lea edx, [eax+4] |
mov esi, mpint_tmp |
call sha256_update |
invoke sha256_update, con.temp_ctx, mpint_tmp, edx |
;---------------------------------------- |
; HASH: mpint g, generator for subgroup |
mov esi, dh_g |
mov esi, con.dh_g |
mov edi, mpint_tmp |
call mpint_to_big_endian |
lea edx, [eax+4] |
mov esi, mpint_tmp |
call sha256_update |
invoke sha256_update, con.temp_ctx, mpint_tmp, edx |
;--------------------------------------------------- |
; HASH: mpint e, exchange value sent by the client |
mov esi, tx_buffer+sizeof.ssh_header |
mov esi, con.tx_buffer+sizeof.ssh_packet_header |
mov edx, [esi] |
bswap edx |
add edx, 4 |
call sha256_update |
invoke sha256_update, con.temp_ctx, esi, edx |
;--------------------------------------------------- |
; HASH: mpint f, exchange value sent by the server |
169,254 → 165,206 |
mov edx, [esi] |
bswap edx |
add edx, 4 |
call sha256_update |
invoke sha256_update, con.temp_ctx, esi, edx |
pop esi |
mov edi, dh_f |
mov edi, con.dh_f |
call mpint_to_little_endian |
DEBUGF 1, "DH f: " |
stdcall mpint_print, dh_f |
stdcall mpint_print, con.dh_f |
mov edi, dh_signature |
mov edi, con.dh_signature |
call mpint_to_little_endian |
DEBUGF 1, "DH signature: " |
stdcall mpint_print, dh_signature |
stdcall mpint_print, con.dh_signature |
;-------------------------------------- |
; Calculate shared secret K = f^x mod p |
stdcall mpint_modexp, rx_buffer, dh_f, dh_x, dh_p |
stdcall mpint_length, rx_buffer |
stdcall mpint_modexp, con.rx_buffer, con.dh_f, con.dh_x, con.dh_p |
stdcall mpint_length, con.rx_buffer |
DEBUGF 1, "DH K: " |
stdcall mpint_print, rx_buffer |
stdcall mpint_print, con.rx_buffer |
; We always need it in big endian order, so store it as such. |
mov edi, dh_K |
mov esi, rx_buffer |
mov edi, con.dh_K |
mov esi, con.rx_buffer |
call mpint_to_big_endian |
mov [dh_K.length], eax |
mov [con.dh_K_length], eax |
;----------------------------------- |
; HASH: mpint K, the shared secret |
mov edx, [dh_K.length] |
mov edx, [con.dh_K_length] |
add edx, 4 |
mov esi, dh_K |
call sha256_update |
invoke sha256_update, con.temp_ctx, con.dh_K, edx |
;------------------------------- |
; Finalize the exchange hash (H) |
mov edi, dh_H |
call sha256_final |
invoke sha256_final, con.temp_ctx |
mov esi, con.temp_ctx.hash |
mov edi, con.dh_H |
mov ecx, SHA256_HASH_SIZE/4 |
rep movsd |
DEBUGF 1, "Exchange hash H: " |
stdcall dump_256bit_hex, dh_H |
stdcall dump_hex, con.dh_H, 8 |
; TODO: skip this block when re-keying |
mov esi, dh_H |
mov edi, session_id |
mov ecx, 32/4 |
mov esi, con.dh_H |
mov edi, con.session_id |
mov ecx, SHA256_HASH_SIZE/4 |
rep movsd |
;--------------- |
; Calculate keys |
; TODO: re-use partial hash of K and H |
; First, calculate partial hash of K and H so we can re-use it for every key. |
invoke sha256_init, con.k_h_ctx |
mov edx, [con.dh_K_length] |
add edx, 4 |
invoke sha256_update, con.k_h_ctx, con.dh_K, edx |
invoke sha256_update, con.k_h_ctx, con.dh_H, 32 |
;--------------------------------------------------------------- |
; Initial IV client to server: HASH(K || H || "A" || session_id) |
call sha256_init |
mov edx, [dh_K.length] |
add edx, 4 |
mov esi, dh_K |
call sha256_update |
mov edx, 32 |
mov esi, dh_H |
call sha256_update |
mov edx, 1 |
mov esi, str_A |
call sha256_update |
mov edx, 32 |
mov esi, session_id |
call sha256_update |
mov edi, tx_iv |
call sha256_final |
mov esi, con.k_h_ctx |
mov edi, con.temp_ctx |
mov ecx, sizeof.ctx_sha224256/4 |
rep movsd |
mov [con.session_id_prefix], 'A' |
invoke sha256_update, con.temp_ctx, con.session_id_prefix, 32+1 |
invoke sha256_final, con.temp_ctx.hash |
mov edi, con.tx_iv |
mov esi, con.temp_ctx |
mov ecx, SHA256_HASH_SIZE/4 |
rep movsd |
DEBUGF 1, "Remote IV: " |
stdcall dump_256bit_hex, tx_iv |
stdcall dump_hex, con.tx_iv, 8 |
;--------------------------------------------------------------- |
; Initial IV server to client: HASH(K || H || "B" || session_id) |
call sha256_init |
mov edx, [dh_K.length] |
add edx, 4 |
mov esi, dh_K |
call sha256_update |
mov edx, 32 |
mov esi, dh_H |
call sha256_update |
mov edx, 1 |
mov esi, str_B |
call sha256_update |
mov edx, 32 |
mov esi, session_id |
call sha256_update |
mov edi, rx_iv |
call sha256_final |
mov esi, con.k_h_ctx |
mov edi, con.temp_ctx |
mov ecx, sizeof.ctx_sha224256/4 |
rep movsd |
inc [con.session_id_prefix] |
invoke sha256_update, con.temp_ctx, con.session_id_prefix, 32+1 |
invoke sha256_final, con.temp_ctx |
mov edi, con.rx_iv |
mov esi, con.temp_ctx |
mov ecx, SHA256_HASH_SIZE/4 |
rep movsd |
DEBUGF 1, "Local IV: " |
stdcall dump_256bit_hex, rx_iv |
stdcall dump_hex, con.rx_iv, 8 |
;------------------------------------------------------------------- |
; Encryption key client to server: HASH(K || H || "C" || session_id) |
call sha256_init |
mov edx, [dh_K.length] |
add edx, 4 |
mov esi, dh_K |
call sha256_update |
mov edx, 32 |
mov esi, dh_H |
call sha256_update |
mov edx, 1 |
mov esi, str_C |
call sha256_update |
mov edx, 32 |
mov esi, session_id |
call sha256_update |
mov edi, tx_enc_key |
call sha256_final |
mov esi, con.k_h_ctx |
mov edi, con.temp_ctx |
mov ecx, sizeof.ctx_sha224256/4 |
rep movsd |
inc [con.session_id_prefix] |
invoke sha256_update, con.temp_ctx, con.session_id_prefix, 32+1 |
invoke sha256_final, con.temp_ctx |
mov edi, con.tx_enc_key |
mov esi, con.temp_ctx |
mov ecx, SHA256_HASH_SIZE/4 |
rep movsd |
DEBUGF 1, "Remote key: " |
stdcall dump_256bit_hex, tx_enc_key |
stdcall dump_hex, con.tx_enc_key, 8 |
;------------------------------------------------------------------- |
; Encryption key server to client: HASH(K || H || "D" || session_id) |
call sha256_init |
mov edx, [dh_K.length] |
add edx, 4 |
mov esi, dh_K |
call sha256_update |
mov edx, 32 |
mov esi, dh_H |
call sha256_update |
mov edx, 1 |
mov esi, str_D |
call sha256_update |
mov edx, 32 |
mov esi, session_id |
call sha256_update |
mov edi, rx_enc_key |
call sha256_final |
mov esi, con.k_h_ctx |
mov edi, con.temp_ctx |
mov ecx, sizeof.ctx_sha224256/4 |
rep movsd |
inc [con.session_id_prefix] |
invoke sha256_update, con.temp_ctx, con.session_id_prefix, 32+1 |
invoke sha256_final, con.temp_ctx |
mov edi, con.rx_enc_key |
mov esi, con.temp_ctx |
mov ecx, SHA256_HASH_SIZE/4 |
rep movsd |
DEBUGF 1, "Local key: " |
stdcall dump_256bit_hex, rx_enc_key |
stdcall dump_hex, con.rx_enc_key, 8 |
;------------------------------------------------------------------ |
; Integrity key client to server: HASH(K || H || "E" || session_id) |
call sha256_init |
mov edx, [dh_K.length] |
add edx, 4 |
mov esi, dh_K |
call sha256_update |
mov edx, 32 |
mov esi, dh_H |
call sha256_update |
mov edx, 1 |
mov esi, str_E |
call sha256_update |
mov edx, 32 |
mov esi, session_id |
call sha256_update |
mov edi, tx_int_key |
call sha256_final |
mov esi, con.k_h_ctx |
mov edi, con.temp_ctx |
mov ecx, sizeof.ctx_sha224256/4 |
rep movsd |
inc [con.session_id_prefix] |
invoke sha256_update, con.temp_ctx, con.session_id_prefix, 32+1 |
invoke sha256_final, con.temp_ctx |
mov edi, con.tx_int_key |
mov esi, con.temp_ctx |
mov ecx, SHA256_HASH_SIZE/4 |
rep movsd |
DEBUGF 1, "Remote Integrity key: " |
stdcall dump_256bit_hex, tx_int_key |
stdcall dump_hex, con.tx_int_key, 8 |
;------------------------------------------------------------------ |
; Integrity key server to client: HASH(K || H || "F" || session_id) |
call sha256_init |
mov edx, [dh_K.length] |
add edx, 4 |
mov esi, dh_K |
call sha256_update |
mov edx, 32 |
mov esi, dh_H |
call sha256_update |
mov edx, 1 |
mov esi, str_F |
call sha256_update |
mov edx, 32 |
mov esi, session_id |
call sha256_update |
mov edi, rx_int_key |
call sha256_final |
mov esi, con.k_h_ctx |
mov edi, con.temp_ctx |
mov ecx, sizeof.ctx_sha224256/4 |
rep movsd |
inc [con.session_id_prefix] |
invoke sha256_update, con.temp_ctx, con.session_id_prefix, 32+1 |
invoke sha256_final, con.temp_ctx |
mov edi, con.rx_int_key |
mov esi, con.temp_ctx |
mov ecx, SHA256_HASH_SIZE/4 |
rep movsd |
DEBUGF 1, "Local Integrity key: " |
stdcall dump_256bit_hex, rx_int_key |
stdcall dump_hex, con.rx_int_key, 8 |
;------------------------------------- |
; << Parse Diffie-Hellman New Keys MSG |
stdcall ssh_recv_packet, [socketnum], rx_buffer, BUFFERSIZE, 0 |
stdcall ssh_recv_packet, con, 0 |
cmp eax, -1 |
je .socket_err |
cmp [rx_buffer+ssh_header.message_code], SSH_MSG_NEWKEYS |
cmp [con.rx_buffer.message_code], SSH_MSG_NEWKEYS |
jne .proto_err |
DEBUGF 1, "Received New Keys\n" |
DEBUGF 2, "Received New Keys\n" |
;------------------------------- |
; >> Reply with New Keys message |
stdcall ssh_send_packet, [socketnum], ssh_new_keys, ssh_new_keys.length, 0 |
stdcall ssh_send_packet, con, ssh_new_keys, ssh_new_keys.length, 0 |
xor eax, eax |
ret |
.socket_err: |
DEBUGF 2, "Socket error during key exchange!\n" |
DEBUGF 3, "Socket error during key exchange!\n" |
mov eax, 1 |
ret |
.proto_err: |
DEBUGF 2, "Protocol error during key exchange!\n" |
DEBUGF 3, "Protocol error during key exchange!\n" |
mov eax, 2 |
ret |
endp |
proc dump_256bit_hex _ptr |
pushad |
mov esi, [_ptr] |
mov ecx, 8 |
.next_dword: |
lodsd |
bswap eax |
DEBUGF 1,'%x',eax |
loop .next_dword |
DEBUGF 1,'\n' |
popad |
ret |
endp |
iglobal |
str_A db 'A' |
str_B db 'B' |
str_C db 'C' |
str_D db 'D' |
str_E db 'E' |
str_F db 'F' |
endg |
/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 <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 |
/programs/network/ssh/mpint.inc |
---|
541,13 → 541,13 |
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 |
ret |
.invalid: |
DEBUGF 1, "modexp: Invalid input!\n" |
DEBUGF 3, "modexp: Invalid input!\n" |
ret |
endp |
/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 |
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 '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 |
(((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 |
; 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 |
jz done |
resolve: |
mov [sockaddr1.port], 22 shl 8 |
mov [con.sockaddr], AF_INET4 |
mov [con.port], 22 shl 8 |
; delete terminating '\n' |
mov esi, hostname |
mov esi, con.hostname |
@@: |
lodsb |
cmp al, ':' |
137,7 → 235,7 |
.port_done: |
xchg bl, bh |
mov [sockaddr1.port], bx |
mov [con.port], bx |
.done: |
144,7 → 242,7 |
; 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 |
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 |
; 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,35 → 274,34 |
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) |
211,12 → 308,22 |
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 |
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,39 → 401,145 |
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 |
push eax |
340,14 → 552,27 |
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 |
@@: |
lodsb |
355,23 → 580,22 |
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 |
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 |
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 |
str9 db ')',10,0 |
str10 db 'Invalid hostname.',10,10,0 |
str11 db 10,'Remote host closed the connection.',10,10,0 |
str12 db 'Enter username: ',0 |
sockaddr1: |
dw AF_INET4 |
.port dw 0 |
.ip dd 0 |
rb 10 |
ssh_ident_ha: |
dd_n (ssh_ident.length-2) |
ssh_ident: |
db "SSH-2.0-KolibriOS_SSH_0.01",13,10 |
db "SSH-2.0-KolibriOS_SSH_0.02",13,10 |
.length = $ - ssh_ident |
ssh_kex: |
490,16 → 703,75 |
.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 |
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 |
; Temporary values ; To be removed FIXME |
mpint_tmp rb MPINT_MAX_LEN+4 |
; Diffie Hellman variables |
dh_p dd ? |
rb MAX_BITS/8 |
dh_g dd ? |
rb MAX_BITS/8 |
dh_x dd ? |
rb MAX_BITS/8 |
dh_e dd ? |
rb MAX_BITS/8 |
dh_f dd ? |
rb MAX_BITS/8 |
dh_signature dd ? |
rb MAX_BITS/8 |
; Output from key exchange |
dh_K dd ? ; Shared Secret (Big endian) |
rb MAX_BITS/8 |
.length dd ? ; Length in little endian |
dh_H rb 32 ; Exchange Hash |
session_id rb 32 |
rx_iv rb 32 ; Rx initialisation vector |
tx_iv rb 32 ; Tx initialisation vector |
rx_enc_key rb 32 ; Rx encryption key |
tx_enc_key rb 32 ; Tx encryption key |
rx_int_key rb 32 ; Rx integrity key |
tx_int_key rb 32 ; Tx integrity key |
; Temporary values ; To be removed |
mpint_tmp rb MPINT_MAX_LEN+4 |
mem: |
/programs/network/ssh/ssh_transport.inc |
---|
15,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 connection, flags |
proc ssh_recv_packet sock, buf, size, flags |
locals |
bufferptr dd ? |
remaining dd ? |
padding dd ? |
data_length dd ? ; Total length of packet without MAC |
endl |
DEBUGF 1, "ssh_recv_packet\n" |
DEBUGF 2, "> " |
; Receive first block (Read length, padding length, message code) |
mcall recv, [sock], [buf], [rx_blocksize], [flags] |
DEBUGF 1, "chunk = %u\n", eax |
cmp eax, [rx_blocksize] |
jne .fail ;;;; |
mov ebx, [connection] |
mov ecx, [ebx+ssh_connection.socketnum] |
mov esi, [ebx+ssh_connection.rx_crypt_blocksize] |
lea edx, [ebx+ssh_connection.rx_buffer] |
mov edi, [flags] |
mcall recv |
DEBUGF 1, "chunk = %u ", eax |
mov ebx, [connection] |
cmp eax, [ebx+ssh_connection.rx_crypt_blocksize] |
jne .fail |
; stdcall [decrypt_proc], [rx_context], [buf], [buf] |
; Decrypt first block |
cmp [ebx+ssh_connection.rx_crypt_proc], 0 |
je @f |
pusha |
lea esi, [ebx+ssh_connection.rx_buffer] |
stdcall [ebx+ssh_connection.rx_crypt_proc], [ebx+ssh_connection.rx_crypt_ctx_ptr], esi, esi |
popa |
@@: |
mov ebx, [buf] |
movzx eax, [ebx+ssh_header.padding] |
mov [padding], eax |
mov eax, [ebx+ssh_header.length] |
bswap eax ; length to little endian |
mov [ebx+ssh_header.length], eax |
DEBUGF 1, "ssh_recv_packet length = %u\n", eax |
; Check data length |
mov esi, [ebx+ssh_connection.rx_buffer.packet_length] |
bswap esi ; convert length to little endian |
mov [ebx+ssh_connection.rx_buffer.packet_length], esi |
DEBUGF 1, "packet length=%u ", esi |
cmp esi, BUFFERSIZE |
ja .fail ; packet is too large |
cmp eax, [size] |
ja .fail ;;;; |
; Calculate amount of remaining data |
add esi, 4 ; Packet length field itself is not included in the count |
sub esi, [ebx+ssh_connection.rx_crypt_blocksize] ; Already received this amount of data |
add esi, [ebx+ssh_connection.rx_mac_length] |
jz .got_all_data |
sub eax, [rx_blocksize] |
add eax, 4 |
mov [remaining], eax |
add ebx, [rx_blocksize] |
mov [bufferptr], ebx |
; Receive remaining data |
lea edx, [ebx+ssh_connection.rx_buffer] |
add edx, [ebx+ssh_connection.rx_crypt_blocksize] |
mov ecx, [ebx+ssh_connection.socketnum] |
mov edi, [flags] |
.receive_loop: |
mcall recv, [sock], [bufferptr], [remaining], 0 |
DEBUGF 1, "chunk = %u\n", eax |
mcall recv |
DEBUGF 1, "chunk = %u ", eax |
cmp eax, 0 |
jbe .fail |
add [bufferptr], eax |
sub [remaining], eax |
ja .receive_loop |
add edx, eax |
sub esi, eax |
jnz .receive_loop |
; .decrypt_loop: |
; stdcall [decrypt_proc], [rx_context], [buf], [buf] |
; ja .decrypt_loop |
; Decrypt data |
mov ebx, [connection] |
cmp [ebx+ssh_connection.rx_crypt_proc], 0 |
je .decrypt_complete |
mov ecx, [ebx+ssh_connection.rx_buffer.packet_length] |
add ecx, 4 ; Packet_length field itself |
sub ecx, [ebx+ssh_connection.rx_crypt_blocksize] ; Already decrypted this amount of data |
jz .decrypt_complete |
; .hmac_loop: |
; TODO |
; ja .hmac_loop |
lea esi, [ebx+ssh_connection.rx_buffer] |
add esi, [ebx+ssh_connection.rx_crypt_blocksize] |
.decrypt_loop: |
pusha |
stdcall [ebx+ssh_connection.rx_crypt_proc], [ebx+ssh_connection.rx_crypt_ctx_ptr], esi, esi |
popa |
add esi, [ebx+ssh_connection.rx_crypt_blocksize] |
sub ecx, [ebx+ssh_connection.rx_crypt_blocksize] |
jnz .decrypt_loop |
.decrypt_complete: |
; Return usefull data length in eax |
mov eax, [buf] |
movzx ebx, [eax+ssh_header.padding] |
mov eax, [eax+ssh_header.length] |
; Authenticate message |
cmp [ebx+ssh_connection.rx_mac_proc], 0 |
je .mac_complete |
lea esi, [ebx+ssh_connection.rx_seq] |
mov ecx, [ebx+ssh_connection.rx_buffer.packet_length] |
add ecx, 8 ; packet_length field itself + sequence number |
lea eax, [ebx+ssh_connection.rx_mac_ctx] |
mov edx, [ebx+ssh_connection.rx_buffer.packet_length] |
bswap edx ; convert length to big endian |
mov [ebx+ssh_connection.rx_buffer.packet_length], edx |
stdcall [ebx+ssh_connection.rx_mac_proc], eax, esi, ecx |
mov edx, [ebx+ssh_connection.rx_buffer.packet_length] |
bswap edx ; convert length to little endian |
mov [ebx+ssh_connection.rx_buffer.packet_length], edx |
lea esi, [ebx+ssh_connection.rx_mac_ctx] |
lea edi, [ebx+ssh_connection.rx_buffer] |
add edi, [ebx+ssh_connection.rx_buffer.packet_length] |
add edi, 4 |
mov ecx, [ebx+ssh_connection.rx_mac_length] |
shr ecx, 2 |
repe cmpsd |
jne .mac_failed |
.mac_complete: |
inc byte[ebx+ssh_connection.rx_seq+3] ; Update sequence counter |
jnc @f |
inc byte[ebx+ssh_connection.rx_seq+2] |
jnc @f |
inc byte[ebx+ssh_connection.rx_seq+1] |
jnc @f |
inc byte[ebx+ssh_connection.rx_seq+0] |
@@: |
; Return useful data length to the caller via eax register |
.got_all_data: |
mov eax, [ebx+ssh_connection.rx_buffer.packet_length] |
movzx ebx, [ebx+ssh_connection.rx_buffer.padding_length] |
sub eax, ebx |
DEBUGF 1, "ssh_recv_packet complete, usefull data length=%u\n", eax |
DEBUGF 1, "useful data length=%u\n", eax |
ret |
.fail: |
DEBUGF 1, "ssh_recv_packet failed!\n" |
DEBUGF 3, "ssh_recv_packet failed!\n" |
mov eax, -1 |
ret |
.mac_failed: |
DEBUGF 3, "ssh_recv_packet MAC failed!\n" |
mov eax, -1 |
ret |
endp |
proc ssh_send_packet sock, buf, payloadsize, flags |
proc ssh_send_packet connection, buf, payload_size, flags |
locals |
size dd ? |
packet_size dd ? |
endl |
DEBUGF 1, "ssh_send_packet: size=%u\n", [payloadsize] |
DEBUGF 2, "< " |
mov eax, [payloadsize] |
; Pad the packet with random data |
mov eax, [payload_size] |
inc eax ; padding length byte |
lea edx, [eax+4] ; total packet size (without padding) |
mov [size], edx |
mov ebx, [tx_blocksize] |
lea edx, [eax+4] ; total packet size (without padding and MAC) |
mov [packet_size], edx |
mov ecx, [connection] |
mov ebx, [ecx+ssh_connection.tx_crypt_blocksize] |
dec ebx |
and edx, ebx |
neg edx |
add edx, [tx_blocksize] |
add edx, [ecx+ssh_connection.tx_crypt_blocksize] |
cmp edx, 4 ; minimum padding size |
jae @f |
add edx, [tx_blocksize] |
add edx, [ecx+ssh_connection.tx_crypt_blocksize] |
@@: |
DEBUGF 1, "Padding %u bytes\n", edx |
add [size], edx |
DEBUGF 1, "padding %u bytes ", edx |
add [packet_size], edx |
add eax, edx |
DEBUGF 1, "Total size: %u\n", eax |
DEBUGF 1, "total size: %u ", eax |
bswap eax |
mov edi, tx_buffer |
stosd |
lea edi, [ecx+ssh_connection.tx_buffer] |
stosd ; packet_length |
mov al, dl |
stosb |
stosb ; padding_length |
mov esi, [buf] |
; cmp esi, edi |
; je @f |
mov ecx, [payloadsize] |
mov ecx, [payload_size] |
rep movsb |
; @@: |
mov ebx, edx |
mov esi, edx |
146,8 → 207,59 |
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 |