diff options
-rw-r--r-- | tox-crypto/src/Crypto/Tox.hs | 66 |
1 files changed, 38 insertions, 28 deletions
diff --git a/tox-crypto/src/Crypto/Tox.hs b/tox-crypto/src/Crypto/Tox.hs index ea276045..04b55d94 100644 --- a/tox-crypto/src/Crypto/Tox.hs +++ b/tox-crypto/src/Crypto/Tox.hs | |||
@@ -294,29 +294,27 @@ encryptPayload st g = | |||
294 | g | 294 | g |
295 | 295 | ||
296 | -- (Poly1305.State, XSalsa.State) | 296 | -- (Poly1305.State, XSalsa.State) |
297 | computeSharedSecret :: SecretKey -> PublicKey -> Nonce24 -> State | 297 | computeSharedSecret :: SecretKey -> PublicKey -> Maybe (Nonce24 -> State) |
298 | computeSharedSecret sk recipient = k `seq` \nonce -> | 298 | computeSharedSecret sk recipient = case mk of |
299 | let -- cipher state | 299 | Just k -> Just $ \nonce -> |
300 | st0 = XSalsa.initialize 20 k nonce | 300 | let -- cipher state |
301 | -- Poly1305 key | 301 | st0 = XSalsa.initialize 20 k nonce |
302 | (rs, crypt) = XSalsa.combine st0 zs where Nonce32 zs = zeros32 | 302 | -- Poly1305 key |
303 | -- Since rs is 32 bytes, this pattern should never fail... | 303 | (rs, crypt) = XSalsa.combine st0 zs where Nonce32 zs = zeros32 |
304 | Cryptonite.CryptoPassed hash = Poly1305.initialize rs | 304 | -- Since rs is 32 bytes, this pattern should never fail... |
305 | in State hash crypt | 305 | Cryptonite.CryptoPassed hash = Poly1305.initialize rs |
306 | in State hash crypt | ||
307 | Nothing -> Nothing | ||
306 | where | 308 | where |
307 | -- diffie helman | 309 | -- diffie helman |
308 | #if MIN_VERSION_cryptonite(0,24,0) | 310 | #if MIN_VERSION_cryptonite(0,24,0) |
309 | -- TODO: Handle failure. | 311 | -- Note This *does* fail. |
310 | -- Failure was observed... | 312 | shared = Cryptonite.maybeCryptoError $ ecdh (Proxy :: Proxy Curve_X25519) sk recipient |
311 | -- Reproduce by issuing tox command "ping 192.168.10.1:33446" without specifying | ||
312 | -- the public key portion of the node id. | ||
313 | -- "Irrefutable pattern failed for pattern CryptoPassed shared" | ||
314 | Cryptonite.CryptoPassed shared = ecdh (Proxy :: Proxy Curve_X25519) sk recipient | ||
315 | #else | 313 | #else |
316 | shared = ecdh (Proxy :: Proxy Curve_X25519) sk recipient | 314 | shared = Just $ ecdh (Proxy :: Proxy Curve_X25519) sk recipient |
317 | #endif | 315 | #endif |
318 | -- shared secret XSalsa key | 316 | -- shared secret XSalsa key |
319 | k = hsalsa20 shared zeros24 | 317 | mk = fmap (`hsalsa20` zeros24) shared |
320 | 318 | ||
321 | unsafeFirstWord64 :: ByteArrayAccess ba => ba -> Word64 | 319 | unsafeFirstWord64 :: ByteArrayAccess ba => ba -> Word64 |
322 | unsafeFirstWord64 ba = unsafeDupablePerformIO $ BA.withByteArray ba peek | 320 | unsafeFirstWord64 ba = unsafeDupablePerformIO $ BA.withByteArray ba peek |
@@ -366,6 +364,15 @@ lookupNonceFunction c@(TransportCrypto{secretsCache}) sk recipient = do | |||
366 | now <- getPOSIXTime | 364 | now <- getPOSIXTime |
367 | atomically $ lookupNonceFunctionSTM now c sk recipient | 365 | atomically $ lookupNonceFunctionSTM now c sk recipient |
368 | 366 | ||
367 | -- | Dummy, used to indicate computeSharedSecret failure. This is a way to provide | ||
368 | -- the old non-failing interface compatibly. | ||
369 | dummyState :: State | ||
370 | dummyState = State hash xsalsa | ||
371 | where | ||
372 | xsalsa = XSalsa.initialize 20 zeros32 zeros24 | ||
373 | -- Since zeros32 is 32 bytes, this pattern should never fail... | ||
374 | Cryptonite.CryptoPassed hash = Poly1305.initialize zeros32 | ||
375 | |||
369 | {-# INLINE lookupNonceFunctionSTM #-} | 376 | {-# INLINE lookupNonceFunctionSTM #-} |
370 | -- | This version of 'lookupNonceFunction' is STM instead of IO, this means if some later part of | 377 | -- | This version of 'lookupNonceFunction' is STM instead of IO, this means if some later part of |
371 | -- of the transaction fails, we may end up forgoing a computation that could have been cached. | 378 | -- of the transaction fails, we may end up forgoing a computation that could have been cached. |
@@ -375,18 +382,21 @@ lookupNonceFunctionSTM :: POSIXTime -> TransportCrypto -> SecretKey -> PublicKey | |||
375 | lookupNonceFunctionSTM now TransportCrypto{secretsCache} sk recipient = do | 382 | lookupNonceFunctionSTM now TransportCrypto{secretsCache} sk recipient = do |
376 | mm <- readTVar $ sharedSecret secretsCache | 383 | mm <- readTVar $ sharedSecret secretsCache |
377 | case MM.lookup' recipient mm of | 384 | case MM.lookup' recipient mm of |
378 | Nothing -> do | 385 | Nothing -> case computeSharedSecret sk recipient of |
379 | let miss = computeSharedSecret sk recipient | 386 | Just miss -> do |
380 | writeTVar (sharedSecret secretsCache) | 387 | writeTVar (sharedSecret secretsCache) |
381 | (MM.insertTake' 160 recipient (MM.singleton' sk miss (Down now)) (Down now) mm) | 388 | (MM.insertTake' 160 recipient (MM.singleton' sk miss (Down now)) (Down now) mm) |
382 | return miss | 389 | return miss |
390 | Nothing -> return $ const dummyState | ||
383 | Just (stamp,smm) -> do | 391 | Just (stamp,smm) -> do |
384 | let (r,v) = case MM.lookup' sk smm of | 392 | let (r,mv) = case MM.lookup' sk smm of |
385 | Nothing | let miss = computeSharedSecret sk recipient | 393 | Nothing | Just miss <- computeSharedSecret sk recipient |
386 | -> (miss, MM.insertTake' 3 sk miss (Down now) smm) | 394 | -> (miss, Just $ MM.insertTake' 3 sk miss (Down now) smm) |
387 | Just (stamp2,hit) -> (hit , MM.insert' sk hit (Down now) smm) | 395 | Nothing -> (const dummyState, Nothing) |
388 | writeTVar (sharedSecret secretsCache) | 396 | Just (stamp2,hit) -> (hit , Just $ MM.insert' sk hit (Down now) smm) |
389 | (MM.insertTake' 160 recipient v (Down now) mm) | 397 | forM_ mv $ \v -> do |
398 | writeTVar (sharedSecret secretsCache) | ||
399 | (MM.insertTake' 160 recipient v (Down now) mm) | ||
390 | return r | 400 | return r |
391 | 401 | ||
392 | 402 | ||