📜 ⬆️ ⬇️

Crypto-correspondence for the distrustful

Caution: this post may cause a brief exacerbation of paranoia.

Hello! Do you believe in popular products for secure correspondence as I do not believe in them? For example, in browser-based cryptographs with client-side encryption, or in p2p-crypto-messengers?

In this post we will talk about the organization of secure communication between two interlocutors. It is addressed to the same incredulous people like me, so there will not be any code written by me or protocols and algorithms invented on my knees. Only the openssl library and the openssh toolkit will be used.
')
image



Introduction


In all the protected communication products that I met, I inevitably had a question of trust in their developers. I did not understand why, say, the author of the product still did not come and did not ask to weaken encryption or give a special javascript code to a client with a certain ip-address. You can say "this is impossible." Read, for example, the recent post Post service Lavabit forced to close , and, especially, the continuation of this story (Eng.), Past the Habr.

Unfortunately, people make mistakes. Take, for example, the service first on Google’s link for “secure chat” and “crypto chat” requests, which is called Cryptocat . About three months ago, an error was discovered in his code - because of the insufficiently good implementation of the random number generator, it was possible to decrypt group messages that were transmitted from October 17, 2011 to June 15, 2013, see Decryptocat . Moreover, at the beginning of 2013, Veracode conducted an audit of the code , which awarded it a “Security Quality Score of 100/100”, and this was not the only audit of the code during this period.

Therefore, the idea of ​​using libraries for communication, open algorithms and protocols with more than a decade history of searching for vulnerabilities has arisen. For me, as well as, I hope that for many of you - these are algorithms and protocols from openssl and openssh (which, by the way, uses openssl inside), namely: TLS, SSH, SHA1, AES256, RSA and DH. I will tell you by their example, but, of course, you can replace them with those that you personally trust; the basic idea will not change.

About OpenSSL


OpenSSL is an open source library that implements the SSL / TLS protocols. They are used every time you enter the site via HTTPS. About this was recently an article .

Here is a list of vulnerabilities found in OpenSSL for more than 10 years of analysis.

A partial list of programs that use OpenSSL: apache, nginx, squid, openvpn, openssh, ntp, dhcp, cups, syslog-ng, xorg-server, php, python, ruby, libevent, nodejs, curl, wget, links, lynx, socat, hostapd, wpa_supplicant, virtualbox, vmware-player, libreoffice, ffmpeg.

And quite a bit about TLS. TLS is a crypto protocol that allows you to establish secure connections. Now there are 3 versions of this protocol: 1.0, 1.1 and 1.2. They are described, respectively, in rfc 2246 , rfc 4346 and rfc 5246 . It's funny that they all end at 46. We will use version 1.0 because it came out in 1999 and no major vulnerabilities were found in it.

The protocol is very tricky. The process is very simplistic: the parties agree on a key for symmetric encryption and then use it. All messages are protected from change / substitution using a combination of a hash function with a secret key ( HMAC ). The protocol also provides for mutual authentication of the server and the client.

In addition to the full implementation of TLS, the OpenSSL library contains many cryptographic and mathematical algorithms and has a console interface.

Examples of using
1) Testing numbers for simplicity:
$ openssl prime 997 3E5 is prime 

2) Random number generation:
 $ openssl rand -hex 16 2871002e6f3cff937d066da9d3017197 

3) Checksum calculation:
 $ openssl sha1 /etc/passwd SHA1(/etc/passwd)= 8b74a9f1ddf496c02bc85e0e120bbb903d922276 

4) Encryption:
 $ openssl aes-256-cbc -k pass -in /etc/passwd <  > 


This is the interface that we will use for our task. Let's get down to business.

Simple option


The first interlocutor (with a “white” ip, let's call it “server”) performs:
 openssl s_server -accept 4433 -nocert -cipher ADH-AES256-SHA -tls1 -no_ticket 


The second interlocutor, the client, performs:
 openssl s_client -connect <host>:4433 -cipher ADH-AES256-SHA -tls1 -no_ticket 


What did we just do? The first command we launched tls 1.0-server, and the second - connected to it. Now you can communicate, all messages are encrypted with the AES256 algorithm, the encryption key is consistent using the Diffie-Hellman (DH) algorithm . Here is a great five minute video explaining its essence. The DH algorithm allows you to get a shared secret key using an unprotected communication channel.

This could be the end, but this approach has three problems:
1) It does not protect against man-in-the-middle attacks (MITM). The idea of ​​an attack is trivial - we become between the server and the client, the client thinks that he is connecting to the server, and in fact, he is connecting to us (to the attacker), and we are transmitting his traffic to the real server.
2) A white ip is required for at least one side.
3) Even if the data cannot be decrypted, “meta-information” about the connection is available: who connected with whom, when and how much data was transferred.

Defending against MITM


In order to protect MITM, you need the server to authenticate the client and the client the server. This is achieved using asymmetric encryption .

On the server and on the client, you need to generate a private RSA key and a public certificate.

On the server we perform:
 openssl genrsa -out server.key 2048 openssl req -new -key server.key -batch -days 3650 -x509 -out server.crt 


On the client:
 openssl genrsa -out client.key 2048 openssl req -new -key client.key -batch -days 3650 -x509 -out client.crt 


Here, 2048 is the number of bits in the private key module, 3650 is the certificate validity period in days.

