Simple Secure Channel
It’s been a while since I first heard about J-PAKE, a password authenticated key agreement (PAKE) protocol running on Diffie-Hellman groups. The setting is the following: two parties want to communicate securely, but they only have a shared password. After reading the paper, I was surprised what security guarantees can still be achieved. Basically, one can bootstrap a high-entropy shared key from a (potentially low-entropy) shared password, while still being secure against active and passive eavesdroppers. The shared password also implicitly authenticates both parties against each other. The paper even comes with a security proof, reducing the security of the J-PAKE protocol to some well-studied assumptions (DDH and some others).
There were a couple of use-cases that immediately came to my mind. Consider SSH. When you want to log in on a remote host using SSH, there are two things you have to know. The first thing is your password (assuming that you’re doing password authentication). The second thing is the remote host’s public key fingerprint. When you first log in on the remote host, you need to somehow verify the public key that it provided. Many users probably just accept it, hoping that they are not currently being attacked. This situation could be significantly improved by using the J-PAKE protocol: the public key fingerprint would not be necessary anymore, as authentication (and key exchange) would happen solely based on the user’s password.
Or consider a VPN solution. Instead of having to issue X.509 certificates for your road warriors, you could just give them user names and passwords for authentication. The passwords wouldn’t even have to contain much entropy: J-PAKE guarantees that there is exactly one attack against low-entropy passwords, namely on-line brute-force. That is, an attacker can exploit low-entropy passwords, but only by actively establishing a connection with one of the parties and then guessing the password. This is however easily mitigated by rate-limiting.
After all these thoughts, I decided to build a toy implementation of a cryptographic channel secured by J-PAKE. My attempt can be found on GitHub. Please be aware that this is probably not ready for production use and that I’m not making any security claims here. There might be implementation weaknesses, so please audit the code before you use it (as you do with any code you download from the Interwebs, right?).
My Implementation
There are a number of things I probably should mention. First of all: a secure channel doesn’t only need a key exchange protocol, but also an actual transport protocol. I’m using a symmetric cipher for providing security here (currently, AES and Twofish are supported). The cipher is run in EAX mode, so that confidentiality and authenticity of the transmitted data can be reduced to the security of the underlying block cipher.
The J-PAKE protocol is fully symmetric. That is, both parties behave exactly the same way. This implies that the shared password has to be present in plain text on both sides of the connection. On the client-side, this is the usual assumption. However, on the server-side, we typically don’t want to store plain text passwords. There is no easy way to solve this problem. Therefore, my implementation provides a central authentication service. This service is assumed to run in a secure environment where it is not possible to extract the stored passwords. So we have clients, regular services and the authentication service. The client directly communicates with the regular services. However, these services do not know any password. They therefore forward the client’s key exchange messages to the authentication service, which can handle them. When the authentication service accepts, it sends the master key for the connection to the service. The network connection between the service and then authenticator is secured using a special service password. That is, each service has their own password to authenticate against the authentication service.
As already mentioned, the J-PAKE protocol can handle low-entropy passwords. In order to prevent brute-force attacks, my implementation makes use of a rate-limiting scheme: Whenever an authentication attempt fails, the party that observes the failed attempt introduces an exponentially growing timeout until the next authentication attempt is started.
For further details regarding the internals, please refer to the Haddock documentation included in the source package.
Also, cheers to Joern, who contributed the OTP support.
Feedback is of course welcome.