packages feed

hstox-0.0.1: src/tox/Network/Tox/DHT/DhtPacket.lhs

\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 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, 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 qualified Network.Tox.Crypto.CombinedKey as CombinedKey
import           Network.Tox.Crypto.Key         (Nonce, PublicKey)
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 (KeyPair senderSecretKey senderPublicKey') receiverPublicKey nonce plainText =
  DhtPacket senderPublicKey' nonce $ Box.encrypt combinedKey nonce plainText
  where combinedKey = CombinedKey.precompute senderSecretKey receiverPublicKey


encode :: Binary payload => KeyPair -> PublicKey -> Nonce -> payload -> DhtPacket
encode keyPair receiverPublicKey nonce =
  encrypt keyPair receiverPublicKey nonce
  . PlainText
  . LazyByteString.toStrict
  . runPut
  . put


decrypt :: KeyPair -> DhtPacket -> Maybe PlainText
decrypt (KeyPair receiverSecretKey _) DhtPacket { senderPublicKey, encryptionNonce, encryptedPayload } =
  Box.decrypt combinedKey encryptionNonce encryptedPayload
  where combinedKey = CombinedKey.precompute receiverSecretKey senderPublicKey


decode :: Binary payload => KeyPair -> DhtPacket -> Maybe payload
decode keyPair packet = decrypt keyPair packet >>= Box.decode


{-------------------------------------------------------------------------------
 -
 - :: Tests.
 -
 ------------------------------------------------------------------------------}


instance Arbitrary DhtPacket where
  arbitrary =
    DhtPacket <$> arbitrary <*> arbitrary <*> arbitrary
\end{code}