diff options
author | joe <joe@jerkface.net> | 2017-09-03 17:00:13 -0400 |
---|---|---|
committer | joe <joe@jerkface.net> | 2017-09-03 17:00:13 -0400 |
commit | 287379163d93d58142972f5f94c2beb8e872f7d4 (patch) | |
tree | d36d782a92ef499af073785321f81cc1ae11fd39 | |
parent | 6e82103d0e7f87127bb5b3f1f395e1d5b7adb1e0 (diff) |
Implemented more stubs for DHT transport.
-rw-r--r-- | DHTHandlers.hs | 36 | ||||
-rw-r--r-- | DHTTransport.hs | 131 | ||||
-rw-r--r-- | ToxAddress.hs | 40 | ||||
-rw-r--r-- | ToxCrypto.hs | 34 |
4 files changed, 192 insertions, 49 deletions
diff --git a/DHTHandlers.hs b/DHTHandlers.hs index 41a4bc06..437b05f3 100644 --- a/DHTHandlers.hs +++ b/DHTHandlers.hs | |||
@@ -6,19 +6,24 @@ import DHTTransport | |||
6 | import Network.QueryResponse as QR hiding (Client) | 6 | import Network.QueryResponse as QR hiding (Client) |
7 | import qualified Network.QueryResponse as QR (Client) | 7 | import qualified Network.QueryResponse as QR (Client) |
8 | import ToxCrypto | 8 | import ToxCrypto |
9 | import ToxMessage as Tox (PacketKind(..), pattern PingType, pattern GetNodesType, pattern DHTRequestType) | 9 | import ToxMessage as Tox (PacketKind(..), pattern PingType, pattern PongType, pattern GetNodesType, pattern SendNodesType, pattern DHTRequestType) |
10 | import Network.BitTorrent.DHT.Search | ||
10 | 11 | ||
12 | import Control.Arrow | ||
11 | import qualified Data.Wrapper.PSQInt as Int | 13 | import qualified Data.Wrapper.PSQInt as Int |
12 | import Kademlia | 14 | import Kademlia |
13 | import Network.Address (WantIP (..), ipFamily, testIdBit) | 15 | import Network.Address (WantIP (..), ipFamily, testIdBit,fromSockAddr, sockAddrPort) |
14 | import qualified Network.DHT.Routing as R | 16 | import qualified Network.DHT.Routing as R |
15 | import TriadCommittee | 17 | import TriadCommittee |
18 | import Global6 | ||
16 | 19 | ||
17 | import Control.Monad | 20 | import Control.Monad |
18 | import Control.Concurrent.STM | 21 | import Control.Concurrent.STM |
19 | import Data.Time.Clock.POSIX (POSIXTime, getPOSIXTime) | 22 | import Data.Time.Clock.POSIX (POSIXTime, getPOSIXTime) |
20 | import Network.Socket | 23 | import Network.Socket |
24 | import Data.Hashable | ||
21 | import Data.IP | 25 | import Data.IP |
26 | import Data.Ord | ||
22 | import Data.Maybe | 27 | import Data.Maybe |
23 | import Data.Bits | 28 | import Data.Bits |
24 | 29 | ||
@@ -77,9 +82,11 @@ newRouting addr crypto update4 update6 = do | |||
77 | 82 | ||
78 | 83 | ||
79 | -- TODO: This should cover more cases | 84 | -- TODO: This should cover more cases |
85 | isLocal :: IP -> Bool | ||
80 | isLocal (IPv6 ip6) = (ip6 == toEnum 0) | 86 | isLocal (IPv6 ip6) = (ip6 == toEnum 0) |
81 | isLocal (IPv4 ip4) = (ip4 == toEnum 0) | 87 | isLocal (IPv4 ip4) = (ip4 == toEnum 0) |
82 | 88 | ||
89 | isGlobal :: IP -> Bool | ||
83 | isGlobal = not . isLocal | 90 | isGlobal = not . isLocal |
84 | 91 | ||
85 | prefer4or6 :: NodeInfo -> Maybe WantIP -> WantIP | 92 | prefer4or6 :: NodeInfo -> Maybe WantIP -> WantIP |
@@ -210,6 +217,27 @@ transitionCommittee committee _ = return $ return () | |||
210 | 217 | ||
211 | type Handler = MethodHandler String TransactionId NodeInfo Message | 218 | type Handler = MethodHandler String TransactionId NodeInfo Message |
212 | 219 | ||
220 | isPing :: (f Ping -> Ping) -> DHTMessage f -> Either String Ping | ||
221 | isPing unpack (DHTPing a) = Right $ unpack $ assymData a | ||
222 | isPing _ _ = Left "Bad ping" | ||
223 | |||
224 | mkPong :: TransactionId -> NodeInfo -> NodeInfo -> Pong -> DHTMessage ((,) Nonce8) | ||
225 | mkPong tid src dst pong = DHTPong $ wrapAssym tid src dst (, pong) | ||
226 | |||
227 | isGetNodes :: (f GetNodes -> GetNodes) -> DHTMessage f -> Either String GetNodes | ||
228 | isGetNodes unpack (DHTGetNodes a) = Right $ unpack $ assymData a | ||
229 | isGetNodes _ _ = Left "Bad GetNodes" | ||
230 | |||
231 | mkSendNodes :: TransactionId -> NodeInfo -> NodeInfo -> SendNodes -> DHTMessage ((,) Nonce8) | ||
232 | mkSendNodes tid src dst sendnodes = DHTSendNodes $ wrapAssym tid src dst (, sendnodes) | ||
233 | |||
213 | handlers :: Routing -> Tox.PacketKind -> Maybe Handler | 234 | handlers :: Routing -> Tox.PacketKind -> Maybe Handler |
214 | handlers routing PingType = handler PongType pingH | 235 | handlers routing PingType = Just $ MethodHandler (isPing snd) mkPong pingH |
215 | handlers routing GetNodesType = handler SendNodesType $ getNodesH routing | 236 | handlers routing GetNodesType = Just $ MethodHandler (isGetNodes snd) mkSendNodes $ getNodesH routing |
237 | |||
238 | nodeSearch :: Client -> Search NodeId (IP,PortNumber) () NodeInfo NodeInfo | ||
239 | nodeSearch client = Search | ||
240 | { searchSpace = toxSpace | ||
241 | , searchNodeAddress = nodeIP &&& nodePort | ||
242 | , searchQuery = getNodes client | ||
243 | } | ||
diff --git a/DHTTransport.hs b/DHTTransport.hs index 690ee346..778390cf 100644 --- a/DHTTransport.hs +++ b/DHTTransport.hs | |||
@@ -29,10 +29,11 @@ import Network.QueryResponse | |||
29 | 29 | ||
30 | import Control.Arrow | 30 | import Control.Arrow |
31 | import Control.Monad | 31 | import Control.Monad |
32 | import Data.Bool | ||
32 | import qualified Data.ByteString as B | 33 | import qualified Data.ByteString as B |
33 | ;import Data.ByteString (ByteString) | 34 | ;import Data.ByteString (ByteString) |
34 | import Data.Tuple | 35 | import Data.Tuple |
35 | import Data.Serialize as S (Get, Serialize, get, put, runGet) | 36 | import Data.Serialize as S |
36 | import Data.Word | 37 | import Data.Word |
37 | import Network.Socket | 38 | import Network.Socket |
38 | 39 | ||
@@ -50,13 +51,14 @@ data DHTMessage (f :: * -> *) | |||
50 | | DHTDHTRequest PublicKey (Assym (f DHTRequest)) | 51 | | DHTDHTRequest PublicKey (Assym (f DHTRequest)) |
51 | 52 | ||
52 | mapMessage :: forall f b. (forall a. Nonce24 -> f a -> b) -> DHTMessage f -> b | 53 | mapMessage :: forall f b. (forall a. Nonce24 -> f a -> b) -> DHTMessage f -> b |
53 | mapMessage f msg = f _todo _todo | 54 | mapMessage f (DHTPing a) = f (assymNonce a) (assymData a) |
55 | mapMessage f (DHTPong a) = f (assymNonce a) (assymData a) | ||
56 | mapMessage f (DHTGetNodes a) = f (assymNonce a) (assymData a) | ||
57 | mapMessage f (DHTSendNodes a) = f (assymNonce a) (assymData a) | ||
58 | mapMessage f (DHTCookieRequest a) = f (assymNonce a) (assymData a) | ||
59 | mapMessage f (DHTDHTRequest _ a) = f (assymNonce a) (assymData a) | ||
60 | mapMessage f (DHTCookie nonce fcookie) = f nonce fcookie | ||
54 | 61 | ||
55 | instance Sized GetNodes where | ||
56 | size = ConstSize 32 -- TODO This right? | ||
57 | |||
58 | instance Sized SendNodes where | ||
59 | size = VarSize $ \(SendNodes ns) -> _nodeFormatSize * length ns | ||
60 | 62 | ||
61 | instance Sized Ping where size = ConstSize 1 | 63 | instance Sized Ping where size = ConstSize 1 |
62 | instance Sized Pong where size = ConstSize 1 | 64 | instance Sized Pong where size = ConstSize 1 |
@@ -77,27 +79,48 @@ parseDHTAddr (msg,saddr) | |||
77 | _ -> right | 79 | _ -> right |
78 | 80 | ||
79 | encodeDHTAddr :: (DHTMessage Encrypted8,NodeInfo) -> (ByteString, SockAddr) | 81 | encodeDHTAddr :: (DHTMessage Encrypted8,NodeInfo) -> (ByteString, SockAddr) |
80 | encodeDHTAddr = _todo | 82 | encodeDHTAddr (msg,ni) = (runPut $ putMessage msg, nodeAddr ni) |
83 | |||
84 | dhtMessageType :: DHTMessage Encrypted8 -> ( Word8, Put ) | ||
85 | dhtMessageType (DHTPing a) = (0x00, putAssym a) | ||
86 | dhtMessageType (DHTPong a) = (0x01, putAssym a) | ||
87 | dhtMessageType (DHTGetNodes a) = (0x02, putAssym a) | ||
88 | dhtMessageType (DHTSendNodes a) = (0x04, putAssym a) | ||
89 | dhtMessageType (DHTCookieRequest a) = (0x18, putAssym a) | ||
90 | dhtMessageType (DHTCookie n x) = (0x19, put n >> put x) | ||
91 | dhtMessageType (DHTDHTRequest k a) = (0x20, putPublicKey k >> putAssym a) | ||
92 | |||
93 | putMessage :: DHTMessage Encrypted8 -> Put | ||
94 | putMessage msg = case dhtMessageType msg of (typ,p) -> put typ >> p | ||
81 | 95 | ||
82 | getCookie :: Get (Nonce24, Encrypted8 Cookie) | 96 | getCookie :: Get (Nonce24, Encrypted8 Cookie) |
83 | getCookie = get | 97 | getCookie = get |
84 | 98 | ||
85 | getDHTReqest :: Get (PublicKey, Assym (Encrypted8 DHTRequest)) | 99 | getDHTReqest :: Get (PublicKey, Assym (Encrypted8 DHTRequest)) |
86 | getDHTReqest = _todo | 100 | getDHTReqest = (,) <$> getPublicKey <*> getAssym |
101 | |||
102 | -- ## DHT Request packets | ||
103 | -- | ||
104 | -- | Length | Contents | | ||
105 | -- |:-------|:--------------------------| | ||
106 | -- | `1` | `uint8_t` (0x20) | | ||
107 | -- | `32` | receiver's DHT public key | | ||
108 | -- ... ... | ||
109 | |||
87 | 110 | ||
88 | getDHT :: Sized a => Get (Assym (Encrypted8 a)) | 111 | getDHT :: Sized a => Get (Assym (Encrypted8 a)) |
89 | getDHT = _todo | 112 | getDHT = getAssym |
90 | 113 | ||
91 | 114 | ||
92 | -- Throws an error if called with a non-internet socket. | 115 | -- Throws an error if called with a non-internet socket. |
93 | direct :: Sized a => ByteString | 116 | direct :: Sized a => ByteString |
94 | -> SockAddr | 117 | -> SockAddr |
95 | -> (Assym (Encrypted8 a) | 118 | -> (Assym (Encrypted8 a) -> DHTMessage Encrypted8) |
96 | -> DHTMessage Encrypted8) | ||
97 | -> Either String (DHTMessage Encrypted8, NodeInfo) | 119 | -> Either String (DHTMessage Encrypted8, NodeInfo) |
98 | direct bs saddr f = fanGet bs getDHT f (asymNodeInfo saddr) | 120 | direct bs saddr f = fanGet bs getDHT f (asymNodeInfo saddr) |
99 | 121 | ||
100 | -- Throws an error if called with a non-internet socket. | 122 | -- Throws an error if called with a non-internet socket. |
123 | asymNodeInfo :: SockAddr -> Assym a -> NodeInfo | ||
101 | asymNodeInfo saddr asym = either (error . mappend "asymNodeInfo: ") id $ nodeInfo (NodeId $ senderKey asym) saddr | 124 | asymNodeInfo saddr asym = either (error . mappend "asymNodeInfo: ") id $ nodeInfo (NodeId $ senderKey asym) saddr |
102 | 125 | ||
103 | 126 | ||
@@ -105,35 +128,49 @@ fanGet :: ByteString -> Get x -> (x -> a) -> (x -> b) -> Either String (a,b) | |||
105 | fanGet bs getIt f nid = fmap (f &&& nid) $ runGet getIt bs | 128 | fanGet bs getIt f nid = fmap (f &&& nid) $ runGet getIt bs |
106 | 129 | ||
107 | -- Throws an error if called with a non-internet socket. | 130 | -- Throws an error if called with a non-internet socket. |
131 | noReplyAddr :: SockAddr -> NodeInfo | ||
108 | noReplyAddr saddr = either (error . mappend "noReplyAddr: ") id $ nodeInfo zeroID saddr | 132 | noReplyAddr saddr = either (error . mappend "noReplyAddr: ") id $ nodeInfo zeroID saddr |
109 | 133 | ||
110 | 134 | ||
111 | -- ## DHT Request packets | ||
112 | -- | ||
113 | -- | Length | Contents | | ||
114 | -- |:-------|:--------------------------| | ||
115 | -- | `1` | `uint8_t` (0x20) | | ||
116 | -- | `32` | receiver's DHT public key | | ||
117 | -- ... ... | ||
118 | |||
119 | data DHTRequestPacket = DHTRequestPacket | ||
120 | { requestTarget :: PublicKey | ||
121 | , request :: Assym (Encrypted DHTRequest) | ||
122 | } | ||
123 | |||
124 | instance Serialize DHTRequestPacket where | ||
125 | get = _todo | ||
126 | put = _todo | ||
127 | |||
128 | |||
129 | data DHTRequest | 135 | data DHTRequest |
136 | -- #### NAT ping request | ||
137 | -- | ||
138 | -- Length Contents | ||
139 | -- :------- :------------------------- | ||
140 | -- `1` `uint8_t` (0xfe) | ||
141 | -- `1` `uint8_t` (0x00) | ||
142 | -- `8` `uint64_t` random number | ||
130 | = NATPing Nonce8 | 143 | = NATPing Nonce8 |
144 | -- #### NAT ping response | ||
145 | -- | ||
146 | -- Length Contents | ||
147 | -- :------- :----------------------------------------------------------------- | ||
148 | -- `1` `uint8_t` (0xfe) | ||
149 | -- `1` `uint8_t` (0x01) | ||
150 | -- `8` `uint64_t` random number (the same that was received in request) | ||
131 | | NATPong Nonce8 | 151 | | NATPong Nonce8 |
132 | | DHTPK DHTPublicKey | 152 | | DHTPK DHTPublicKey |
133 | 153 | ||
154 | instance Sized DHTRequest where | ||
155 | size = VarSize $ \case | ||
156 | NATPing _ -> 10 | ||
157 | NATPong _ -> 10 | ||
158 | DHTPK dhtpk -> 41 + case size of | ||
159 | ConstSize nodes -> nodes | ||
160 | VarSize sznodes -> sznodes (dhtpkNodes dhtpk) | ||
161 | |||
134 | instance Serialize DHTRequest where | 162 | instance Serialize DHTRequest where |
135 | get = return _todo | 163 | get = do |
136 | put _ = return () -- todo | 164 | tag <- get |
165 | case tag :: Word8 of | ||
166 | 0xfe -> do | ||
167 | direction <- get | ||
168 | bool NATPong NATPing (direction==(0::Word8)) <$> get | ||
169 | 0x9c -> DHTPK <$> get | ||
170 | _ -> fail ("unrecognized DHT request: "++show tag) | ||
171 | put (NATPing n) = put (0xfe00 :: Word16) >> put n | ||
172 | put (NATPong n) = put (0xfe01 :: Word16) >> put n | ||
173 | put (DHTPK pk) = put (0x9c :: Word8) >> put pk | ||
137 | 174 | ||
138 | -- | Length | Contents | | 175 | -- | Length | Contents | |
139 | -- |:------------|:------------------------------------| | 176 | -- |:------------|:------------------------------------| |
@@ -147,12 +184,27 @@ data DHTPublicKey = DHTPublicKey | |||
147 | , dhtpkNodes :: SendNodes | 184 | , dhtpkNodes :: SendNodes |
148 | } | 185 | } |
149 | 186 | ||
187 | instance Serialize DHTPublicKey where | ||
188 | get = DHTPublicKey <$> get <*> getPublicKey <*> get | ||
189 | put (DHTPublicKey nonce key nodes) = do | ||
190 | put nonce | ||
191 | putPublicKey key | ||
192 | put nodes | ||
193 | |||
150 | newtype GetNodes = GetNodes NodeId | 194 | newtype GetNodes = GetNodes NodeId |
151 | deriving (Eq,Ord,Show,Read,S.Serialize) | 195 | deriving (Eq,Ord,Show,Read,S.Serialize) |
152 | 196 | ||
197 | instance Sized GetNodes where | ||
198 | size = ConstSize 32 -- TODO This right? | ||
199 | |||
153 | newtype SendNodes = SendNodes [NodeInfo] | 200 | newtype SendNodes = SendNodes [NodeInfo] |
154 | deriving (Eq,Ord,Show,Read) | 201 | deriving (Eq,Ord,Show,Read) |
155 | 202 | ||
203 | instance Sized SendNodes where | ||
204 | size = VarSize $ \(SendNodes ns) -> case size of | ||
205 | ConstSize nodeFormatSize -> nodeFormatSize * length ns | ||
206 | VarSize nsize -> sum $ map nsize ns | ||
207 | |||
156 | instance S.Serialize SendNodes where | 208 | instance S.Serialize SendNodes where |
157 | get = do | 209 | get = do |
158 | cnt <- S.get :: S.Get Word8 | 210 | cnt <- S.get :: S.Get Word8 |
@@ -189,8 +241,8 @@ data Cookie = Cookie Nonce24 (Encrypted CookieData) | |||
189 | instance Sized Cookie where size = ConstSize 112 -- 24 byte nonce + 88 byte cookie data | 241 | instance Sized Cookie where size = ConstSize 112 -- 24 byte nonce + 88 byte cookie data |
190 | 242 | ||
191 | instance Serialize Cookie where | 243 | instance Serialize Cookie where |
192 | get = return $ Cookie _todo _todo | 244 | get = Cookie <$> get <*> get |
193 | put _ = return () -- todo | 245 | put (Cookie nonce dta) = put nonce >> put dta |
194 | 246 | ||
195 | data CookieData = CookieData -- 16 (mac) | 247 | data CookieData = CookieData -- 16 (mac) |
196 | { cookieTime :: Word64 -- 8 | 248 | { cookieTime :: Word64 -- 8 |
@@ -198,12 +250,15 @@ data CookieData = CookieData -- 16 (mac) | |||
198 | , dhtKey :: PublicKey -- + 32 | 250 | , dhtKey :: PublicKey -- + 32 |
199 | } -- = 88 bytes when encrypted. | 251 | } -- = 88 bytes when encrypted. |
200 | 252 | ||
253 | instance Sized CookieData where | ||
254 | size = ConstSize 72 | ||
255 | |||
201 | instance Sized CookieRequest where | 256 | instance Sized CookieRequest where |
202 | size = ConstSize 64 -- 32 byte key + 32 byte padding | 257 | size = ConstSize 64 -- 32 byte key + 32 byte padding |
203 | 258 | ||
204 | instance Serialize CookieRequest where | 259 | instance Serialize CookieRequest where |
205 | get = CookieRequest <$> return _todo | 260 | get = CookieRequest <$> getPublicKey <* {- padding -} getPublicKey |
206 | put (CookieRequest _) = return () -- todo | 261 | put (CookieRequest k) = putPublicKey k >> {- padding -} putPublicKey k |
207 | 262 | ||
208 | forwardDHTRequests :: TransportCrypto -> (PublicKey -> IO (Maybe NodeInfo)) -> DHTTransport -> DHTTransport | 263 | forwardDHTRequests :: TransportCrypto -> (PublicKey -> IO (Maybe NodeInfo)) -> DHTTransport -> DHTTransport |
209 | forwardDHTRequests crypto closeLookup dht = dht { awaitMessage = await' } | 264 | forwardDHTRequests crypto closeLookup dht = dht { awaitMessage = await' } |
@@ -226,7 +281,7 @@ encryptMessage crypto n (Right assym) = E8 $ ToxCrypto.encrypt secret plain | |||
226 | where | 281 | where |
227 | secret = computeSharedSecret (transportSecret crypto) (senderKey assym) n | 282 | secret = computeSharedSecret (transportSecret crypto) (senderKey assym) n |
228 | plain = encodePlain $ swap $ assymData assym | 283 | plain = encodePlain $ swap $ assymData assym |
229 | encryptMessage crypto n (Left plain) = _todo | 284 | encryptMessage crypto n (Left plain) = _todo -- need cached public key. |
230 | 285 | ||
231 | decrypt :: TransportCrypto -> DHTMessage Encrypted8 -> NodeInfo -> Either String (DHTMessage ((,) Nonce8), NodeInfo) | 286 | decrypt :: TransportCrypto -> DHTMessage Encrypted8 -> NodeInfo -> Either String (DHTMessage ((,) Nonce8), NodeInfo) |
232 | decrypt crypto msg ni = (, ni) <$> (sequenceMessage $ transcode (decryptMessage crypto) msg) | 287 | decrypt crypto msg ni = (, ni) <$> (sequenceMessage $ transcode (decryptMessage crypto) msg) |
@@ -241,7 +296,7 @@ decryptMessage crypto n (Right assymE) = plain8 $ ToxCrypto.decrypt secret e | |||
241 | secret = computeSharedSecret (transportSecret crypto) (senderKey assymE) n | 296 | secret = computeSharedSecret (transportSecret crypto) (senderKey assymE) n |
242 | E8 e = assymData assymE | 297 | E8 e = assymData assymE |
243 | plain8 = Composed . fmap swap . (>>= decodePlain) | 298 | plain8 = Composed . fmap swap . (>>= decodePlain) |
244 | decryptMessage crypto n (Left (E8 e)) = _todo | 299 | decryptMessage crypto n (Left (E8 e)) = _todo -- need cached public key |
245 | 300 | ||
246 | sequenceMessage :: Applicative m => DHTMessage (m ∘ f) -> m (DHTMessage f) | 301 | sequenceMessage :: Applicative m => DHTMessage (m ∘ f) -> m (DHTMessage f) |
247 | sequenceMessage (DHTPing asym) = fmap DHTPing $ sequenceA $ fmap uncomposed asym | 302 | sequenceMessage (DHTPing asym) = fmap DHTPing $ sequenceA $ fmap uncomposed asym |
diff --git a/ToxAddress.hs b/ToxAddress.hs index ea69f6e3..04ee7d6f 100644 --- a/ToxAddress.hs +++ b/ToxAddress.hs | |||
@@ -13,7 +13,7 @@ | |||
13 | {-# LANGUAGE ScopedTypeVariables #-} | 13 | {-# LANGUAGE ScopedTypeVariables #-} |
14 | {-# LANGUAGE TupleSections #-} | 14 | {-# LANGUAGE TupleSections #-} |
15 | {-# LANGUAGE TypeApplications #-} | 15 | {-# LANGUAGE TypeApplications #-} |
16 | module ToxAddress (NodeInfo(..),NodeId(..),nodeInfo,zeroID) where | 16 | module ToxAddress (NodeInfo(..),NodeId(..),nodeInfo,nodeAddr,zeroID,key2id,id2key) where |
17 | 17 | ||
18 | import Control.Applicative | 18 | import Control.Applicative |
19 | import Control.Monad | 19 | import Control.Monad |
@@ -42,6 +42,7 @@ import System.IO.Unsafe (unsafeDupablePerformIO) | |||
42 | import qualified Text.ParserCombinators.ReadP as RP | 42 | import qualified Text.ParserCombinators.ReadP as RP |
43 | import Text.Read | 43 | import Text.Read |
44 | import Data.Bits | 44 | import Data.Bits |
45 | import ToxCrypto | ||
45 | 46 | ||
46 | -- | perform io for hashes that do allocation and ffi. | 47 | -- | perform io for hashes that do allocation and ffi. |
47 | -- unsafeDupablePerformIO is used when possible as the | 48 | -- unsafeDupablePerformIO is used when possible as the |
@@ -66,6 +67,26 @@ unpackPublicKey bs = loop 0 | |||
66 | newtype NodeId = NodeId PublicKey | 67 | newtype NodeId = NodeId PublicKey |
67 | deriving (Eq,ByteArrayAccess) -- (Eq,Ord,ByteArrayAccess, Bits, Hashable) | 68 | deriving (Eq,ByteArrayAccess) -- (Eq,Ord,ByteArrayAccess, Bits, Hashable) |
68 | 69 | ||
70 | key2id :: PublicKey -> NodeId | ||
71 | key2id = NodeId | ||
72 | |||
73 | id2key :: NodeId -> PublicKey | ||
74 | id2key (NodeId key) = key | ||
75 | |||
76 | {- | ||
77 | id2key :: NodeId -> PublicKey | ||
78 | id2key recipient = case publicKey recipient of | ||
79 | CryptoPassed key -> key | ||
80 | -- This should never happen because a NodeId is 32 bytes. | ||
81 | CryptoFailed e -> error ("Unexpected pattern fail: "++show e) | ||
82 | |||
83 | key2id :: PublicKey -> NodeId | ||
84 | key2id pk = case S.decode (BA.convert pk) of | ||
85 | Left _ -> error "key2id" | ||
86 | Right nid -> nid | ||
87 | |||
88 | -} | ||
89 | |||
69 | instance Ord NodeId where | 90 | instance Ord NodeId where |
70 | compare (NodeId a) (NodeId b) = compare (unpackPublicKey a) (unpackPublicKey b) | 91 | compare (NodeId a) (NodeId b) = compare (unpackPublicKey a) (unpackPublicKey b) |
71 | 92 | ||
@@ -83,8 +104,8 @@ instance Show NodeId where | |||
83 | show (NodeId bs) = C8.unpack $ Base16.encode $ BA.convert bs | 104 | show (NodeId bs) = C8.unpack $ Base16.encode $ BA.convert bs |
84 | 105 | ||
85 | instance S.Serialize NodeId where | 106 | instance S.Serialize NodeId where |
86 | get = NodeId . throwCryptoError . publicKey <$> S.getBytes 32 | 107 | get = NodeId <$> getPublicKey |
87 | put (NodeId bs) = S.putByteString $ BA.convert bs | 108 | put (NodeId bs) = putPublicKey bs |
88 | 109 | ||
89 | instance Bits NodeId where -- TODO | 110 | instance Bits NodeId where -- TODO |
90 | 111 | ||
@@ -144,6 +165,12 @@ getIP 0x82 = IPv4 <$> S.get -- TODO: TCP | |||
144 | getIP 0x8a = IPv6 <$> S.get -- TODO: TCP | 165 | getIP 0x8a = IPv6 <$> S.get -- TODO: TCP |
145 | getIP x = fail ("unsupported address family ("++show x++")") | 166 | getIP x = fail ("unsupported address family ("++show x++")") |
146 | 167 | ||
168 | instance Sized NodeInfo where | ||
169 | size = VarSize $ \(NodeInfo nid ip port) -> | ||
170 | case ip of | ||
171 | IPv4 _ -> 39 -- 35 + 4 = 1 + 4 + 2 + 32 | ||
172 | IPv6 _ -> 51 -- 35 + 16 = 1 + 16 + 2 + 32 | ||
173 | |||
147 | instance S.Serialize NodeInfo where | 174 | instance S.Serialize NodeInfo where |
148 | get = do | 175 | get = do |
149 | addrfam <- S.get :: S.Get Word8 | 176 | addrfam <- S.get :: S.Get Word8 |
@@ -354,9 +381,6 @@ instance Show NodeInfo where | |||
354 | | IPv6 ip6 <- ip , Just ip4 <- un4map ip6 = shows ip4 | 381 | | IPv6 ip6 <- ip , Just ip4 <- un4map ip6 = shows ip4 |
355 | | otherwise = ('[' :) . shows ip . (']' :) | 382 | | otherwise = ('[' :) . shows ip . (']' :) |
356 | 383 | ||
357 | nodeAddr :: NodeInfo -> SockAddr | ||
358 | nodeAddr (NodeInfo _ ip port) = setPort port $ toSockAddr ip | ||
359 | |||
360 | nodeInfo :: NodeId -> SockAddr -> Either String NodeInfo | 384 | nodeInfo :: NodeId -> SockAddr -> Either String NodeInfo |
361 | nodeInfo nid saddr | 385 | nodeInfo nid saddr |
362 | | Just ip <- fromSockAddr saddr | 386 | | Just ip <- fromSockAddr saddr |
@@ -368,6 +392,10 @@ zeroID = PubKey $ B.replicate 32 0 | |||
368 | 392 | ||
369 | -} | 393 | -} |
370 | 394 | ||
395 | nodeAddr :: NodeInfo -> SockAddr | ||
396 | nodeAddr (NodeInfo _ ip port) = setPort port $ toSockAddr ip | ||
397 | |||
398 | |||
371 | newtype ForwardPath (n::Nat) = ForwardPath ByteString | 399 | newtype ForwardPath (n::Nat) = ForwardPath ByteString |
372 | deriving (Eq, Ord,Data) | 400 | deriving (Eq, Ord,Data) |
373 | 401 | ||
diff --git a/ToxCrypto.hs b/ToxCrypto.hs index c2e2bbeb..e3bc57f9 100644 --- a/ToxCrypto.hs +++ b/ToxCrypto.hs | |||
@@ -9,6 +9,8 @@ | |||
9 | module ToxCrypto | 9 | module ToxCrypto |
10 | ( PublicKey | 10 | ( PublicKey |
11 | , publicKey | 11 | , publicKey |
12 | , getPublicKey | ||
13 | , putPublicKey | ||
12 | , SecretKey | 14 | , SecretKey |
13 | , SymmetricKey(..) | 15 | , SymmetricKey(..) |
14 | , TransportCrypto(..) | 16 | , TransportCrypto(..) |
@@ -16,6 +18,10 @@ module ToxCrypto | |||
16 | , Encrypted8(..) | 18 | , Encrypted8(..) |
17 | , type (∘)(..) | 19 | , type (∘)(..) |
18 | , Assym(..) | 20 | , Assym(..) |
21 | , getAssym | ||
22 | , getAliasedAssym | ||
23 | , putAssym | ||
24 | , putAliasedAssym | ||
19 | , Plain | 25 | , Plain |
20 | , encodePlain | 26 | , encodePlain |
21 | , decodePlain | 27 | , decodePlain |
@@ -49,7 +55,7 @@ import qualified Data.ByteString.Char8 as C8 | |||
49 | import Data.Data | 55 | import Data.Data |
50 | import Data.Kind | 56 | import Data.Kind |
51 | import Data.Ord | 57 | import Data.Ord |
52 | import Data.Serialize | 58 | import Data.Serialize as S |
53 | import Data.Word | 59 | import Data.Word |
54 | import Foreign.Marshal.Alloc | 60 | import Foreign.Marshal.Alloc |
55 | import Foreign.Ptr | 61 | import Foreign.Ptr |
@@ -57,6 +63,7 @@ import Foreign.Storable | |||
57 | import System.Endian | 63 | import System.Endian |
58 | import qualified Data.ByteString.Internal | 64 | import qualified Data.ByteString.Internal |
59 | import Control.Concurrent.STM | 65 | import Control.Concurrent.STM |
66 | import Crypto.Error.Types (CryptoFailable (..), throwCryptoError) | ||
60 | 67 | ||
61 | -- | A 16-byte mac and an arbitrary-length encrypted stream. | 68 | -- | A 16-byte mac and an arbitrary-length encrypted stream. |
62 | newtype Encrypted a = Encrypted ByteString | 69 | newtype Encrypted a = Encrypted ByteString |
@@ -76,6 +83,7 @@ instance Data Auth where | |||
76 | gunfold k z c = k (z (Auth . Poly1305.Auth . (BA.convert :: ByteString -> Bytes))) | 83 | gunfold k z c = k (z (Auth . Poly1305.Auth . (BA.convert :: ByteString -> Bytes))) |
77 | toConstr _ = con_Auth | 84 | toConstr _ = con_Auth |
78 | dataTypeOf _ = mkDataType "ToxMessage" [con_Auth] | 85 | dataTypeOf _ = mkDataType "ToxMessage" [con_Auth] |
86 | con_Auth :: Constr | ||
79 | con_Auth = mkConstr (dataTypeOf (Auth (error "con_Auth"))) "Auth" [] Prefix | 87 | con_Auth = mkConstr (dataTypeOf (Auth (error "con_Auth"))) "Auth" [] Prefix |
80 | instance Serialize Auth where | 88 | instance Serialize Auth where |
81 | get = Auth . Poly1305.Auth . BA.convert <$> getBytes 16 | 89 | get = Auth . Poly1305.Auth . BA.convert <$> getBytes 16 |
@@ -165,6 +173,7 @@ computeSharedSecret sk recipient nonce = State hash crypt | |||
165 | -- Since rs is 32 bytes, this pattern should never fail... | 173 | -- Since rs is 32 bytes, this pattern should never fail... |
166 | Cryptonite.CryptoPassed hash = Poly1305.initialize rs | 174 | Cryptonite.CryptoPassed hash = Poly1305.initialize rs |
167 | 175 | ||
176 | hsalsa20 :: (ByteArrayAccess t, ByteArrayAccess t1) => t1 -> t -> BA.ScrubbedBytes | ||
168 | hsalsa20 k n = BA.append a b | 177 | hsalsa20 k n = BA.append a b |
169 | where | 178 | where |
170 | Salsa.State st = XSalsa.initialize 20 k n | 179 | Salsa.State st = XSalsa.initialize 20 k n |
@@ -241,6 +250,23 @@ data Assym a = Assym | |||
241 | } | 250 | } |
242 | deriving (Functor,Foldable,Traversable) | 251 | deriving (Functor,Foldable,Traversable) |
243 | 252 | ||
253 | -- | Field order: senderKey, then nonce This is the format used by | ||
254 | -- Ping/Pong/GetNodes/SendNodes. | ||
255 | -- | ||
256 | -- See 'getAliasedAssym' if the nonce precedes the key. | ||
257 | getAssym :: Serialize a => Get (Assym a) | ||
258 | getAssym = Assym <$> getPublicKey <*> get <*> get | ||
259 | |||
260 | putAssym :: Serialize a => Assym a -> Put | ||
261 | putAssym (Assym key nonce dta) = putPublicKey key >> put nonce >> put dta | ||
262 | |||
263 | -- | Field order: nonce, and then senderKey. | ||
264 | getAliasedAssym :: Serialize a => Get (Assym a) | ||
265 | getAliasedAssym = flip Assym <$> get <*> getPublicKey <*> get | ||
266 | |||
267 | putAliasedAssym :: Serialize a => Assym a -> Put | ||
268 | putAliasedAssym (Assym key nonce dta) = put nonce >> putPublicKey key >> put dta | ||
269 | |||
244 | newtype SymmetricKey = SymmetricKey ByteString | 270 | newtype SymmetricKey = SymmetricKey ByteString |
245 | 271 | ||
246 | data TransportCrypto = TransportCrypto | 272 | data TransportCrypto = TransportCrypto |
@@ -249,3 +275,9 @@ data TransportCrypto = TransportCrypto | |||
249 | , transportSymmetric :: STM SymmetricKey | 275 | , transportSymmetric :: STM SymmetricKey |
250 | } | 276 | } |
251 | 277 | ||
278 | getPublicKey :: S.Get PublicKey | ||
279 | getPublicKey = throwCryptoError . publicKey <$> S.getBytes 32 | ||
280 | |||
281 | putPublicKey :: PublicKey -> S.Put | ||
282 | putPublicKey bs = S.putByteString $ BA.convert bs | ||
283 | |||