\begin{code}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE StrictData #-}
module Tox.Onion.Tunnel where
import Data.Binary (Binary, decode, encode, get, put)
import qualified Data.Binary.Get as Get
import qualified Data.Binary.Put as Put
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as LBS
import Data.MessagePack (MessagePack)
import GHC.Generics (Generic)
import Test.QuickCheck.Arbitrary (Arbitrary (..))
import qualified Test.QuickCheck.Gen as Gen
import Tox.Crypto.Core.Box (CipherText, PlainText (..),
cipherText, decrypt, encrypt)
import qualified Tox.Crypto.Core.Box as Box
import Tox.Crypto.Core.Key (CombinedKey, Nonce, PublicKey,
SecretKey)
import Tox.Crypto.Core.Keyed (Keyed)
import qualified Tox.Crypto.Core.Keyed as Keyed
import Tox.Crypto.Core.KeyPair (KeyPair (..))
import Tox.Network.Core.HostAddress (HostAddress (..))
import Tox.Network.Core.PortNumber (PortNumber (..))
import Tox.Network.Core.SocketAddress (SocketAddress (..))
newtype OnionIPPort = OnionIPPort { OnionIPPort -> SocketAddress
unOnionIPPort :: SocketAddress }
deriving (OnionIPPort -> OnionIPPort -> Bool
(OnionIPPort -> OnionIPPort -> Bool)
-> (OnionIPPort -> OnionIPPort -> Bool) -> Eq OnionIPPort
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: OnionIPPort -> OnionIPPort -> Bool
$c/= :: OnionIPPort -> OnionIPPort -> Bool
== :: OnionIPPort -> OnionIPPort -> Bool
$c== :: OnionIPPort -> OnionIPPort -> Bool
Eq, Int -> OnionIPPort -> ShowS
[OnionIPPort] -> ShowS
OnionIPPort -> String
(Int -> OnionIPPort -> ShowS)
-> (OnionIPPort -> String)
-> ([OnionIPPort] -> ShowS)
-> Show OnionIPPort
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [OnionIPPort] -> ShowS
$cshowList :: [OnionIPPort] -> ShowS
show :: OnionIPPort -> String
$cshow :: OnionIPPort -> String
showsPrec :: Int -> OnionIPPort -> ShowS
$cshowsPrec :: Int -> OnionIPPort -> ShowS
Show, ReadPrec [OnionIPPort]
ReadPrec OnionIPPort
Int -> ReadS OnionIPPort
ReadS [OnionIPPort]
(Int -> ReadS OnionIPPort)
-> ReadS [OnionIPPort]
-> ReadPrec OnionIPPort
-> ReadPrec [OnionIPPort]
-> Read OnionIPPort
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [OnionIPPort]
$creadListPrec :: ReadPrec [OnionIPPort]
readPrec :: ReadPrec OnionIPPort
$creadPrec :: ReadPrec OnionIPPort
readList :: ReadS [OnionIPPort]
$creadList :: ReadS [OnionIPPort]
readsPrec :: Int -> ReadS OnionIPPort
$creadsPrec :: Int -> ReadS OnionIPPort
Read, (forall x. OnionIPPort -> Rep OnionIPPort x)
-> (forall x. Rep OnionIPPort x -> OnionIPPort)
-> Generic OnionIPPort
forall x. Rep OnionIPPort x -> OnionIPPort
forall x. OnionIPPort -> Rep OnionIPPort x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep OnionIPPort x -> OnionIPPort
$cfrom :: forall x. OnionIPPort -> Rep OnionIPPort x
Generic)
instance MessagePack OnionIPPort
instance Binary OnionIPPort where
put :: OnionIPPort -> Put
put (OnionIPPort (SocketAddress HostAddress
hostAddr (PortNumber Word16
port))) = do
case HostAddress
hostAddr of
IPv4 HostAddress
addr -> do
Word8 -> Put
Put.putWord8 Word8
2
HostAddress -> Put
Put.putWord32be HostAddress
addr
ByteString -> Put
Put.putByteString (ByteString -> Put) -> ByteString -> Put
forall a b. (a -> b) -> a -> b
$ Int -> Word8 -> ByteString
BS.replicate Int
12 Word8
0
IPv6 (HostAddress
a, HostAddress
b, HostAddress
c, HostAddress
d) -> do
Word8 -> Put
Put.putWord8 Word8
10
HostAddress -> Put
Put.putWord32be HostAddress
a
HostAddress -> Put
Put.putWord32be HostAddress
b
HostAddress -> Put
Put.putWord32be HostAddress
c
HostAddress -> Put
Put.putWord32be HostAddress
d
Word16 -> Put
Put.putWord16be Word16
port
get :: Get OnionIPPort
get = do
Word8
family <- Get Word8
Get.getWord8
HostAddress
hostAddr <- case Word8
family of
Word8
2 -> do
HostAddress
addr <- Get HostAddress
Get.getWord32be
ByteString
_ <- Int -> Get ByteString
Get.getByteString Int
12
HostAddress -> Get HostAddress
forall (m :: * -> *) a. Monad m => a -> m a
return (HostAddress -> Get HostAddress) -> HostAddress -> Get HostAddress
forall a b. (a -> b) -> a -> b
$ HostAddress -> HostAddress
IPv4 HostAddress
addr
Word8
10 -> do
HostAddress
a <- Get HostAddress
Get.getWord32be
HostAddress
b <- Get HostAddress
Get.getWord32be
HostAddress
c <- Get HostAddress
Get.getWord32be
HostAddress
d <- Get HostAddress
Get.getWord32be
HostAddress -> Get HostAddress
forall (m :: * -> *) a. Monad m => a -> m a
return (HostAddress -> Get HostAddress) -> HostAddress -> Get HostAddress
forall a b. (a -> b) -> a -> b
$ (HostAddress, HostAddress, HostAddress, HostAddress) -> HostAddress
IPv6 (HostAddress
a, HostAddress
b, HostAddress
c, HostAddress
d)
Word8
f -> String -> Get HostAddress
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Get HostAddress) -> String -> Get HostAddress
forall a b. (a -> b) -> a -> b
$ String
"Invalid Onion IP family: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Word8 -> String
forall a. Show a => a -> String
show Word8
f
SocketAddress -> OnionIPPort
OnionIPPort (SocketAddress -> OnionIPPort)
-> (Word16 -> SocketAddress) -> Word16 -> OnionIPPort
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HostAddress -> PortNumber -> SocketAddress
SocketAddress HostAddress
hostAddr (PortNumber -> SocketAddress)
-> (Word16 -> PortNumber) -> Word16 -> SocketAddress
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word16 -> PortNumber
PortNumber (Word16 -> OnionIPPort) -> Get Word16 -> Get OnionIPPort
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Get Word16
Get.getWord16be
instance Arbitrary OnionIPPort where
arbitrary :: Gen OnionIPPort
arbitrary = SocketAddress -> OnionIPPort
OnionIPPort (SocketAddress -> OnionIPPort)
-> Gen SocketAddress -> Gen OnionIPPort
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen SocketAddress
forall a. Arbitrary a => Gen a
arbitrary
data OnionRequest0 = OnionRequest0
{ OnionRequest0 -> Nonce
onion0Nonce :: Nonce
, OnionRequest0 -> PublicKey
onion0SenderPublicKey :: PublicKey
, OnionRequest0 -> CipherText
onion0EncryptedPayload :: CipherText
}
deriving (OnionRequest0 -> OnionRequest0 -> Bool
(OnionRequest0 -> OnionRequest0 -> Bool)
-> (OnionRequest0 -> OnionRequest0 -> Bool) -> Eq OnionRequest0
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: OnionRequest0 -> OnionRequest0 -> Bool
$c/= :: OnionRequest0 -> OnionRequest0 -> Bool
== :: OnionRequest0 -> OnionRequest0 -> Bool
$c== :: OnionRequest0 -> OnionRequest0 -> Bool
Eq, Int -> OnionRequest0 -> ShowS
[OnionRequest0] -> ShowS
OnionRequest0 -> String
(Int -> OnionRequest0 -> ShowS)
-> (OnionRequest0 -> String)
-> ([OnionRequest0] -> ShowS)
-> Show OnionRequest0
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [OnionRequest0] -> ShowS
$cshowList :: [OnionRequest0] -> ShowS
show :: OnionRequest0 -> String
$cshow :: OnionRequest0 -> String
showsPrec :: Int -> OnionRequest0 -> ShowS
$cshowsPrec :: Int -> OnionRequest0 -> ShowS
Show, ReadPrec [OnionRequest0]
ReadPrec OnionRequest0
Int -> ReadS OnionRequest0
ReadS [OnionRequest0]
(Int -> ReadS OnionRequest0)
-> ReadS [OnionRequest0]
-> ReadPrec OnionRequest0
-> ReadPrec [OnionRequest0]
-> Read OnionRequest0
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [OnionRequest0]
$creadListPrec :: ReadPrec [OnionRequest0]
readPrec :: ReadPrec OnionRequest0
$creadPrec :: ReadPrec OnionRequest0
readList :: ReadS [OnionRequest0]
$creadList :: ReadS [OnionRequest0]
readsPrec :: Int -> ReadS OnionRequest0
$creadsPrec :: Int -> ReadS OnionRequest0
Read, (forall x. OnionRequest0 -> Rep OnionRequest0 x)
-> (forall x. Rep OnionRequest0 x -> OnionRequest0)
-> Generic OnionRequest0
forall x. Rep OnionRequest0 x -> OnionRequest0
forall x. OnionRequest0 -> Rep OnionRequest0 x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep OnionRequest0 x -> OnionRequest0
$cfrom :: forall x. OnionRequest0 -> Rep OnionRequest0 x
Generic)
instance MessagePack OnionRequest0
instance Binary OnionRequest0 where
put :: OnionRequest0 -> Put
put OnionRequest0
req = do
Nonce -> Put
forall t. Binary t => t -> Put
put (Nonce -> Put) -> Nonce -> Put
forall a b. (a -> b) -> a -> b
$ OnionRequest0 -> Nonce
onion0Nonce OnionRequest0
req
PublicKey -> Put
forall t. Binary t => t -> Put
put (PublicKey -> Put) -> PublicKey -> Put
forall a b. (a -> b) -> a -> b
$ OnionRequest0 -> PublicKey
onion0SenderPublicKey OnionRequest0
req
CipherText -> Put
forall t. Binary t => t -> Put
put (CipherText -> Put) -> CipherText -> Put
forall a b. (a -> b) -> a -> b
$ OnionRequest0 -> CipherText
onion0EncryptedPayload OnionRequest0
req
get :: Get OnionRequest0
get = Nonce -> PublicKey -> CipherText -> OnionRequest0
OnionRequest0 (Nonce -> PublicKey -> CipherText -> OnionRequest0)
-> Get Nonce -> Get (PublicKey -> CipherText -> OnionRequest0)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Get Nonce
forall t. Binary t => Get t
get Get (PublicKey -> CipherText -> OnionRequest0)
-> Get PublicKey -> Get (CipherText -> OnionRequest0)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Get PublicKey
forall t. Binary t => Get t
get Get (CipherText -> OnionRequest0)
-> Get CipherText -> Get OnionRequest0
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Get CipherText
forall t. Binary t => Get t
get
instance Arbitrary OnionRequest0 where
arbitrary :: Gen OnionRequest0
arbitrary = Nonce -> PublicKey -> CipherText -> OnionRequest0
OnionRequest0 (Nonce -> PublicKey -> CipherText -> OnionRequest0)
-> Gen Nonce -> Gen (PublicKey -> CipherText -> OnionRequest0)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen Nonce
forall a. Arbitrary a => Gen a
arbitrary Gen (PublicKey -> CipherText -> OnionRequest0)
-> Gen PublicKey -> Gen (CipherText -> OnionRequest0)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen PublicKey
forall a. Arbitrary a => Gen a
arbitrary Gen (CipherText -> OnionRequest0)
-> Gen CipherText -> Gen OnionRequest0
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen CipherText
forall a. Arbitrary a => Gen a
arbitrary
data OnionRequestRelay = OnionRequestRelay
{ OnionRequestRelay -> Nonce
onionRelayNonce :: Nonce
, OnionRequestRelay -> PublicKey
onionRelayTemporaryKey :: PublicKey
, OnionRequestRelay -> CipherText
onionRelayEncryptedPayload :: CipherText
, OnionRequestRelay -> Nonce
onionRelayReturnNonce :: Nonce
, OnionRequestRelay -> CipherText
onionRelayReturnData :: CipherText
}
deriving (OnionRequestRelay -> OnionRequestRelay -> Bool
(OnionRequestRelay -> OnionRequestRelay -> Bool)
-> (OnionRequestRelay -> OnionRequestRelay -> Bool)
-> Eq OnionRequestRelay
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: OnionRequestRelay -> OnionRequestRelay -> Bool
$c/= :: OnionRequestRelay -> OnionRequestRelay -> Bool
== :: OnionRequestRelay -> OnionRequestRelay -> Bool
$c== :: OnionRequestRelay -> OnionRequestRelay -> Bool
Eq, Int -> OnionRequestRelay -> ShowS
[OnionRequestRelay] -> ShowS
OnionRequestRelay -> String
(Int -> OnionRequestRelay -> ShowS)
-> (OnionRequestRelay -> String)
-> ([OnionRequestRelay] -> ShowS)
-> Show OnionRequestRelay
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [OnionRequestRelay] -> ShowS
$cshowList :: [OnionRequestRelay] -> ShowS
show :: OnionRequestRelay -> String
$cshow :: OnionRequestRelay -> String
showsPrec :: Int -> OnionRequestRelay -> ShowS
$cshowsPrec :: Int -> OnionRequestRelay -> ShowS
Show, ReadPrec [OnionRequestRelay]
ReadPrec OnionRequestRelay
Int -> ReadS OnionRequestRelay
ReadS [OnionRequestRelay]
(Int -> ReadS OnionRequestRelay)
-> ReadS [OnionRequestRelay]
-> ReadPrec OnionRequestRelay
-> ReadPrec [OnionRequestRelay]
-> Read OnionRequestRelay
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [OnionRequestRelay]
$creadListPrec :: ReadPrec [OnionRequestRelay]
readPrec :: ReadPrec OnionRequestRelay
$creadPrec :: ReadPrec OnionRequestRelay
readList :: ReadS [OnionRequestRelay]
$creadList :: ReadS [OnionRequestRelay]
readsPrec :: Int -> ReadS OnionRequestRelay
$creadsPrec :: Int -> ReadS OnionRequestRelay
Read, (forall x. OnionRequestRelay -> Rep OnionRequestRelay x)
-> (forall x. Rep OnionRequestRelay x -> OnionRequestRelay)
-> Generic OnionRequestRelay
forall x. Rep OnionRequestRelay x -> OnionRequestRelay
forall x. OnionRequestRelay -> Rep OnionRequestRelay x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep OnionRequestRelay x -> OnionRequestRelay
$cfrom :: forall x. OnionRequestRelay -> Rep OnionRequestRelay x
Generic)
instance MessagePack OnionRequestRelay
instance Binary OnionRequestRelay where
put :: OnionRequestRelay -> Put
put OnionRequestRelay
req = do
Nonce -> Put
forall t. Binary t => t -> Put
put (Nonce -> Put) -> Nonce -> Put
forall a b. (a -> b) -> a -> b
$ OnionRequestRelay -> Nonce
onionRelayNonce OnionRequestRelay
req
PublicKey -> Put
forall t. Binary t => t -> Put
put (PublicKey -> Put) -> PublicKey -> Put
forall a b. (a -> b) -> a -> b
$ OnionRequestRelay -> PublicKey
onionRelayTemporaryKey OnionRequestRelay
req
CipherText -> Put
forall t. Binary t => t -> Put
put (CipherText -> Put) -> CipherText -> Put
forall a b. (a -> b) -> a -> b
$ OnionRequestRelay -> CipherText
onionRelayEncryptedPayload OnionRequestRelay
req
Nonce -> Put
forall t. Binary t => t -> Put
put (Nonce -> Put) -> Nonce -> Put
forall a b. (a -> b) -> a -> b
$ OnionRequestRelay -> Nonce
onionRelayReturnNonce OnionRequestRelay
req
CipherText -> Put
forall t. Binary t => t -> Put
put (CipherText -> Put) -> CipherText -> Put
forall a b. (a -> b) -> a -> b
$ OnionRequestRelay -> CipherText
onionRelayReturnData OnionRequestRelay
req
get :: Get OnionRequestRelay
get = Nonce
-> PublicKey
-> CipherText
-> Nonce
-> CipherText
-> OnionRequestRelay
OnionRequestRelay (Nonce
-> PublicKey
-> CipherText
-> Nonce
-> CipherText
-> OnionRequestRelay)
-> Get Nonce
-> Get
(PublicKey
-> CipherText -> Nonce -> CipherText -> OnionRequestRelay)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Get Nonce
forall t. Binary t => Get t
get Get
(PublicKey
-> CipherText -> Nonce -> CipherText -> OnionRequestRelay)
-> Get PublicKey
-> Get (CipherText -> Nonce -> CipherText -> OnionRequestRelay)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Get PublicKey
forall t. Binary t => Get t
get Get (CipherText -> Nonce -> CipherText -> OnionRequestRelay)
-> Get CipherText -> Get (Nonce -> CipherText -> OnionRequestRelay)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Get CipherText
forall t. Binary t => Get t
get Get (Nonce -> CipherText -> OnionRequestRelay)
-> Get Nonce -> Get (CipherText -> OnionRequestRelay)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Get Nonce
forall t. Binary t => Get t
get Get (CipherText -> OnionRequestRelay)
-> Get CipherText -> Get OnionRequestRelay
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Get CipherText
forall t. Binary t => Get t
get
instance Arbitrary OnionRequestRelay where
arbitrary :: Gen OnionRequestRelay
arbitrary = Nonce
-> PublicKey
-> CipherText
-> Nonce
-> CipherText
-> OnionRequestRelay
OnionRequestRelay (Nonce
-> PublicKey
-> CipherText
-> Nonce
-> CipherText
-> OnionRequestRelay)
-> Gen Nonce
-> Gen
(PublicKey
-> CipherText -> Nonce -> CipherText -> OnionRequestRelay)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen Nonce
forall a. Arbitrary a => Gen a
arbitrary Gen
(PublicKey
-> CipherText -> Nonce -> CipherText -> OnionRequestRelay)
-> Gen PublicKey
-> Gen (CipherText -> Nonce -> CipherText -> OnionRequestRelay)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen PublicKey
forall a. Arbitrary a => Gen a
arbitrary Gen (CipherText -> Nonce -> CipherText -> OnionRequestRelay)
-> Gen CipherText -> Gen (Nonce -> CipherText -> OnionRequestRelay)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen CipherText
forall a. Arbitrary a => Gen a
arbitrary Gen (Nonce -> CipherText -> OnionRequestRelay)
-> Gen Nonce -> Gen (CipherText -> OnionRequestRelay)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen Nonce
forall a. Arbitrary a => Gen a
arbitrary Gen (CipherText -> OnionRequestRelay)
-> Gen CipherText -> Gen OnionRequestRelay
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen CipherText
forall a. Arbitrary a => Gen a
arbitrary
data OnionRequestPayload = OnionRequestPayload
{ OnionRequestPayload -> OnionIPPort
onionPayloadDestination :: OnionIPPort
, OnionRequestPayload -> PublicKey
onionPayloadTemporaryKey :: PublicKey
, OnionRequestPayload -> CipherText
onionPayloadEncryptedPayload :: CipherText
}
deriving (OnionRequestPayload -> OnionRequestPayload -> Bool
(OnionRequestPayload -> OnionRequestPayload -> Bool)
-> (OnionRequestPayload -> OnionRequestPayload -> Bool)
-> Eq OnionRequestPayload
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: OnionRequestPayload -> OnionRequestPayload -> Bool
$c/= :: OnionRequestPayload -> OnionRequestPayload -> Bool
== :: OnionRequestPayload -> OnionRequestPayload -> Bool
$c== :: OnionRequestPayload -> OnionRequestPayload -> Bool
Eq, Int -> OnionRequestPayload -> ShowS
[OnionRequestPayload] -> ShowS
OnionRequestPayload -> String
(Int -> OnionRequestPayload -> ShowS)
-> (OnionRequestPayload -> String)
-> ([OnionRequestPayload] -> ShowS)
-> Show OnionRequestPayload
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [OnionRequestPayload] -> ShowS
$cshowList :: [OnionRequestPayload] -> ShowS
show :: OnionRequestPayload -> String
$cshow :: OnionRequestPayload -> String
showsPrec :: Int -> OnionRequestPayload -> ShowS
$cshowsPrec :: Int -> OnionRequestPayload -> ShowS
Show, ReadPrec [OnionRequestPayload]
ReadPrec OnionRequestPayload
Int -> ReadS OnionRequestPayload
ReadS [OnionRequestPayload]
(Int -> ReadS OnionRequestPayload)
-> ReadS [OnionRequestPayload]
-> ReadPrec OnionRequestPayload
-> ReadPrec [OnionRequestPayload]
-> Read OnionRequestPayload
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [OnionRequestPayload]
$creadListPrec :: ReadPrec [OnionRequestPayload]
readPrec :: ReadPrec OnionRequestPayload
$creadPrec :: ReadPrec OnionRequestPayload
readList :: ReadS [OnionRequestPayload]
$creadList :: ReadS [OnionRequestPayload]
readsPrec :: Int -> ReadS OnionRequestPayload
$creadsPrec :: Int -> ReadS OnionRequestPayload
Read, (forall x. OnionRequestPayload -> Rep OnionRequestPayload x)
-> (forall x. Rep OnionRequestPayload x -> OnionRequestPayload)
-> Generic OnionRequestPayload
forall x. Rep OnionRequestPayload x -> OnionRequestPayload
forall x. OnionRequestPayload -> Rep OnionRequestPayload x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep OnionRequestPayload x -> OnionRequestPayload
$cfrom :: forall x. OnionRequestPayload -> Rep OnionRequestPayload x
Generic)
instance MessagePack OnionRequestPayload
instance Binary OnionRequestPayload where
put :: OnionRequestPayload -> Put
put OnionRequestPayload
req = do
OnionIPPort -> Put
forall t. Binary t => t -> Put
put (OnionIPPort -> Put) -> OnionIPPort -> Put
forall a b. (a -> b) -> a -> b
$ OnionRequestPayload -> OnionIPPort
onionPayloadDestination OnionRequestPayload
req
PublicKey -> Put
forall t. Binary t => t -> Put
put (PublicKey -> Put) -> PublicKey -> Put
forall a b. (a -> b) -> a -> b
$ OnionRequestPayload -> PublicKey
onionPayloadTemporaryKey OnionRequestPayload
req
CipherText -> Put
forall t. Binary t => t -> Put
put (CipherText -> Put) -> CipherText -> Put
forall a b. (a -> b) -> a -> b
$ OnionRequestPayload -> CipherText
onionPayloadEncryptedPayload OnionRequestPayload
req
get :: Get OnionRequestPayload
get = OnionIPPort -> PublicKey -> CipherText -> OnionRequestPayload
OnionRequestPayload (OnionIPPort -> PublicKey -> CipherText -> OnionRequestPayload)
-> Get OnionIPPort
-> Get (PublicKey -> CipherText -> OnionRequestPayload)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Get OnionIPPort
forall t. Binary t => Get t
get Get (PublicKey -> CipherText -> OnionRequestPayload)
-> Get PublicKey -> Get (CipherText -> OnionRequestPayload)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Get PublicKey
forall t. Binary t => Get t
get Get (CipherText -> OnionRequestPayload)
-> Get CipherText -> Get OnionRequestPayload
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Get CipherText
forall t. Binary t => Get t
get
instance Arbitrary OnionRequestPayload where
arbitrary :: Gen OnionRequestPayload
arbitrary = OnionIPPort -> PublicKey -> CipherText -> OnionRequestPayload
OnionRequestPayload (OnionIPPort -> PublicKey -> CipherText -> OnionRequestPayload)
-> Gen OnionIPPort
-> Gen (PublicKey -> CipherText -> OnionRequestPayload)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen OnionIPPort
forall a. Arbitrary a => Gen a
arbitrary Gen (PublicKey -> CipherText -> OnionRequestPayload)
-> Gen PublicKey -> Gen (CipherText -> OnionRequestPayload)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen PublicKey
forall a. Arbitrary a => Gen a
arbitrary Gen (CipherText -> OnionRequestPayload)
-> Gen CipherText -> Gen OnionRequestPayload
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen CipherText
forall a. Arbitrary a => Gen a
arbitrary
data OnionResponse = OnionResponse
{ OnionResponse -> Nonce
onionResponseNonce :: Nonce
, OnionResponse -> CipherText
onionResponseEncryptedSendback :: CipherText
, OnionResponse -> ByteString
onionResponseData :: BS.ByteString
}
deriving (OnionResponse -> OnionResponse -> Bool
(OnionResponse -> OnionResponse -> Bool)
-> (OnionResponse -> OnionResponse -> Bool) -> Eq OnionResponse
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: OnionResponse -> OnionResponse -> Bool
$c/= :: OnionResponse -> OnionResponse -> Bool
== :: OnionResponse -> OnionResponse -> Bool
$c== :: OnionResponse -> OnionResponse -> Bool
Eq, Int -> OnionResponse -> ShowS
[OnionResponse] -> ShowS
OnionResponse -> String
(Int -> OnionResponse -> ShowS)
-> (OnionResponse -> String)
-> ([OnionResponse] -> ShowS)
-> Show OnionResponse
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [OnionResponse] -> ShowS
$cshowList :: [OnionResponse] -> ShowS
show :: OnionResponse -> String
$cshow :: OnionResponse -> String
showsPrec :: Int -> OnionResponse -> ShowS
$cshowsPrec :: Int -> OnionResponse -> ShowS
Show, ReadPrec [OnionResponse]
ReadPrec OnionResponse
Int -> ReadS OnionResponse
ReadS [OnionResponse]
(Int -> ReadS OnionResponse)
-> ReadS [OnionResponse]
-> ReadPrec OnionResponse
-> ReadPrec [OnionResponse]
-> Read OnionResponse
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [OnionResponse]
$creadListPrec :: ReadPrec [OnionResponse]
readPrec :: ReadPrec OnionResponse
$creadPrec :: ReadPrec OnionResponse
readList :: ReadS [OnionResponse]
$creadList :: ReadS [OnionResponse]
readsPrec :: Int -> ReadS OnionResponse
$creadsPrec :: Int -> ReadS OnionResponse
Read, (forall x. OnionResponse -> Rep OnionResponse x)
-> (forall x. Rep OnionResponse x -> OnionResponse)
-> Generic OnionResponse
forall x. Rep OnionResponse x -> OnionResponse
forall x. OnionResponse -> Rep OnionResponse x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep OnionResponse x -> OnionResponse
$cfrom :: forall x. OnionResponse -> Rep OnionResponse x
Generic)
instance MessagePack OnionResponse
instance Binary OnionResponse where
put :: OnionResponse -> Put
put OnionResponse
res = do
Nonce -> Put
forall t. Binary t => t -> Put
put (Nonce -> Put) -> Nonce -> Put
forall a b. (a -> b) -> a -> b
$ OnionResponse -> Nonce
onionResponseNonce OnionResponse
res
CipherText -> Put
forall t. Binary t => t -> Put
put (CipherText -> Put) -> CipherText -> Put
forall a b. (a -> b) -> a -> b
$ OnionResponse -> CipherText
onionResponseEncryptedSendback OnionResponse
res
ByteString -> Put
Put.putByteString (ByteString -> Put) -> ByteString -> Put
forall a b. (a -> b) -> a -> b
$ OnionResponse -> ByteString
onionResponseData OnionResponse
res
get :: Get OnionResponse
get = Nonce -> CipherText -> ByteString -> OnionResponse
OnionResponse (Nonce -> CipherText -> ByteString -> OnionResponse)
-> Get Nonce -> Get (CipherText -> ByteString -> OnionResponse)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Get Nonce
forall t. Binary t => Get t
get Get (CipherText -> ByteString -> OnionResponse)
-> Get CipherText -> Get (ByteString -> OnionResponse)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Get CipherText
forall t. Binary t => Get t
get Get (ByteString -> OnionResponse)
-> Get ByteString -> Get OnionResponse
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (ByteString -> ByteString
LBS.toStrict (ByteString -> ByteString) -> Get ByteString -> Get ByteString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Get ByteString
Get.getRemainingLazyByteString)
instance Arbitrary OnionResponse where
arbitrary :: Gen OnionResponse
arbitrary = Nonce -> CipherText -> ByteString -> OnionResponse
OnionResponse (Nonce -> CipherText -> ByteString -> OnionResponse)
-> Gen Nonce -> Gen (CipherText -> ByteString -> OnionResponse)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen Nonce
forall a. Arbitrary a => Gen a
arbitrary Gen (CipherText -> ByteString -> OnionResponse)
-> Gen CipherText -> Gen (ByteString -> OnionResponse)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen CipherText
forall a. Arbitrary a => Gen a
arbitrary Gen (ByteString -> OnionResponse)
-> Gen ByteString -> Gen OnionResponse
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> ([Word8] -> ByteString
BS.pack ([Word8] -> ByteString) -> Gen [Word8] -> Gen ByteString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen [Word8]
forall a. Arbitrary a => Gen a
arbitrary)
wrapOnion0 :: Keyed m
=> KeyPair -> PublicKey -> Nonce -> OnionRequestPayload -> m OnionRequest0
wrapOnion0 :: KeyPair
-> PublicKey -> Nonce -> OnionRequestPayload -> m OnionRequest0
wrapOnion0 (KeyPair SecretKey
sk PublicKey
pk) PublicKey
receiverPk Nonce
nonce OnionRequestPayload
payload = do
CombinedKey
combined <- SecretKey -> PublicKey -> m CombinedKey
forall (m :: * -> *).
Keyed m =>
SecretKey -> PublicKey -> m CombinedKey
Keyed.getCombinedKey SecretKey
sk PublicKey
receiverPk
let encrypted :: CipherText
encrypted = CombinedKey -> Nonce -> PlainText -> CipherText
Box.encrypt CombinedKey
combined Nonce
nonce (OnionRequestPayload -> PlainText
forall a. Binary a => a -> PlainText
Box.encode OnionRequestPayload
payload)
OnionRequest0 -> m OnionRequest0
forall (m :: * -> *) a. Monad m => a -> m a
return (OnionRequest0 -> m OnionRequest0)
-> OnionRequest0 -> m OnionRequest0
forall a b. (a -> b) -> a -> b
$ Nonce -> PublicKey -> CipherText -> OnionRequest0
OnionRequest0 Nonce
nonce PublicKey
pk CipherText
encrypted
unwrapOnion0 :: Keyed m
=> KeyPair -> OnionRequest0 -> m (Maybe OnionRequestPayload)
unwrapOnion0 :: KeyPair -> OnionRequest0 -> m (Maybe OnionRequestPayload)
unwrapOnion0 (KeyPair SecretKey
sk PublicKey
_) (OnionRequest0 Nonce
nonce PublicKey
senderPk CipherText
encrypted) = do
CombinedKey
combined <- SecretKey -> PublicKey -> m CombinedKey
forall (m :: * -> *).
Keyed m =>
SecretKey -> PublicKey -> m CombinedKey
Keyed.getCombinedKey SecretKey
sk PublicKey
senderPk
case CombinedKey -> Nonce -> CipherText -> Maybe PlainText
Box.decrypt CombinedKey
combined Nonce
nonce CipherText
encrypted of
Maybe PlainText
Nothing -> Maybe OnionRequestPayload -> m (Maybe OnionRequestPayload)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe OnionRequestPayload
forall a. Maybe a
Nothing
Just PlainText
plain -> Maybe OnionRequestPayload -> m (Maybe OnionRequestPayload)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe OnionRequestPayload -> m (Maybe OnionRequestPayload))
-> Maybe OnionRequestPayload -> m (Maybe OnionRequestPayload)
forall a b. (a -> b) -> a -> b
$ PlainText -> Maybe OnionRequestPayload
forall (m :: * -> *) a. (MonadFail m, Binary a) => PlainText -> m a
Box.decode PlainText
plain
wrapOnionRelay :: Keyed m
=> KeyPair -> PublicKey -> Nonce -> OnionRequestPayload -> Nonce -> CipherText -> m OnionRequestRelay
wrapOnionRelay :: KeyPair
-> PublicKey
-> Nonce
-> OnionRequestPayload
-> Nonce
-> CipherText
-> m OnionRequestRelay
wrapOnionRelay (KeyPair SecretKey
sk PublicKey
pk) PublicKey
receiverPk Nonce
nonce OnionRequestPayload
payload Nonce
retNonce CipherText
retData = do
CombinedKey
combined <- SecretKey -> PublicKey -> m CombinedKey
forall (m :: * -> *).
Keyed m =>
SecretKey -> PublicKey -> m CombinedKey
Keyed.getCombinedKey SecretKey
sk PublicKey
receiverPk
let encrypted :: CipherText
encrypted = CombinedKey -> Nonce -> PlainText -> CipherText
Box.encrypt CombinedKey
combined Nonce
nonce (OnionRequestPayload -> PlainText
forall a. Binary a => a -> PlainText
Box.encode OnionRequestPayload
payload)
OnionRequestRelay -> m OnionRequestRelay
forall (m :: * -> *) a. Monad m => a -> m a
return (OnionRequestRelay -> m OnionRequestRelay)
-> OnionRequestRelay -> m OnionRequestRelay
forall a b. (a -> b) -> a -> b
$ Nonce
-> PublicKey
-> CipherText
-> Nonce
-> CipherText
-> OnionRequestRelay
OnionRequestRelay Nonce
nonce PublicKey
pk CipherText
encrypted Nonce
retNonce CipherText
retData
unwrapOnionRelay :: Keyed m
=> KeyPair -> OnionRequestRelay -> m (Maybe (OnionRequestPayload, Nonce, CipherText))
unwrapOnionRelay :: KeyPair
-> OnionRequestRelay
-> m (Maybe (OnionRequestPayload, Nonce, CipherText))
unwrapOnionRelay (KeyPair SecretKey
sk PublicKey
_) (OnionRequestRelay Nonce
nonce PublicKey
senderPk CipherText
encrypted Nonce
retNonce CipherText
retData) = do
CombinedKey
combined <- SecretKey -> PublicKey -> m CombinedKey
forall (m :: * -> *).
Keyed m =>
SecretKey -> PublicKey -> m CombinedKey
Keyed.getCombinedKey SecretKey
sk PublicKey
senderPk
case CombinedKey -> Nonce -> CipherText -> Maybe PlainText
Box.decrypt CombinedKey
combined Nonce
nonce CipherText
encrypted of
Maybe PlainText
Nothing -> Maybe (OnionRequestPayload, Nonce, CipherText)
-> m (Maybe (OnionRequestPayload, Nonce, CipherText))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (OnionRequestPayload, Nonce, CipherText)
forall a. Maybe a
Nothing
Just PlainText
plain -> case PlainText -> Maybe OnionRequestPayload
forall (m :: * -> *) a. (MonadFail m, Binary a) => PlainText -> m a
Box.decode PlainText
plain of
Maybe OnionRequestPayload
Nothing -> Maybe (OnionRequestPayload, Nonce, CipherText)
-> m (Maybe (OnionRequestPayload, Nonce, CipherText))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (OnionRequestPayload, Nonce, CipherText)
forall a. Maybe a
Nothing
Just OnionRequestPayload
payload -> Maybe (OnionRequestPayload, Nonce, CipherText)
-> m (Maybe (OnionRequestPayload, Nonce, CipherText))
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (OnionRequestPayload, Nonce, CipherText)
-> m (Maybe (OnionRequestPayload, Nonce, CipherText)))
-> Maybe (OnionRequestPayload, Nonce, CipherText)
-> m (Maybe (OnionRequestPayload, Nonce, CipherText))
forall a b. (a -> b) -> a -> b
$ (OnionRequestPayload, Nonce, CipherText)
-> Maybe (OnionRequestPayload, Nonce, CipherText)
forall a. a -> Maybe a
Just (OnionRequestPayload
payload, Nonce
retNonce, CipherText
retData)
\end{code}
\chapter{Onion}
The goal of the onion module in Tox is to prevent peers that are not friends
from finding out the temporary DHT public key from a known long term public key
of the peer and to prevent peers from discovering the long term public key of
peers when only the temporary DHT key is known.
It makes sure only friends of a peer can find it and connect to it and
indirectly makes sure non friends cannot find the ip address of the peer when
knowing the Tox address of the friend.
The only way to prevent peers in the network from associating the temporary DHT
public key with the long term public key is to not broadcast the long term key
and only give others in the network that are not friends the DHT public key.
The onion lets peers send their friends, whose real public key they know as it
is part of the Tox ID, their DHT public key so that the friends can then find
and connect to them without other peers being able to identify the real public
keys of peers.
So how does the onion work?
The onion works by enabling peers to announce their real public key to peers by
going through the onion path. It is like a DHT but through onion paths. In
fact it uses the DHT in order for peers to be able to find the peers with ids
closest to their public key by going through onion paths.
In order to announce its real public key anonymously to the Tox network while
using the onion, a peer first picks 3 random nodes that it knows (they can be
from anywhere: the DHT, connected TCP relays or nodes found while finding peers
with the onion). The nodes should be picked in a way that makes them unlikely
to be operated by the same person perhaps by looking at the ip addresses and
looking if they are in the same subnet or other ways. More research is needed
to make sure nodes are picked in the safest way possible.
The reason for 3 nodes is that 3 hops is what they use in Tor and other
anonymous onion based networks.
These nodes are referred to as nodes A, B and C. Note that if a peer cannot
communicate via UDP, its first peer will be one of the TCP relays it is
connected to, which will be used to send its onion packet to the network.
TCP relays can only be node A or the first peer in the chain as the TCP relay
is essentially acting as a gateway to the network. The data sent to the TCP
Client module to be sent as a TCP onion packet by the module is different from
the one sent directly via UDP. This is because it doesn't need to be encrypted
(the connection to the TCP relay server is already encrypted).
First I will explain how communicating via onion packets work.
Note: nonce is a 24 byte nonce. The nested nonces are all the same as the
outer nonce.
Onion packet (request):
Initial (TCP) data sent as the data of an onion packet through the TCP client
module:
\begin{itemize}
\item \texttt{IP\_Port} of node B
\item A random public key PK1
\item Encrypted with the secret key SK1 and the public key of Node B and the nonce:
\begin{itemize}
\item \texttt{IP\_Port} of node C
\item A random public key PK2
\item Encrypted with the secret key SK2 and the public key of Node C and the nonce:
\begin{itemize}
\item \texttt{IP\_Port} of node D
\item Data to send to Node D
\end{itemize}
\end{itemize}
\end{itemize}
Initial (UDP) (sent from us to node A):
\begin{itemize}
\item \texttt{uint8\_t} (0x80) packet id
\item Nonce
\item Our temporary DHT public key
\item Encrypted with our temporary DHT secret key and the public key of Node A and
the nonce:
\begin{itemize}
\item \texttt{IP\_Port} of node B
\item A random public key PK1
\item Encrypted with the secret key SK1 and the public key of Node B and the nonce:
\begin{itemize}
\item \texttt{IP\_Port} of node C
\item A random public key PK2
\item Encrypted with the secret key SK2 and the public key of Node C and the
nonce:
\begin{itemize}
\item \texttt{IP\_Port} of node D
\item Data to send to Node D
\end{itemize}
\end{itemize}
\end{itemize}
\end{itemize}
(sent from node A to node B):
\begin{itemize}
\item \texttt{uint8\_t} (0x81) packet id
\item Nonce
\item A random public key PK1
\item Encrypted with the secret key SK1 and the public key of Node B and the nonce:
\begin{itemize}
\item \texttt{IP\_Port} of node C
\item A random public key PK2
\item Encrypted with the secret key SK2 and the public key of Node C and the nonce:
\begin{itemize}
\item \texttt{IP\_Port} of node D
\item Data to send to Node D
\end{itemize}
\end{itemize}
\item Nonce
\item Encrypted with temporary symmetric key of Node A and the nonce:
\begin{itemize}
\item \texttt{IP\_Port} (of us)
\end{itemize}
\end{itemize}
(sent from node B to node C):
\begin{itemize}
\item \texttt{uint8\_t} (0x82) packet id
\item Nonce
\item A random public key PK1
\item Encrypted with the secret key SK1 and the public key of Node C and the nonce:
\begin{itemize}
\item \texttt{IP\_Port} of node D
\item Data to send to Node D
\end{itemize}
\item Nonce
\item Encrypted with temporary symmetric key of Node B and the nonce:
\begin{itemize}
\item \texttt{IP\_Port} (of Node A)
\item Nonce
\item Encrypted with temporary symmetric key of Node A and the nonce:
\begin{itemize}
\item \texttt{IP\_Port} (of us)
\end{itemize}
\end{itemize}
\end{itemize}
(sent from node C to node D):
\begin{itemize}
\item Data to send to Node D
\item Nonce
\item Encrypted with temporary symmetric key of Node C and the nonce:
\begin{itemize}
\item \texttt{IP\_Port} (of Node B)
\item Nonce
\item Encrypted with temporary symmetric key of Node B and the nonce:
\begin{itemize}
\item \texttt{IP\_Port} (of Node A)
\item Nonce
\item Encrypted with temporary symmetric key of Node A and the nonce:
\begin{itemize}
\item \texttt{IP\_Port} (of us)
\end{itemize}
\end{itemize}
\end{itemize}
\end{itemize}
Onion packet (response):
initial (sent from node D to node C):
\begin{itemize}
\item \texttt{uint8\_t} (0x8c) packet id
\item Nonce
\item Encrypted with the temporary symmetric key of Node C and the nonce:
\begin{itemize}
\item \texttt{IP\_Port} (of Node B)
\item Nonce
\item Encrypted with the temporary symmetric key of Node B and the nonce:
\begin{itemize}
\item \texttt{IP\_Port} (of Node A)
\item Nonce
\item Encrypted with the temporary symmetric key of Node A and the nonce:
\begin{itemize}
\item \texttt{IP\_Port} (of us)
\end{itemize}
\end{itemize}
\end{itemize}
\item Data to send back
\end{itemize}
(sent from node C to node B):
\begin{itemize}
\item \texttt{uint8\_t} (0x8d) packet id
\item Nonce
\item Encrypted with the temporary symmetric key of Node B and the nonce:
\begin{itemize}
\item \texttt{IP\_Port} (of Node A)
\item Nonce
\item Encrypted with the temporary symmetric key of Node A and the nonce:
\begin{itemize}
\item \texttt{IP\_Port} (of us)
\end{itemize}
\end{itemize}
\item Data to send back
\end{itemize}
(sent from node B to node A):
\begin{itemize}
\item \texttt{uint8\_t} (0x8e) packet id
\item Nonce
\item Encrypted with the temporary symmetric key of Node A and the nonce:
\begin{itemize}
\item \texttt{IP\_Port} (of us)
\end{itemize}
\item Data to send back
\end{itemize}
(sent from node A to us):
\begin{itemize}
\item Data to send back
\end{itemize}
Each packet is encrypted multiple times so that only node A will be able to
receive and decrypt the first packet and know where to send it to, node B will
only be able to receive that decrypted packet, decrypt it again and know where
to send it and so on. You will also notice a piece of encrypted data (the
sendback) at the end of the packet that grows larger and larger at every layer
with the IP of the previous node in it. This is how the node receiving the end
data (Node D) will be able to send data back.
When a peer receives an onion packet, they will decrypt it, encrypt the
coordinates (IP/port) of the source along with the already existing encrypted
data (if it exists) with a symmetric key known only by the peer and only
refreshed every hour (in toxcore) as a security measure to force expire paths.
Here's a diagram how it works:
\begin{verbatim}
peer
-> [onion1[onion2[onion3[data]]]] -> Node A
-> [onion2[onion3[data]]][sendbackA] -> Node B
-> [onion3[data]][sendbackB[sendbackA]] -> Node C
-> [data][SendbackC[sendbackB[sendbackA]]]-> Node D (end)
\end{verbatim}
\begin{verbatim}
Node D
-> [SendbackC[sendbackB[sendbackA]]][response] -> Node C
-> [sendbackB[sendbackA]][response] -> Node B
-> [sendbackA][response] -> Node A
-> [response] -> peer
\end{verbatim}
The random public keys in the onion packets are temporary public keys generated
for and used for that onion path only. This is done in order to make it
difficult for others to link different paths together. Each encrypted layer
must have a different public key. This is the reason why there are multiple
keys in the packet definintions above.
The nonce is used to encrypt all the layers of encryption. This 24 byte nonce
should be randomly generated. If it isn't randomly generated and has a
relation to nonces used for other paths it could be possible to tie different
onion paths together.
The \texttt{IP\_Port} is an ip and port in packed format:
\begin{tabular}{l|l}
Length & Contents \\
\hline
\texttt{1} & \texttt{TOX\_AF\_INET} (2) for IPv4 or \texttt{TOX\_AF\_INET6} (10) for IPv6 \\
\texttt{4 / 16} & IP address (4 bytes if IPv4, 16 if IPv6) \\
\texttt{12 / 0} & Zeroes \\
\texttt{2} & \texttt{uint16\_t} Port \\
\end{tabular}
If IPv4 the format is padded with 12 bytes of zeroes so that both IPv4 and IPv6
have the same stored size.
The \texttt{IP\_Port} will always end up being of size 19 bytes. This is to
make it hard to know if an ipv4 or ipv6 ip is in the packet just by looking at
the size. The 12 bytes of zeros when ipv4 must be set to 0 and not left
uninitialized as some info may be leaked this way if it stays uninitialized.
All numbers here are in big endian format.
The \texttt{IP\_Port} in the sendback data can be in any format as long as the
length is 19 bytes because only the one who writes it can decrypt it and read
it, however, using the previous format is recommended because of code reuse.
The nonce in the sendback data must be a 24 byte nonce.
Each onion layers has a different packed id that identifies it so that an
implementation knows exactly how to handle them. Note that any data being sent
back must be encrypted, appear random and not leak information in any way as
all the nodes in the path will see it.
If anything is wrong with the received onion packets (decryption fails) the
implementation should drop them.
The implementation should have code for each different type of packet that
handles it, adds (or decrypts) a sendback and sends it to the next peer in the
path. There are a lot of packets but an implementation should be very
straightforward.
Note that if the first node in the path is a TCP relay, the TCP relay must put
an identifier (instead of an IP/Port) in the sendback so that it knows that any
response should be sent to the appropriate peer connected to the TCP relay.