diff options
author | joe <joe@jerkface.net> | 2017-07-09 21:54:39 -0400 |
---|---|---|
committer | joe <joe@jerkface.net> | 2017-07-09 21:54:39 -0400 |
commit | c565ec07f37006a5abb7b3bc5a1b08013fbeb5d7 (patch) | |
tree | 6501a1750f3f460c3bc37d6e18c62e77c7580011 /src/Network/DatagramServer | |
parent | 7808d0e6c96ccdf0431619fa1a688612b8a1f921 (diff) |
Added MAC authentication (hash after encrypt).
Diffstat (limited to 'src/Network/DatagramServer')
-rw-r--r-- | src/Network/DatagramServer/Tox.hs | 70 |
1 files changed, 58 insertions, 12 deletions
diff --git a/src/Network/DatagramServer/Tox.hs b/src/Network/DatagramServer/Tox.hs index 85ee269c..5003f3a4 100644 --- a/src/Network/DatagramServer/Tox.hs +++ b/src/Network/DatagramServer/Tox.hs | |||
@@ -34,7 +34,9 @@ import qualified Network.DatagramServer.Types as Envelope (NodeId) | |||
34 | import Crypto.PubKey.ECC.Types | 34 | import Crypto.PubKey.ECC.Types |
35 | import Crypto.PubKey.Curve25519 | 35 | import Crypto.PubKey.Curve25519 |
36 | import Crypto.ECC.Class | 36 | import Crypto.ECC.Class |
37 | import qualified Crypto.Cipher.XSalsa as Salsa20 | 37 | import qualified Crypto.Cipher.Salsa as Salsa |
38 | import qualified Crypto.Cipher.XSalsa as XSalsa | ||
39 | import qualified Crypto.MAC.Poly1305 as Poly1305 | ||
38 | import Data.LargeWord | 40 | import Data.LargeWord |
39 | import Foreign.Ptr | 41 | import Foreign.Ptr |
40 | import Foreign.Storable | 42 | import Foreign.Storable |
@@ -42,10 +44,13 @@ import Foreign.Marshal.Alloc | |||
42 | import Data.Typeable | 44 | import Data.Typeable |
43 | import StaticAssert | 45 | import StaticAssert |
44 | import Crypto.Error.Types | 46 | import Crypto.Error.Types |
47 | import qualified Crypto.Error as Cryptonite | ||
45 | import Data.Hashable | 48 | import Data.Hashable |
46 | import Text.PrettyPrint as PP hiding ((<>)) | 49 | import Text.PrettyPrint as PP hiding ((<>)) |
47 | import Text.PrettyPrint.HughesPJClass hiding (($$), (<>)) | 50 | import Text.PrettyPrint.HughesPJClass hiding (($$), (<>)) |
48 | import Data.ByteArray (convert) | 51 | import qualified Data.ByteArray as BA |
52 | import Data.ByteArray ( Bytes, convert ) | ||
53 | import Data.Monoid | ||
49 | 54 | ||
50 | 55 | ||
51 | type Key32 = Word256 -- 32 byte key | 56 | type Key32 = Word256 -- 32 byte key |
@@ -224,26 +229,29 @@ data ToxCipherContext = ToxCipherContext | |||
224 | { dhtSecretKey :: SecretKey | 229 | { dhtSecretKey :: SecretKey |
225 | } | 230 | } |
226 | 231 | ||
227 | newtype Ciphered = Ciphered { cipheredBytes :: ByteString } | 232 | data Ciphered = Ciphered { cipheredMAC :: Poly1305.Auth |
233 | , cipheredBytes :: ByteString } | ||
228 | 234 | ||
229 | getMessage :: Get (Message Ciphered) | 235 | getMessage :: Get (Message Ciphered) |
230 | getMessage = do | 236 | getMessage = do |
231 | typ <- get | 237 | typ <- get |
232 | nid <- get | 238 | nid <- get |
233 | tid <- get | 239 | tid <- get |
240 | mac <- Poly1305.Auth . convert <$> getBytes 2 | ||
234 | cnt <- remaining | 241 | cnt <- remaining |
235 | bs <- getBytes cnt | 242 | bs <- getBytes cnt |
236 | return Message { msgType = typ | 243 | return Message { msgType = typ |
237 | , msgClient = nid | 244 | , msgClient = nid |
238 | , msgNonce = tid | 245 | , msgNonce = tid |
239 | , msgPayload = Ciphered bs } | 246 | , msgPayload = Ciphered mac bs } |
240 | 247 | ||
241 | putMessage :: Message Ciphered -> Put | 248 | putMessage :: Message Ciphered -> Put |
242 | putMessage (Message {..}) = do | 249 | putMessage (Message {..}) = do |
243 | put msgType | 250 | put msgType |
244 | put msgClient | 251 | put msgClient |
245 | put msgNonce | 252 | put msgNonce |
246 | let Ciphered bs = msgPayload | 253 | let Ciphered (Poly1305.Auth mac) bs = msgPayload |
254 | putByteString (convert mac) | ||
247 | putByteString bs | 255 | putByteString bs |
248 | 256 | ||
249 | id2key :: NodeId Message -> PublicKey | 257 | id2key :: NodeId Message -> PublicKey |
@@ -251,20 +259,58 @@ id2key recipient = case publicKey recipient of | |||
251 | CryptoPassed key -> key | 259 | CryptoPassed key -> key |
252 | CryptoFailed e -> error ("id2key: "++show e) | 260 | CryptoFailed e -> error ("id2key: "++show e) |
253 | 261 | ||
254 | lookupSecret :: ToxCipherContext -> NodeId Message -> TransactionID Message -> Salsa20.State | 262 | |
255 | lookupSecret ctx recipient nonce = Salsa20.initialize 20 key nonce | 263 | zeros32 :: Bytes |
264 | zeros32 = BA.replicate 32 0 | ||
265 | |||
266 | zeros24 :: Bytes | ||
267 | zeros24 = BA.take 24 zeros32 | ||
268 | |||
269 | hsalsa20 k n = a <> b | ||
256 | where | 270 | where |
257 | key = ecdh (Proxy :: Proxy Curve_X25519) (dhtSecretKey ctx) (id2key recipient) -- ByteArrayAccess b => b | 271 | Salsa.State st = XSalsa.initialize 20 k n |
272 | (_, as) = BA.splitAt 4 st | ||
273 | (a, xs) = BA.splitAt 16 as | ||
274 | (_, bs) = BA.splitAt 24 xs | ||
275 | (b, _ ) = BA.splitAt 16 bs | ||
276 | |||
277 | lookupSecret :: ToxCipherContext -> NodeId Message -> TransactionID Message -> (Poly1305.State, XSalsa.State) | ||
278 | lookupSecret ctx recipient nonce = (hash, crypt) | ||
279 | where | ||
280 | -- diffie helman | ||
281 | shared = ecdh (Proxy :: Proxy Curve_X25519) (dhtSecretKey ctx) (id2key recipient) -- ByteArrayAccess b => b | ||
282 | -- shared secret XSalsa key | ||
283 | k = hsalsa20 shared zeros24 | ||
284 | -- cipher state | ||
285 | st0 = XSalsa.initialize 20 k nonce | ||
286 | -- Poly1305 key | ||
287 | (rs, crypt) = XSalsa.combine st0 zeros32 | ||
288 | Cryptonite.CryptoPassed hash = Poly1305.initialize rs -- TODO: Pattern fail? | ||
258 | 289 | ||
259 | decipher :: ToxCipherContext -> Message Ciphered -> Either String (Message ByteString) | 290 | decipher :: ToxCipherContext -> Message Ciphered -> Either String (Message ByteString) |
260 | decipher ctx ciphered = Right (fst . Salsa20.combine st . cipheredBytes <$> ciphered) | 291 | decipher ctx ciphered = mapM (decipherAndAuth hash crypt) ciphered |
261 | where | 292 | where |
262 | st = lookupSecret ctx (msgClient ciphered) (msgNonce ciphered) | 293 | (hash, crypt) = lookupSecret ctx (msgClient ciphered) (msgNonce ciphered) |
263 | 294 | ||
264 | encipher :: ToxCipherContext -> NodeId Message -> Message ByteString -> Message Ciphered | 295 | encipher :: ToxCipherContext -> NodeId Message -> Message ByteString -> Message Ciphered |
265 | encipher ctx recipient plain = Ciphered . fst . Salsa20.combine st <$> plain | 296 | encipher ctx recipient plain = encipherAndHash hash crypt <$> plain |
266 | where | 297 | where |
267 | st = lookupSecret ctx recipient (msgNonce plain) | 298 | (hash, crypt) = lookupSecret ctx recipient (msgNonce plain) |
299 | |||
300 | encipherAndHash :: Poly1305.State -> XSalsa.State -> ByteString -> Ciphered | ||
301 | encipherAndHash hash crypt m = Ciphered a c | ||
302 | where | ||
303 | c = fst . XSalsa.combine crypt $ m | ||
304 | a = Poly1305.finalize . Poly1305.update hash $ c | ||
305 | |||
306 | decipherAndAuth :: Poly1305.State -> XSalsa.State -> Ciphered -> Either String ByteString | ||
307 | decipherAndAuth hash crypt (Ciphered mac c) | ||
308 | | (a == mac) = Right m | ||
309 | | otherwise = Left "decipherAndAuth: auth fail" | ||
310 | where | ||
311 | m = fst . XSalsa.combine crypt $ c | ||
312 | a = Poly1305.finalize . Poly1305.update hash $ c | ||
313 | |||
268 | 314 | ||
269 | -- see rfc7748 | 315 | -- see rfc7748 |
270 | -- | 316 | -- |