From time to time i faced with task how to transfer important data between servers securely (ie over ssl or something similar). I do not use passwords for remote access and do not have private keys on remote systems, so i can not use ssh for this purposes.
First i wanted to write about solution that i used few days ago (based on socat), but this solution is to complicated (later you will see why). I remembered that openssl can encrypt files with password and send result to STDOUT. While i was reading manual for openssl, i found that openssl can be used like netcat (s_server and s_client commands), unfortunately i did not found way how to use openssl for data transfer, because in session that you can establish openssl interprets some chars as commands (R for renegotiation for example), so if you want to use openssl client/server for data transfer, you need something like base64 encoding, but without control characters.
Solution with netcat and openssl:
First i created file for test (you can use data from STDIN, tar output for example, or transfer existing file):
client$ dd if=/dev/urandom of=/tmp/rand bs=1M count=10 10+0 records in 10+0 records out 10485760 bytes (10 MB) copied, 1.36697 seconds, 7.7 MB/s client$ md5sum /tmp/rand 10fe36edbbd48cde844ad1a2a29a8e0f /tmp/rand |
Next, prepare server side:
server$ read pass PasSwOrD server$ nc -l -p 6667|openssl aes-256-cbc -d -k $pass > /tmp/rand |
I used “read” to prevent save key into history file.
There “PasSwOrD” is your key, i use ssh to organize data transfer, so i did not worried that the traffic with key can be captured.
Next initiate transfer from client side:
client$ read pass PasSwOrD client$ cat /tmp/rand |openssl aes-256-cbc -salt -k $pass|nc -w1 server.remote 6667 |
Check sum:
server$ md5sum /tmp/rand 10fe36edbbd48cde844ad1a2a29a8e0f /tmp/rand |
Yeah! Your see? I transfered mah file.
UPDATE: [2019-05-26] Nowaday openssl has broken backward compatibility, so when you try to decrypt file you cold get error message like `digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:crypto/evp/evp_enc.c:535`, if so you need to add -md md5 or -md sha256 on both sides to openssl’s options.
Ok, next we will do it with socat.
First you need to generate client side and server side key and certificates, let’s do it on server:
server$ openssl genrsa -out server.key 2048 Generating RSA private key, 2048 bit long modulus ........+++ ......................................+++ e is 65537 (0x10001) |
Create certificate:
server$ openssl req -new -key server.key -x509 -days 108 -batch -out server.crt |
Create pem file:
server$ cat server.* > ./server.pem |
After that you will need to execute same commands on client side, but you will need to change filenames from “server” to “client”.
Next step is to exchange certificates between client and server (do it on both sides), they could be copy pasted:
server$ cat > ./client.crt << EOF -----BEGIN CERTIFICATE----- .... a lot of garbage .... -----END CERTIFICATE----- EOF |
Now we ready to transfer file, prepare server:
server$ socat openssl-listen:4433,reuseaddr,cert=./server.pem,cafile=./client.crt STDIO > /tmp/rand |
Client:
client$ socat STDIO openssl-connect:server.remote:4433,cert=./client.pem,cafile=./server.crt < /tmp/rand |
client$ md5sum /tmp/rand 10fe36edbbd48cde844ad1a2a29a8e0f /tmp/rand |
Gotcha!
As you can see, socat with TLS not a easy solution if you need just a transfer file, so i will recommend to use first solution. Also, in debian, you can use snakeoil key and cert, but it is your homework.
UPDATE:
I found how to use openssl for data transfer, only one problem, they did not close socket after EOF, so you need to stop it by hands:
Prepare server (this time i used snakeoil cert):
server% sudo openssl s_server -quiet -accept 4343 -cert /etc/ssl/certs/ssl-cert-snakeoil.pem -key /etc/ssl/private/ssl-cert-snakeoil.key < /tmp/test |
Run client:
client% md5sum /tmp/rnd 86246865b3932804979fdac48a99cebf /tmp/rnd client% openssl s_client -connect localhost:4343 -quiet > /tmp/rnd |
After data transfered, hit ^C on server side and check:
^C server% md5sum /tmp/test 86246865b3932804979fdac48a99cebf /tmp/test |
6 comments on “How to transfer data between hosts securely.”
I wrote before, openssl does not close connection after file will transfered. You need to press Ctrl-C, manualy.
With socat and nc ==> running OK
client% openssl s_client -connect server_IP:4343 -quiet > /tmp/rnd
depth=0 C = XX, L = Default City, O = Default Company Ltd
verify error:num=18:self signed certificate
verify return:1
depth=0 C = XX, L = Default City, O = Default Company Ltd
verify return:1
please advice ==> where is the server key,cert etc …. to send the file to server ?
If you use debian or ubuntu, you can use pregenerated certificate and key. Check /etc/ssl/certs/ssl-cert-snakeoil.pem and /etc/ssl/private/ssl-cert-snakeoil.key.
I use centos and there is no CA in that server. is it mandatory to setup the CA first or not ?
You can generate certificate and key, like i wrote above:
spirit@mfi:/tmp% openssl genrsa -out server.key 2048
Generating RSA private key, 2048 bit long modulus
……….+++
……………………………………………..+++
e is 65537 (0x10001)
spirit@mfi:/tmp% openssl req -new -key server.key -x509 -days 108 -batch -out server.crt
spirit@mfi:/tmp% echo ivanbayan.com > ./test
spirit@mfi:/tmp% openssl s_server -quiet -accept 4343 -cert /tmp/server.crt -key /tmp/server.key < /tmp/test spirit@mfi:/tmp% openssl s_client -connect localhost:4343 -quiet 2>/dev/null
ivanbayan.com
Quest completed. =)
still same ==> run from client :
# openssl s_client -connect SERVER_IP:4343 -quiet > test
depth=0 C = XX, L = Default City, O = Default Company Ltd
verify error:num=18:self signed certificate
verify return:1
depth=0 C = XX, L = Default City, O = Default Company Ltd
verify return:1
read:errno=0