diff --git a/programs/network/ssh/random.inc b/programs/network/ssh/random.inc index b048f619a..eb5862a64 100644 --- a/programs/network/ssh/random.inc +++ b/programs/network/ssh/random.inc @@ -36,7 +36,6 @@ endg proc init_random - mcall 26, 10 ; seed xor ecx, ecx ; make random numbers and put them into buffer @@: diff --git a/programs/network/ssh/seed.inc b/programs/network/ssh/seed.inc new file mode 100644 index 000000000..7de72523b --- /dev/null +++ b/programs/network/ssh/seed.inc @@ -0,0 +1,77 @@ +; seed.inc - Collect some entropy from KolibriOS system +; +; Copyright (C) 2021 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 . + + +align 4 +create_seed: + + push ebx edx + + mcall 3 ; System time + xor edx, eax + rol edx, 1 + mcall 14 ; Screen size + xor edx, eax + rol edx, 1 + mcall 18, 4 ; Idle time counter + xor edx, eax + rol edx, 1 + mcall 18, 5 ; CPU clock rate + xor edx, eax + rol edx, 1 + mcall 18, 7 ; Active window slot + xor edx, eax + rol edx, 1 + mcall 18, 16 ; Free RAM space + xor edx, eax + rol edx, 1 + mcall 18, 17 ; Total RAM space + xor edx, eax + rol edx, 1 + mcall 18, 21 ; Active window slot + xor edx, eax + rol edx, 1 + mcall 26, 10 ; High precision time counter + xor edx, eax + rol edx, 1 + xor edx, ebx + rol edx, 1 + mcall 37, 0 ; Screen coordinates of the cursor + xor edx, eax + rol edx, 1 + mcall 54, 0 ; Number of slots on the clipboard + xor edx, eax + rol edx, 1 + mcall 66, 3 ; Status of the keyboard control keys + xor edx, eax + rol edx, 1 + mcall 68, 0 ; Task switch counter + xor edx, eax + rol edx, 1 + mcall 74, 0x108 ; Network interface 1 TX bytes counter + xor edx, eax + rol edx, 1 + mcall 74, 0x109 ; Network interface 1 RX bytes counter + xor edx, eax + rol edx, 1 + mcall 76, 0x100 ; Network interface 1 MAC address + xor eax, ebx + xor eax, edx + + pop edx ebx + + ret \ No newline at end of file diff --git a/programs/network/ssh/ssh.asm b/programs/network/ssh/ssh.asm index be58d927e..e5dbaefc6 100644 --- a/programs/network/ssh/ssh.asm +++ b/programs/network/ssh/ssh.asm @@ -51,6 +51,7 @@ include 'ssh_transport.inc' include 'dh_gex.inc' include 'mpint.inc' +include 'seed.inc' include 'random.inc' include 'aes256.inc' @@ -118,8 +119,11 @@ struct ssh_connection rx_crypt_blocksize dd ? tx_crypt_blocksize dd ? - rx_padsize dd ? ; = Max(8, rx_crypt_blocksize) - tx_padsize dd ? ; = Max(8, tx_crypt_blocksize) +; Padding + +; rx_padsize dd ? ; = Max(8, rx_crypt_blocksize) + tx_pad_size dd ? ; = Max(8, tx_crypt_blocksize) + tx_pad_proc dd ? ; Message authentication @@ -189,6 +193,7 @@ start: jnz exit DEBUGF 2, "SSH: Init PRNG\n" + call create_seed call init_random DEBUGF 2, "SSH: Init Console\n" @@ -335,8 +340,9 @@ resolve: mov [con.tx_mac_proc], 0 mov [con.rx_mac_length], 0 mov [con.tx_mac_length], 0 - mov [con.rx_padsize], 8 ; minimum padsize - mov [con.tx_padsize], 8 +; mov [con.rx_padsize], 8 ; minimum padsize + mov [con.tx_pad_size], 8 + mov [con.tx_pad_proc], padding_zero DEBUGF 2, "Sending KEX init\n" mov edi, ssh_kex.cookie @@ -436,7 +442,7 @@ resolve: test eax, eax jnz exit -; Set keys +; Set keys and initialize transport subroutines DEBUGF 2, "SSH: Setting encryption keys\n" @@ -446,7 +452,7 @@ resolve: stdcall aes256_set_encrypt_key, eax, con.rx_enc_key mov [con.rx_crypt_proc], aes256_ctr_crypt mov [con.rx_crypt_blocksize], AES256_BLOCKSIZE - mov [con.rx_padsize], AES256_BLOCKSIZE +; mov [con.rx_pad_size], AES256_BLOCKSIZE stdcall aes256_ctr_init, con.tx_iv mov [con.tx_crypt_ctx_ptr], eax @@ -454,7 +460,9 @@ resolve: stdcall aes256_set_encrypt_key, eax, con.tx_enc_key mov [con.tx_crypt_proc], aes256_ctr_crypt mov [con.tx_crypt_blocksize], AES256_BLOCKSIZE - mov [con.tx_padsize], AES256_BLOCKSIZE + + mov [con.tx_pad_size], AES256_BLOCKSIZE + mov [con.tx_pad_proc], MBRandom stdcall hmac_sha256_setkey, con.rx_mac_ctx, con.rx_int_key, SHA256_HASH_SIZE mov [con.rx_mac_proc], hmac_sha256 @@ -464,6 +472,10 @@ resolve: mov [con.tx_mac_proc], hmac_sha256 mov [con.tx_mac_length], SHA256_HASH_SIZE +; Re-seed RNG for padding bytes + call create_seed + call init_random + ; TODO: erase all keys from memory and free the memory ; >> Request service (user-auth) @@ -778,7 +790,7 @@ str14 db 10, 27, '[?25h', 27, '[0m', 0 ssh_ident_ha: dd_n (ssh_ident.length-2) ssh_ident: - db "SSH-2.0-KolibriOS_SSH_0.03",13,10 + db "SSH-2.0-KolibriOS_SSH_0.04",13,10 .length = $ - ssh_ident ssh_kex: diff --git a/programs/network/ssh/ssh_transport.inc b/programs/network/ssh/ssh_transport.inc index cdbcc3b54..0fc978c66 100644 --- a/programs/network/ssh/ssh_transport.inc +++ b/programs/network/ssh/ssh_transport.inc @@ -24,6 +24,12 @@ struct ssh_packet_header message_code db ? ; First byte of payload ends +proc padding_zero + + xor eax, eax + ret + +endp proc ssh_recv_packet connection, flags @@ -127,14 +133,10 @@ endl 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] - @@: + add byte[ebx+ssh_connection.rx_seq+3], 1 ; Update sequence counter + adc byte[ebx+ssh_connection.rx_seq+2], 0 + adc byte[ebx+ssh_connection.rx_seq+1], 0 + adc byte[ebx+ssh_connection.rx_seq+0], 0 ; Return useful data length to the caller via eax register .got_all_data: @@ -166,56 +168,63 @@ locals endl DEBUGF 2, "< " -; Pad the packet with random data +; Check how many bytes we should pad 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_padsize] + mov ebx, [ecx+ssh_connection.tx_pad_size] dec ebx and edx, ebx neg edx - add edx, [ecx+ssh_connection.tx_padsize] - cmp edx, 4 ; minimum padding size - jae @f - add edx, [ecx+ssh_connection.tx_padsize] - @@: + add edx, [ecx+ssh_connection.tx_pad_size] + add edx, [ecx+ssh_connection.tx_pad_size] DEBUGF 1, "padding %u bytes ", edx - add [packet_size], edx + add [packet_size], edx ; total packet size with padding +; Start building the packet +; First comes the packet length, in network byte order ofcourse. add eax, edx DEBUGF 1, "total size: %u ", eax bswap eax lea edi, [ecx+ssh_connection.tx_buffer] - stosd ; packet_length + stosd +; Then the padding length mov al, dl - stosb ; padding_length + stosb +; And the actual payload bytes mov esi, [buf] mov ecx, [payload_size] rep movsb - mov ebx, edx +; Append the packet with #edx padding bytes. +; Since we must pad at least 8 bytes, we can always use DWORD writes. +; First do an (unaligned) write exactly following the data + dec edx mov esi, edx + shr esi, 2 ; number dwords + mov ebx, edx and ebx, 3 - jz @f - call MBRandom + inc ebx ; number bytes in first write (1-4) + mov edx, [connection] + call [edx+ssh_connection.tx_pad_proc] mov dword[edi], eax add edi, ebx +; Then, do as many aligned writes as nescessary + mov ebx, [connection] @@: - - shr esi, 2 - @@: - call MBRandom + call [ebx+ssh_connection.tx_pad_proc] stosd dec esi jnz @r -; Message authentication +; Append the packet with Message Authentication Code 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] + 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 @@ -229,16 +238,12 @@ endl 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] - @@: + add byte[edx+ssh_connection.tx_seq+3], 1 ; Update sequence counter + adc byte[edx+ssh_connection.tx_seq+2], 0 + adc byte[edx+ssh_connection.tx_seq+1], 0 + adc byte[edx+ssh_connection.tx_seq+0], 0 -; Encrypt data +; Now, encrypt everything but MAC cmp [edx+ssh_connection.tx_crypt_proc], 0 je .encrypt_complete lea esi, [edx+ssh_connection.tx_buffer]