Then the server must transfer its certificate (server.crt file) to the client, and the client (client.crt file) to the server. This is a weak point, because an attacker can replace the certificate at the time of the transfer (if he just reads it, that's okay). Therefore, it is better to transmit it using several channels (pastebin, email, skype, jabber, sms, voice over the phone, Russian post, steganography in photos of kittens on the blog, etc.). To transfer the certificate is enough once.

After that, the command to create a TLS server will look like this:
 openssl s_server -accept 4433 -cert server.crt -key server.key -Verify 0 -CAfile client.crt -cipher DHE-RSA-AES256-SHA -tls1 -no_ticket 


Connect to server:
 openssl s_client -connect <host>:4433 -cert client.crt -key client.key -verify 0 -CAfile server.crt -cipher DHE-RSA-AES256-SHA -tls1 -no_ticket 


Now the server and client will be able to authenticate each other.

Important: if authentication failed, then neither the server nor the client will disconnect the connection! They will only write about the error. Unfortunately, there is no key that would change this behavior, so you need to carefully look at the connection log. The error looks like this:
 verify error:num=18:self signed certificate 


We assume that we have decided the MITM problem, it remains to understand how to solve problems 2) and 3). This is where SSH will help.

SSH to the rescue


The SSH protocol is actively used when administering UNIX servers. It is somewhat similar to TLS, the transmitted data is also encrypted and signed. Both parties agree on the encryption key, for example, using the same DH algorithm.

In order to implement our insidious plan for the secure exchange of information, we need a server with SSH access and a white IP. To find such a server today is not particularly difficult. It is better to look for one that is connected to a lot and often.

One of the features of the protocol - it allows you to create secure tunnels. We will take advantage of this!

On the server we perform:
 ssh -c aes256-cbc -m hmac-sha1-96 -o KexAlgorithms=diffie-hellman-group-exchange-sha1 -R 4433:127.0.0.1:4433 user@sshhost nc -l -p 4433 -v 


Here, for extra peace of mind, we explicitly specify encryption, key exchange and hashing algorithms. The -R switch means that all connections to port 4433 of the ssh server will go to the encrypted ssh tunnel and go to the ssh client on the same port. If the user is set as the shell / sbin / nologin, then sometimes the use of the –N switch that tells the ssh client not to execute any commands on the server, but just to create a tunnel, helps.

On the client we perform:
 ssh -c aes256-cbc -m hmac-sha1-96 -o KexAlgorithms=diffie-hellman-group-exchange-sha1 -L 4433:127.0.0.1:4433 user@sshhost nc 127.0.0.1 4433 


Now, if the client connects to itself on 127.0.0.1 on port 4433, then the ssh client will connect through the secure tunnel to port 4433 of the remote machine, and from there, the data will be re-encrypted and sent through another tunnel to the server machine.

The nc command is a call to the popular netcat utility. It allows you to listen and set up tcp connections, as well as transmit data through them. When executing the commands above, it will seem to an outside observer that there is no tunnel and that these are just two ssh connections to the same server that are not connected to each other. Thus, we get a secure and relatively invisible connection.

What is wrong? That we cannot trust an ssh server! Theoretically, he can write decrypted data to his log at the time of their re-encryption, when they get from one tunnel to another.

SSH + OpenSSL or We have to go deeper


Now let our TLS-traffic over the chain of SSH-tunnels. If you are closely following, then the final sequence of commands will be as follows:

On server:
 #          ,   -  openssl genrsa -out server.key 2048 openssl req -new -key server.key -batch -days 3650 -x509 -out server.crt [ server.crt ] ssh -c aes256-cbc -m hmac-sha1-96 -o KexAlgorithms=diffie-hellman-group-exchange-sha1 -R 4433:127.0.0.1:4433 user@sshhost openssl s_server -accept 4433 -cert server.crt -key server.key -Verify 0 -CAfile client.crt -cipher DHE-RSA-AES256-SHA -tls1 -no_ticket [ ] [         ] [] 


On the client:
 #          ,   -  openssl genrsa -out client.key 2048 openssl req -new -key client.key -batch -days 3650 -x509 -out client.crt [ client.crt ] ssh -c aes256-cbc -m hmac-sha1-96 -o KexAlgorithms=diffie-hellman-group-exchange-sha1 -L 4433:127.0.0.1:4433 user@sshhost openssl s_client -connect localhost:4433 -cert client.crt -key client.key -verify 0 -CAfile server.crt -cipher DHE-RSA-AES256-SHA -tls1 -no_ticket [         ] [] 


In order for the ssh client to go to the background after connecting, you can specify the -Nf keys.

Total



So, without writing a single line of code and using only standard tools, we were able to correspond using an imperceptible connection that can work behind a NAT, a connection protected from listening, MITM attacks and message spoofing. In addition, it is relatively simple to set up - each interlocutor is required to perform only 4 commands and one file transfer for the first connection, and two commands for the subsequent ones. Yes, SSH access is still required to any server.

MiniFAQ


Q: Why not VPN?
A: VPN is a good solution. But it is difficult to configure, requires root rights on the server or trust to the server.

Q: Why not GnuPG?
A: GnuPG is also a good solution. But if you wish, the previously transmitted data can be decrypted by obtaining the private key (for example, together with a laptop).

Q: What makes you think that there are no vulnerabilities in OpenSSL?
A: I am sure they are there. OpenSSL personally seems to me subjectively reliable, so I told you by its example. You can use any other implementation that you personally trust.

Q: Do you promise that the commands are correct?
A: I do not promise! I advise you to check!

Q: How are you doing with cross-platform?
A: OpenSSL is cross-platform. SSH clients exist under most OSs.

Q: I want a web interface, why the console ?!
A: Web interface requires writing code. One small XSS vulnerability can cost important data. My logic is simple: no code - no errors.

Q: Error getaddrinfo: Name or service not known when executing the openssl s_server command
A: You probably have IPv6 turned off. Update openssl.

Q: Error gethostbyname failure when executing the openssl s_server command
A: Check the / etc / hosts file. The first name for the address 127.0.0.1 must be resolved.

Source: https://habr.com/ru/post/192184/


All Articles