curve25519 application for simple 'in place' protection of socket traffic

"bert hubert" <[email protected]> Sun, 28 Sep 2008 15:47:08 +0200
Newsgroups gmane.comp.djb.sigs
Message-ID <[email protected]>
Hi everybody,

I hope this is the right place to discuss CURVE25519!

For a small project, I needed a way to do almost 'drop in' encryption
over nonblocking sockets. This ruled out a lot of existing libraries.
Plus doing crypto is fun! Especially for an amateur like me.

So, I decided to try out CURVE25519 + AES128-CTR.

My goals:
       Perfect forward secrecy
       Complete shrouding of all traffic (including negotiation)
except against main in the middle
       Authentication of server identity
       1-bit-in-1-bit-out
       High performance
       Small code base

Non-goals for now:
       Preventing timing attacks
       Message authentication
       Rekeying

I've implemented the following, using CURVE25519 and (for now) AES-128:
- you create & connect the socket, or create & bind it

- clients & servers have static CURVE25519 keys which change rarely

- both ends call establishSecret(sock): writes a random public key to
the other end, reads a random public key
  use this to establish a shared 256-bit session secret
- only man in the middle can be aware of this shared session secret

- all communications from this point secured with this session secret:
  set AES-CTR1 counter to 0 for client, set its (truncated/hashed) key
to our session secret
  set AES-CTR1 counter to 2^127 for server, set its (truncated/hahed)
key to our session secret

- client sends its static public key over AES-CTR1, knows the server
static public key
- server reads the client static public key, sends nothing (knows
everything already)
- this leads to the static shared secret, known at client and server
  (server might well cache this, might be static for years)

- configure a second AES-CTR instance (AES-CTR2) with this shared
secret, client counter=0, server counter=2^127
- server encrypts a predetermined string (right now "Dan J. Bernstein"
:-)) with AES-CTR2 instance
- superencrypted using AES-CTR1 instance
- client decrypts both layers, checks if it received the predetermined string
- if correct, we've connected to the right server

- client (who has a lot more entropy we guess) creates a new AES key,
encrypts this using AES-CTR2 and AES-CTR1
  sends to server

- configure AES-CTR3 based on this key, client counter=0, server counter=2^127

- retire AES-CTR1 & 2
- from here on everything encrypted using AES-CTR3

Now my question - is the above a safe way to use CURVE25519? Do I need
a special hash to compress shared secrets to 128 bits?
Secondly, I use 2 CURVE25519 calls (worst case), and no less than 3
AES instances. Would there be a smarter way?

I'm a bit worried that there is no IV or nonce in there, but for now I
don't see a problem either - but what do I know.

I'd love to hear your throughts!