EllipticCP

Overview

EllipticCP messages are encrypted and authenticated with AEAD algorithm instantiated with ChaCha20 and Poly1305 (RFC 8439). AEAD algorithm uses shared secret obtained from Curve25519 Diffie-Hellman function.

Both server and client have long-term key pairs. Server generates it's short-term key pair on startup and changes it periodically (every hour or so). Client must obtain server's long term public key separately. Before opening connection, client generates key pair which is client's short-term key for this connection. During life time of a connection, both client and server can change short-term key at any time.

Short-term keys have "parity" property. Initial key (server's first key upon startup or client's key generated before opening a connection) is defined to be of even parity. After each key change, it's "parity" is also changed (e.g. if old one was 'even', new one is 'odd').

Packet format

Client -> server Server -> client
Init request packet:
(I,C',N,Box[INIT_REQ message](C'->S))
Init reply packet:
(I,N,Box[INIT_REP message](S->C'))
Open request packet:
(I,C',K,N,Box[OPEN_REQ message](C'->S'))
Open reply packet:
(I,C',N,Box[OPEN_REP message](S'->C'))
Message packet:
(I,C',N,Box[message](C'->S'))
Message packet:
(I,C',N,Box[message](S'->C'))
... ...
Key exchange packet:
(I,C',N,Box[KEYX_REQ message](C'->S'))
Key exchange packet:
(I,C',N,Box[KEYX_REP message](S'->C'))
... ...

Where:

  • I is key identifier (1 byte);
  • C' is client's short-term public key (32 bytes);
  • S' is server's short-term public key (32 bytes);
  • S is server's long-term public key (32 bytes);
  • K is a cookie (32 bytes);
  • N is nonce (64-bit integer in big endian form);
  • Box[X](C->S) is a cryptographic box, encrypting and authenticating X from the public key C to the public key S.

Key identifier (KEYID) contains information about keys used to encrypt and authenticate cryptographic box:

  • KEYID[7:4]:
    • b1111 if server's long-term key is used (init request/reply packets only);
    • b0000 if 'even' servers's short-term key is used;
    • b0001 if 'odd' server's short-term key is used;
  • KEYID[3:0]:
    • b1111 used in init reply packet only;
    • b0000 if 'even' client's short-term key is used;
    • b0001 if 'odd' client's short-term key is used.

Client and server initialize nonce for new connection to randomly generated 64-bit number before sending init request/open reply packet. Nonces are inceased by precisely 1 for each subsequent packet. Nonce for init reply packet is initialized to randomly generated 64-bit number on startup and is increased by precisely 1 for every subsequent init reply packet. 96-bit AEAD nonce is constructed in the following way:

  • client -> server: ASCII "CLNT" is prepended to nonce present in packet header;
  • server -> client: ASCII "SRVR" is prepended to nonce present in packet header;

Upon openning connection, both client and server can send any number of message packets.

Client periodically sends key exchange packet to check if server has changed it's short-term key and to keep connection alive. If client generates new short-term key, it must send key exchange packet to inform server about key change. Server will use new short-term key for subsequent packets only after it receives packet from client which uses that new key. Client can use any new short-term key immediately after receiving key exchange response. If client does not receive response to key exchange after some number of tries, it should consider connection broken.

Server can purge connections after some time of inactivity. Before purging connections server must generate new "minute key" - see cookie in INIT_REP message below.

Messages defined by EllipticCP

Message format is (MT,MD[,MT,MD,...]) where:

  • MT is 1 byte message type:
    • b10000000: INIT_REQ - init request message;
    • b10000001: INIT_REP - init reply message;
    • b10000010: OPEN_REQ - open request message;
    • b10000011: OPEN_REP - open reply message;
    • b10000100: KEYX_REQ - key exchange request message;
    • b10000101: KEYX_REP - key exchange reply message;
    • b000xxxxx: application specific;
  • MD is message data. Structure and length of message data is defined by message type.

Init request message

  • Message type is INIT_REQ;
  • Message data is null.

Init reply message

  • Message type is INIT_REP;
  • Message data is (I,S',K) where:
    • I is key identifier (1 byte): 0 if server's current key is 'even', 1 otherwise;
    • S' is server's current short-term public key (32 bytes);
    • K is cookie (32 bytes) - obtained by encrypring client's short-term key C' with symmetric encryption algorithm (AES-128 in ecb mode) using server's "minute key".

Open request message

  • Message type is OPEN_REQ;
  • Message data is (CT,VP[,V]) where:
    • CT is connection type (1 byte):
      • b10000001: VCONN connection (TBD);
      • b10000010: VLINK connection (TBD);
      • b0xxxxxxx: application specific;
    • VP is vouch present (1 byte): 1 if vouch subpacket is present, 0 otherwise;
    • V is vouch subpacket (C,N,Box[C'](C->S)) where:
      • C is client's long-term public key (32 bytes);
      • N is nonce (8 bytes) - 96-bit AEAD nonce is constucted by prepending ASCII "VBOX" to N;
      • C' is client's short-term public key (32 bytes).

Open reply message

  • Message type is OPEN_REP;
  • Message data is null.

Key exchange request message

  • Message type is KEYX_REQ;
  • Message data is (I,C') where:
    • I is key identifier (1 byte): 0 if client's current key is 'even', 1 otherwise;
    • C' is client's current short-term public key (32 bytes);

Key exchange reply message

  • Message type is KEYX_REP;
  • Message data is (I,S') where:
    • I is key identifier (1 byte): 0 if server's current key is 'even', 1 otherwise;
    • S' is server's current short-term public key (32 bytes);