/nikea-kt

Non-Interactive Key Agreement

Primary LanguageKotlin

Nikea: Non-Interactive Key Agreement

Nikea provides end-to-end encrypted communication with offline handshake establishment.

Handshake keys are selected by a server, but clients verify them using trust-on-first-use signatures. This allows for one of the peers to be offline during establishment (and initial use) of the handshake.

Built using Libsodium bindings for Kotlin Multiplatform, it provides the following features:

  • Key Agreement using X25519 Elliptic Curve Diffie-Hellman
  • Perfect Forward Secrecy by using unique ephemeral keys in every handshake and a hash ratchet while active
  • Non-interactive handshake establishment even if the peer is offline (through pre-shared (ephemeral) keys)
  • Trust through a trust-on-first-use (tofu) signature verification mechanism for all peer keys (Ed25519)

Disclaimer: this is a personal project and not safe for use in production.

Motivation

From the Noise Protocol Framework spec:

Note that the second message's payload may contain a zero-length plaintext, but the payload ciphertext will still contain authentication data (such as an authentication tag or "synthetic IV"), since encryption is with an AEAD mode. The second message's payload can also be used to deliver certificates for the responder's static public key.

While this is advantageous for 0-RTT messages, it also has a disadvantage: both peers need to be online at the same time to exchange messages . This is because the k value of the CipherState is not meant to be persisted (i.e. ephemeral keys & handshake states are deleted when going offline).

Info

A noise KK handshake:

-> s
<- s
...
-> e, es, ee
<- e, ee, se

A nikea handshake:

-> s, e, identk, sig(s), sig(e)
<- s, e, itentk, sig(s), sig(e)
...
- es, ss, ee, se

All this library does is a 4x Diffie-Hellman key agreement plus some signature verification and hash ratcheting.

Since there is no negotiation or interactive communication to complete the handshake, there are no chaining keys (-> no hkdf), etc. A server acts as middleman and provides the keys & signatures, the clients just verify.

TODO

  • more negative tests
  • Config is of no use since the only one of each algorithm is implemented
    • Libsodium does not provide X448 or Ed448 and the Libsodium bindings do not provide Blake2b
  • how do WhatsApp/others persist the handshake state? Whitepaper

Comparison

Usage

Publish your library to the local Maven repository

Algorithms

Ed25519 & X25519

Ed25519 is a deterministic signature scheme & X25519 is an Elliptic Curve Diffie-Hellman (ECDH) key agreement scheme. Both use Curve25519 and are comparably fast and efficient. In both cases, the private keys are simply 32 random bytes (seed). From this, a public key for each keypair type can be generated. While public keys can be translated between both schemes, it's nonetheless recommended to use different private keys for both operations.

Ed25519 uses a curve which is birationally equivalent to Curve25519. More generally, the EdDSA (Edwards-curve Digital Signature Algorithm) approach can be considered as a variant of ElGamal signatures (such as Schnorr or DSA). Importantly, they all follow the hash-then-sign (go) approach, meaning that they can sign arbitrary length messages by transforming them to a fixed-size representation first. For Ed25519, the default hash algo is SHA-512. Most Libsodium wrappers do not provide the ability to change this easily.

Resources:

Libsodium notes:

  • crypto_box(): implements ECDH in Montgomery form Curve25519 (fast for variable base scalar mult. - eg. DH: X25519)
    • convert private key to public key: crypto_scalarmult_base (doc)
  • crypto_sign(): implements EdDSA in Twisted Edwards form Curve25519 (fast for fixed base scalar multi. - eg. signing: Ed25519)
    • convert private key to public key: crypto_sign_seed_keypair (doc)

XChaCha20-Poly1305

A secret key algorithm for encryption. Without hardware acceleration, it's usually faster than AES-256-GCM while proving a similar degree of security.

SHA-512 or BLAKE2b

Used for key derivation after DH and the hash ratchet during communication. Some Libsodium wrappers don't provide BLAKE2b.

Resources