Arivi Network protocol – Key Exchange
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.
(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 :- First phase is initiation of handshake request made by the initiator.
- 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)
Header {
opcode :: Opcode,
ephemeralPublicKey :: NodeId,
aeadNonce :: ByteString
}
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
- Signature which is in Handshake_Init structure which can be decrypted by SS produced by Recipient
- EPuK of Initiator which is available in Parcel itself.
- 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)