Arivi Network protocol – Key Exchange

Arivi Network protocol – Key Exchange

In our case NodeId or Public key is the combination of a Ed25519 public key and Curve25519 public key. We do this because we need both the key pairs created using Ed25519 and Curve25519 curves for signing and key exchange respectively. So instead of having a separate NodeId we can combine public keys of both the pairs to form a single NodeId. We derive the key-exchange PvtK from the curve25519 using hash of signature PvtK.

Curve25519 for Encryption & Ed25519 for Signatures:

  • Curve25519 provides a very simple, constant time, and fast variable-base scalar multiplication algorithms. This is very good for ECDH and this is why it is used specifically for ECDH.
  • Ed25519 instead provides a very fast fixed-base and double-base scalar multiplications, due to the fast and complete twisted Edwards addition law. The fixed-base algorithm of Ed25519 is, on most platforms, faster than the variable-base of Curve25519.
First 32 bytes of public key is Digital Signature Public key (DsPub) this name indicates that it is used in verification of signature in peer node. Last 32 bytes public key is Key Exchange Public key (KePub) this name indicates that it is used in generation of shared secret.

(DsPvt, DsPub) = ed21159_GenerateKeys(entropy 32 bytes)
(KePvt, KePub) = curve25519_GenerateKeys(sha256( Pvt ))
NodeId = KePub | DsPub

Key Exchange:

Key exchange as been explained in from of two phases :
  1. First phase is initiation of handshake request made by the initiator.
  2. Second phase can be noted as handshake response made by the recipient.

First Phase:

This phase is divided into two parts first describes how Initiator Node initiates communication with recipient node by sending Handshake request and second part describes when recipient node receives that handshake request and decrypts and verifies its authenticity and integrity.

At Initiator Node

Static public and private key of Initiator

(Pubk, Pvtk)

When session begins the Initiator prepares to send a handshake request it generates a pair of ephemeral keys using curve Ed25519.

(EPubK, EPvtK) <- createEpKeyPair()

Two Shared secrets are created First one using ephemeral private key of Initiator with KePubK (key exchange public key) of recipient which will be used for encryption.

sSharedSecretKey <- curve25519(PvtK, KePubK_recipient)

And Second using static private key of Initiator with KePubK of recipient which is used in generation signature.

eSharedSecretKey <- curve25519(EPvtK, KePubK_recipient)

Handshake init message is first encrypted payload sent to Recipient by Initiator which contains the NodeId of Initiator and its signature ( i.e generated by signing sSSk with PvtK of Initiator ).

Handshake_Init_message
{
versionList :: [Version],
connectionId :: ConnectionId,
nonce :: Initiator_Nonce,
nodePublicKey :: NodeId,
signature :: Signature
}
Handshake_init.signature <- sign(Static_SS, PvtK)

Parcel header section will hold EPubK of Initiator which will be required by recipient.

Header {
opcode :: Opcode,
ephemeralPublicKey :: NodeId,
aeadNonce :: ByteString
}

Payload is the combination of ciphertext and Message Authentication Code which is the output we get from ChaCha20/Poly1305 taking shared secret key, Initialization value (IV), plain text which needs to be encrypted and payload header as AAD ( which will not be encrypted but MAC will be used to authenticate it ) as input parameters.

Parcel.payload <- chacha20-poly1305(Handshake_init,SS,header,header.aeadNonce)

Parcel is sent to Recipient which is pseudo frame which contains `Header` and `CipherText`. These fields will be encoded using CBOR format. Ciphertext is encrypted p2p message which is received from the Arivi P2P Layer. Header will not be encrypted so it will be useful at the receiving side to show which type of parcel it is and also in authentication using AAD. After encoding these fields length of the parcel in plain text is prepended before sending the it on the network which is of 2 bytes in size. Data sent on wire will be: [ Header Length + Parcel Header + ( Ciphertext + MAC ) ]

Parcel {
Header :: Header,
Encrypted_Payload :: Payload }

At Recipient Node

Once the Recipient encounters parcel it generates eSSk ( eSharedSecretKey )by using EPubK of Initiator and ephemeral private key of Recipient which is used to decrypt Ciphertext in Parcel. Later Recipient will generate a static SharedSecretKey sSSk using PvtK of Recipient and Pubk of Initiator which can verify the digital signature to confirm that packet received by it actually came from the Initiator it says it did.

Public and private key pair of Node2 :: (Pubk,Pvtk)
EPubK_initiator <- Parcel.header.ephemeralPublicKey
eSSk <- ed(PvtK, EPubK_initiator)
sSSk <- ed(PvtK, EnPubK_initiator)
Handshake_Init <- decrypt(Parcel.payload,SS) #chacha20/poly1305

Verifying authenticity and Integrity of packet is done by ED25519 using following parameters:
  1. Signature which is in Handshake_Init structure which can be decrypted by SS produced by Recipient
  2. EPuK of Initiator which is available in Parcel itself.
  3. sSSk which is produced by Recipient.

Bool <- verify(sSSk,Handshake_Init.signature,KePubk_initiator)


Second phase:

Now once the Recipient trusts Initiator, The entire process will be repeated again from the perspective of Recipient because the Static_SS generated by Initiator used the Static Keys (that are PubK of Recipient and PvtK of Initiator) hence to maintain Perfect Forward Secrecy Recipient generates a new set of Ephemeral Key pair. A final shared secret key is generated using EPvtK of Recipient and EPubK of Initiator ( Given in Parcel’s header ) once the exchange is done future payloads will be encrypted by final shared secret key generated by Recipient. To achieve forward Secrecy finally a shared secret key is generated by only using the ephemeral keys independently by both nodes but process completes after recipient replies back to initiator with its public ephemeral key.

At Recipient Node

SS <- ed25519(EPvtK,EPubK_node1)
Parcel.header.ephemeralPublicKey <-EPubK_node2
Parcel.payload <- Encrypt(Handshake_Init,SS)

At Initiator Node

EPubK_node2 <- Parcel.header.ephemeralPublicKey
SS <- ed25519(EPubK_node2,EPvt_node1)
decrypt(Parcel,SS)

Now they are said to be in an ESTABLISHED session, and either party can send and receive data messages.