RoundTrips.hs 3.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. {-# LANGUAGE OverloadedStrings #-}
  2. module RoundTrips (tests) where
  3. import Distribution.TestSuite
  4. import Base (simpleTest)
  5. import Data.ByteString (ByteString)
  6. import qualified Data.ByteString.Lazy as LBS
  7. import qualified Data.ByteString.Lazy.Char8 as C8
  8. import qualified Data.ByteString.Char8 as SC8
  9. import Crypto.Error
  10. import Crypto.Chunked
  11. import Crypto.ChunkedAlgorithms
  12. tests :: IO [Test]
  13. tests = return [
  14. simpleTest "Check MAC size" checkMacSize,
  15. simpleTest "Good round trip" goodRoundTrip,
  16. simpleTest "Auth error" authError
  17. ]
  18. testKey :: ByteString
  19. testKey = SC8.pack "01234567890123456789012345678901"
  20. testNonce :: ByteString
  21. testNonce = SC8.pack "012345678901"
  22. testString :: LBS.ByteString
  23. testString = C8.pack $ unlines [
  24. "ChaCha20 and Poly1305 for IETF Protocols",
  25. "Abstract",
  26. "This document defines the ChaCha20 stream cipher as well as the use",
  27. "of the Poly1305 authenticator, both as stand-alone algorithms and as",
  28. "a combined mode, or Authenticated Encryption with Associated Data",
  29. "(AEAD) algorithm.",
  30. "This document does not introduce any new crypto, but is meant to",
  31. "serve as a stable reference and an implementation guide. It is a",
  32. "product of the Crypto Forum Research Group (CFRG).",
  33. "Status of This Memo",
  34. "This document is not an Internet Standards Track specification; it is",
  35. "published for informational purposes.",
  36. "This document is a product of the Internet Research Task Force",
  37. "(IRTF). The IRTF publishes the results of Internet-related research",
  38. "and development activities. These results might not be suitable for",
  39. "deployment. This RFC represents the consensus of the Crypto Forum",
  40. "Research Group of the Internet Research Task Force (IRTF). Documents",
  41. "approved for publication by the IRSG are not a candidate for any",
  42. "level of Internet Standard; see Section 2 of RFC 5741.",
  43. "Information about the current status of this document, any errata,",
  44. "and how to provide feedback on it may be obtained at",
  45. "http://www.rfc-editor.org/info/rfc7539."
  46. ]
  47. checkMacSize :: IO Progress
  48. checkMacSize = do
  49. let algo = chunkedChaChaPoly1305 32 testKey
  50. (enc, fails1) = encrypt algo testNonce 0 testString
  51. case sequence fails1 of
  52. CryptoFailed e -> return . Finished . Fail $ "Crypto failed: " ++ show e
  53. CryptoPassed _ -> let
  54. nchunks = LBS.length testString `div` plainSize algo
  55. modchunks = LBS.length testString `mod` plainSize algo
  56. expsize = nchunks * encryptedSize algo + modchunks + (encryptedSize algo - plainSize algo)
  57. in if expsize == LBS.length enc
  58. then return . Finished $ Pass
  59. else return . Finished . Fail $ "Sizes mismatch. Original size is " ++ show (LBS.length testString) ++
  60. " encrypted text size is " ++ show (LBS.length enc) ++ " extimated size is " ++ show expsize
  61. goodRoundTrip :: IO Progress
  62. goodRoundTrip = do
  63. let algo = chunkedChaChaPoly1305 32 testKey
  64. (enc, fails1) = encrypt algo testNonce 0 testString
  65. (dec, fails2) = decrypt algo testNonce 0 enc
  66. case sequence_ fails1 >> sequence fails2 of
  67. CryptoPassed _ -> if dec == testString
  68. then return . Finished $ Pass
  69. else return . Finished . Fail $ "Text differs: " ++ C8.unpack dec
  70. CryptoFailed e -> return . Finished . Fail $ "Crypto failed: " ++ show e
  71. authError :: IO Progress
  72. authError = do
  73. let algo = chunkedChaChaPoly1305 32 testKey
  74. (enc, fails1) = encrypt algo testNonce 0 testString
  75. case LBS.uncons enc of
  76. Nothing -> return . Finished . Fail $ "Empty encrypted text!"
  77. Just (t, tt) -> do
  78. let enc' = LBS.cons (t+1) tt
  79. (dec, fails2) = decrypt algo testNonce 0 enc'
  80. case sequence_ fails1 >> sequence fails2 of
  81. CryptoFailed CryptoError_MacKeyInvalid -> return . Finished $ Pass
  82. CryptoFailed e -> return . Finished . Fail $ "Crypto failed: " ++ show e
  83. CryptoPassed _ -> return . Finished . Fail $ "Got decrypted text: " ++ C8.unpack dec