\section{DHT Packet} The DHT Packet contains the sender's DHT Public Key, an encryption Nonce, and an encrypted payload. The payload is encrypted with the DHT secret key of the sender, the DHT public key of the receiver, and the nonce that is sent along with the packet. DHT Packets are sent inside Protocol Packets with a varying Packet Kind. \begin{tabular}{l|l|l} Length & Type & \href{#protocol-packet}{Contents} \\ \hline \texttt{32} & Public Key & Sender DHT Public Key \\ \texttt{24} & Nonce & Random nonce \\ \texttt{[16,]} & Bytes & Encrypted payload \\ \end{tabular} The encrypted payload is at least 16 bytes long, because the encryption includes a \href{https://en.wikipedia.org/wiki/Message_authentication_code}{MAC} of 16 bytes. A 16 byte payload would thus be the empty message. The DHT protocol never actually sends empty messages, so in reality the minimum size is 27 bytes for the \href{#ping-service}{Ping Packet}. \begin{code} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE Safe #-} module Network.Tox.DHT.DhtPacket where import Control.Applicative ((<$>), (<*>)) import Data.Binary (Binary, get, put) import Data.Binary.Get (getRemainingLazyByteString) import Data.Binary.Put (putByteString, runPut) import qualified Data.ByteString.Lazy as LazyByteString import Data.MessagePack (MessagePack) import Data.Typeable (Typeable) import GHC.Generics (Generic) import Network.Tox.Crypto.Box (CipherText, PlainText (..), unCipherText) import qualified Network.Tox.Crypto.Box as Box import Network.Tox.Crypto.Key (Nonce, PublicKey) import Network.Tox.Crypto.Keyed (Keyed) import qualified Network.Tox.Crypto.Keyed as Keyed import Network.Tox.Crypto.KeyPair (KeyPair (..)) import Test.QuickCheck.Arbitrary (Arbitrary, arbitrary) {------------------------------------------------------------------------------- - - :: Implementation. - ------------------------------------------------------------------------------} data DhtPacket = DhtPacket { senderPublicKey :: PublicKey , encryptionNonce :: Nonce , encryptedPayload :: CipherText } deriving (Eq, Read, Show, Generic, Typeable) instance MessagePack DhtPacket instance Binary DhtPacket where put packet = do put $ senderPublicKey packet put $ encryptionNonce packet putByteString . unCipherText . encryptedPayload $ packet get = DhtPacket <$> get <*> get <*> (LazyByteString.toStrict <$> getRemainingLazyByteString >>= Box.cipherText) encrypt :: KeyPair -> PublicKey -> Nonce -> PlainText -> DhtPacket encrypt = (((Keyed.runNullKeyed .) .) .) . encryptKeyed encryptKeyed :: Keyed m => KeyPair -> PublicKey -> Nonce -> PlainText -> m DhtPacket encryptKeyed (KeyPair senderSecretKey senderPublicKey') receiverPublicKey nonce plainText = (\combinedKey -> DhtPacket senderPublicKey' nonce $ Box.encrypt combinedKey nonce plainText) <$> Keyed.getCombinedKey senderSecretKey receiverPublicKey encode :: Binary payload => KeyPair -> PublicKey -> Nonce -> payload -> DhtPacket encode = (((Keyed.runNullKeyed .) .) .) . encodeKeyed encodeKeyed :: (Binary payload, Keyed m) => KeyPair -> PublicKey -> Nonce -> payload -> m DhtPacket encodeKeyed keyPair receiverPublicKey nonce = encryptKeyed keyPair receiverPublicKey nonce . PlainText . LazyByteString.toStrict . runPut . put decrypt :: KeyPair -> DhtPacket -> Maybe PlainText decrypt = (Keyed.runNullKeyed .) . decryptKeyed decryptKeyed :: Keyed m => KeyPair -> DhtPacket -> m (Maybe PlainText) decryptKeyed (KeyPair receiverSecretKey _) DhtPacket { senderPublicKey, encryptionNonce, encryptedPayload } = (\combinedKey -> Box.decrypt combinedKey encryptionNonce encryptedPayload) <$> Keyed.getCombinedKey receiverSecretKey senderPublicKey decode :: Binary payload => KeyPair -> DhtPacket -> Maybe payload decode = (Keyed.runNullKeyed .) . decodeKeyed decodeKeyed :: (Binary payload, Keyed m) => KeyPair -> DhtPacket -> m (Maybe payload) decodeKeyed keyPair packet = (>>= Box.decode) <$> decryptKeyed keyPair packet {------------------------------------------------------------------------------- - - :: Tests. - ------------------------------------------------------------------------------} instance Arbitrary DhtPacket where arbitrary = DhtPacket <$> arbitrary <*> arbitrary <*> arbitrary \end{code}