{-# LANGUAGE KindSignatures #-} module Network.Tox.Crypto.Transport ( parseNetCrypto , encodeNetCrypto -- CryptoTransport , NetCrypto(..) , CryptoData(..) , CryptoMessage(..) , CryptoPacket(..) , HandshakeData(..) , Handshake(..) ) where import Crypto.Tox import Network.Tox.DHT.Transport (Cookie) import Network.Socket import Data.ByteString import Data.Word import Crypto.Hash data NetCrypto = NetHandshake (Handshake Encrypted) | NetCrypto (CryptoPacket Encrypted) parseNetCrypto :: ByteString -> SockAddr -> Either String (NetCrypto, SockAddr) parseNetCrypto pkt saddr = Left "TODO: parseNetCrypto" encodeNetCrypto :: NetCrypto -> SockAddr -> (ByteString, SockAddr) encodeNetCrypto _ _ = _todo data Handshake (f :: * -> *) = Handshake { handshakeCookie :: Cookie , handshakeNonce :: Nonce24 , hadshakeData :: f HandshakeData } data HandshakeData = HandshakeData { baseNonce :: Nonce24 , sessionKey :: PublicKey , cookieHash :: Digest SHA512 , otherCookie :: Cookie } data CryptoPacket (f :: * -> *) = CryptoPacket { pktNonce :: Word16 , pktData :: f CryptoData } data CryptoData = CryptoData { -- | [our recvbuffers buffer_start, (highest packet number handled + 1), (big endian)] bufferStart :: Word32 -- | [ uint32_t packet number if lossless -- , sendbuffer buffer_end if lossy , (big endian)] , bufferEnd :: Word32 -- | [data] , bufferData :: CryptoMessage } -- TODO: Flesh this out. data CryptoMessage -- First byte indicates data = Padding -- ^ 0 padding (skipped until we hit a non zero (data id) byte) | PacketRequest -- ^ 1 packet request packet (lossy packet) | KillPacket -- ^ 2 connection kill packet (lossy packet) | UnspecifiedPacket -- ^ 3+ unspecified | MessengerLossless -- ^ 16+ reserved for Messenger usage (lossless packets) | MessengerLossy -- ^ 192+ reserved for Messenger usage (lossy packets) | Messenger255 -- ^ 255 reserved for Messenger usage (lossless packet) -- --> CookieRequest WithoutCookie -- <-- CookieResponse CookieAddress -- --> Handshake CookieAddress -- <-- Handshake CookieAddress -- cookie request packet (145 bytes) -- -- [uint8_t 24] -- [Sender's DHT Public key (32 bytes)] -- [Random nonce (24 bytes)] -- [Encrypted message containing: -- [Sender's real public key (32 bytes)] -- [padding (32 bytes)] -- [uint64_t echo id (must be sent back untouched in cookie response)] -- ] -- Handshake packet: -- [uint8_t 26] (0x1a) -- [Cookie] -- [nonce (24 bytes)] -- [Encrypted message containing: -- [24 bytes base nonce] -- [session public key of the peer (32 bytes)] -- [sha512 hash of the entire Cookie sitting outside the encrypted part] -- [Other Cookie (used by the other to respond to the handshake packet)] -- ] -- cookie response packet (161 bytes): -- -- [uint8_t 25] -- [Random nonce (24 bytes)] -- [Encrypted message containing: -- [Cookie] -- [uint64_t echo id (that was sent in the request)] -- ] -- -- Encrypted message is encrypted with the exact same symmetric key as the -- cookie request packet it responds to but with a different nonce. -- (Encrypted message is encrypted with reqesters's DHT private key, -- responders's DHT public key and the nonce.) -- -- Since we don't receive the public key, we will need to lookup the key by -- the SockAddr... I don't understand why the CookieResponse message is -- special this way. TODO: implement a multimap (SockAddr -> SharedSecret) -- and wrap cookie queries with store/delete. TODO: Should the entire -- SharedScret cache be keyed on only SockAddr ? Perhaps the secret cache -- should be (NodeId -> Secret) and the cookie-request map should be -- (SockAddr -> NodeId) -- Encrypted packets: -- -- Length Contents -- :---------:-------------------------------------------------------------- -- `1` `uint8_t` (0x1b) -- `2` `uint16_t` The last 2 bytes of the nonce used to encrypt this -- variable  Payload -- -- The payload is encrypted with the session key and 'base nonce' set by the -- receiver in their handshake + packet number (starting at 0, big endian math).