Blame src-tests/test-sha256.hs

Packit f46cda
{-# LANGUAGE OverloadedStrings #-}
Packit f46cda
Packit f46cda
module Main (main) where
Packit f46cda
Packit f46cda
import           Data.ByteString        (ByteString)
Packit f46cda
import qualified Data.ByteString        as B
Packit f46cda
import qualified Data.ByteString.Base16 as B16
Packit f46cda
import qualified Data.ByteString.Lazy   as BL
Packit f46cda
import           Data.Word
Packit f46cda
Packit f46cda
-- reference implementation
Packit f46cda
import qualified Data.Digest.Pure.SHA   as REF
Packit f46cda
Packit f46cda
-- implementation under test
Packit f46cda
import qualified Crypto.Hash.SHA256     as IUT
Packit f46cda
Packit f46cda
import           Test.Tasty
Packit f46cda
import           Test.Tasty.HUnit
Packit f46cda
import           Test.Tasty.QuickCheck  as QC
Packit f46cda
Packit f46cda
vectors :: [ByteString]
Packit f46cda
vectors =
Packit f46cda
    [ ""
Packit f46cda
    , "The quick brown fox jumps over the lazy dog"
Packit f46cda
    , "The quick brown fox jumps over the lazy cog"
Packit f46cda
    , "abc"
Packit f46cda
    , "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
Packit f46cda
    , "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"
Packit f46cda
    , B.replicate 1000000 0x61
Packit f46cda
    ]
Packit f46cda
Packit f46cda
answers :: [ByteString]
Packit f46cda
answers = map (B.filter (/= 0x20))
Packit f46cda
    [ "e3b0c442 98fc1c14 9afbf4c8 996fb924 27ae41e4 649b934c a495991b 7852b855"
Packit f46cda
    , "d7a8fbb3 07d78094 69ca9abc b0082e4f 8d5651e4 6d3cdb76 2d02d0bf 37c9e592"
Packit f46cda
    , "e4c4d8f3 bf76b692 de791a17 3e053211 50f7a345 b46484fe 427f6acc 7ecc81be"
Packit f46cda
    , "ba7816bf 8f01cfea 414140de 5dae2223 b00361a3 96177a9c b410ff61 f20015ad"
Packit f46cda
    , "248d6a61 d20638b8 e5c02693 0c3e6039 a33ce459 64ff2167 f6ecedd4 19db06c1"
Packit f46cda
    , "cf5b16a7 78af8380 036ce59e 7b049237 0b249b11 e8f07a51 afac4503 7afee9d1"
Packit f46cda
    , "cdc76e5c 9914fb92 81a1c7e2 84d73e67 f1809a48 a497200e 046d39cc c7112cd0"
Packit f46cda
    ]
Packit f46cda
Packit f46cda
ansXLTest :: ByteString
Packit f46cda
ansXLTest = B.filter (/= 0x20)
Packit f46cda
    "50e72a0e 26442fe2 552dc393 8ac58658 228c0cbf b1d2ca87 2ae43526 6fcd055e"
Packit f46cda
Packit f46cda
katTests :: [TestTree]
Packit f46cda
katTests
Packit f46cda
  | length vectors == length answers = map makeTest (zip3 [1::Int ..] vectors answers) ++ [xltest]
Packit f46cda
  | otherwise = error "vectors/answers length mismatch"
Packit f46cda
  where
Packit f46cda
    makeTest (i, v, r) = testGroup ("vec"++show i) $
Packit f46cda
        [ testCase "one-pass" (r @=? runTest v)
Packit f46cda
        , testCase "inc-1"    (r @=? runTestInc 1 v)
Packit f46cda
        , testCase "inc-2"    (r @=? runTestInc 2 v)
Packit f46cda
        , testCase "inc-3"    (r @=? runTestInc 3 v)
Packit f46cda
        , testCase "inc-4"    (r @=? runTestInc 4 v)
Packit f46cda
        , testCase "inc-5"    (r @=? runTestInc 5 v)
Packit f46cda
        , testCase "inc-7"    (r @=? runTestInc 7 v)
Packit f46cda
        , testCase "inc-8"    (r @=? runTestInc 8 v)
Packit f46cda
        , testCase "inc-9"    (r @=? runTestInc 9 v)
Packit f46cda
        , testCase "inc-16"   (r @=? runTestInc 16 v)
Packit f46cda
        , testCase "lazy-1"   (r @=? runTestLazy 1 v)
Packit f46cda
        , testCase "lazy-2"   (r @=? runTestLazy 2 v)
Packit f46cda
        , testCase "lazy-7"   (r @=? runTestLazy 7 v)
Packit f46cda
        , testCase "lazy-8"   (r @=? runTestLazy 8 v)
Packit f46cda
        , testCase "lazy-16"  (r @=? runTestLazy 16 v)
Packit f46cda
        ] ++
Packit f46cda
        [ testCase "lazy-63u"  (r @=? runTestLazyU 63 v) | B.length v > 63 ] ++
Packit f46cda
        [ testCase "lazy-65u"  (r @=? runTestLazyU 65 v) | B.length v > 65 ] ++
Packit f46cda
        [ testCase "lazy-97u"  (r @=? runTestLazyU 97 v) | B.length v > 97 ] ++
Packit f46cda
        [ testCase "lazy-131u" (r @=? runTestLazyU 131 v) | B.length v > 131 ]
Packit f46cda
Packit f46cda
    runTest :: ByteString -> ByteString
Packit f46cda
    runTest = B16.encode . IUT.hash
Packit f46cda
Packit f46cda
    runTestInc :: Int -> ByteString -> ByteString
Packit f46cda
    runTestInc i = B16.encode . IUT.finalize . myfoldl' IUT.update IUT.init . splitB i
Packit f46cda
Packit f46cda
    runTestLazy :: Int -> ByteString -> ByteString
Packit f46cda
    runTestLazy i = B16.encode . IUT.hashlazy . BL.fromChunks . splitB i
Packit f46cda
Packit f46cda
    -- force unaligned md5-blocks
Packit f46cda
    runTestLazyU :: Int -> ByteString -> ByteString
Packit f46cda
    runTestLazyU i = B16.encode . IUT.hashlazy . BL.fromChunks . map B.copy . splitB i
Packit f46cda
Packit f46cda
    ----
Packit f46cda
Packit f46cda
    xltest = testGroup "XL-vec"
Packit f46cda
        [ testCase "inc" (ansXLTest @=? (B16.encode . IUT.hashlazy) vecXL) ]
Packit f46cda
      where
Packit f46cda
        vecXL = BL.fromChunks (replicate 16777216 "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno")
Packit f46cda
Packit f46cda
splitB :: Int -> ByteString -> [ByteString]
Packit f46cda
splitB l b
Packit f46cda
  | B.length b > l = b1 : splitB l b2
Packit f46cda
  | otherwise = [b]
Packit f46cda
  where
Packit f46cda
    (b1, b2) = B.splitAt l b
Packit f46cda
Packit f46cda
Packit f46cda
rfc4231Vectors :: [(ByteString,ByteString,ByteString)]
Packit f46cda
rfc4231Vectors = -- (secrect,msg,mac)
Packit f46cda
    [ (rep 20 0x0b, "Hi There", x"b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7")
Packit f46cda
    , ("Jefe", "what do ya want for nothing?", x"5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843")
Packit f46cda
    , (rep 20 0xaa, rep 50 0xdd, x"773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe")
Packit f46cda
    , (B.pack [1..25], rep 50 0xcd, x"82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b")
Packit f46cda
    , (rep 20 0x0c, "Test With Truncation", x"a3b6167473100ee06e0c796c2955552bfa6f7c0a6a8aef8b93f860aab0cd20c5")
Packit f46cda
    , (rep 131 0xaa, "Test Using Larger Than Block-Size Key - Hash Key First", x"60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54")
Packit f46cda
    , (rep 131 0xaa, "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.", x"9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2")
Packit f46cda
    ]
Packit f46cda
  where
Packit f46cda
    x = fst.B16.decode
Packit f46cda
    rep n c = B.replicate n c
Packit f46cda
Packit f46cda
rfc4231Tests :: [TestTree]
Packit f46cda
rfc4231Tests = zipWith makeTest [1::Int ..] rfc4231Vectors
Packit f46cda
  where
Packit f46cda
    makeTest i (key, msg, mac) = testGroup ("vec"++show i) $
Packit f46cda
        [ testCase "hmac" (hex mac  @=? hex (IUT.hmac key msg))
Packit f46cda
        , testCase "hmaclazy" (hex mac  @=? hex (IUT.hmaclazy key lazymsg))
Packit f46cda
        ]
Packit f46cda
      where
Packit f46cda
        lazymsg = BL.fromChunks . splitB 1 $ msg
Packit f46cda
Packit f46cda
    hex = B16.encode
Packit f46cda
Packit f46cda
rfc5869Vectors :: [(Int,ByteString,ByteString,ByteString,ByteString)]
Packit f46cda
rfc5869Vectors = -- (l,ikm,salt,info,okm)
Packit f46cda
    [ (42, rep 22 0x0b, x"000102030405060708090a0b0c", x"f0f1f2f3f4f5f6f7f8f9", x"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865")
Packit f46cda
    , ( 82
Packit f46cda
      , x"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"
Packit f46cda
      , x"606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
Packit f46cda
      , x"b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"
Packit f46cda
      , x"b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87"
Packit f46cda
      )
Packit f46cda
    , ( 42, rep 22 0x0b, "", "", x"8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8")
Packit f46cda
    ]
Packit f46cda
  where
Packit f46cda
    x = fst.B16.decode
Packit f46cda
    rep n c = B.replicate n c
Packit f46cda
Packit f46cda
rfc5869Tests :: [TestTree]
Packit f46cda
rfc5869Tests = zipWith makeTest [1::Int ..] rfc5869Vectors
Packit f46cda
  where
Packit f46cda
    makeTest i (l,ikm,salt,info,okm) = testGroup ("vec"++show i) $
Packit f46cda
        [ testCase "hkdf" (hex okm @=? hex (IUT.hkdf ikm salt info l)) ]
Packit f46cda
Packit f46cda
    hex = B16.encode
Packit f46cda
Packit f46cda
-- define own 'foldl' here to avoid RULE rewriting to 'hashlazy'
Packit f46cda
myfoldl' :: (b -> a -> b) -> b -> [a] -> b
Packit f46cda
myfoldl' f z0 xs0 = lgo z0 xs0
Packit f46cda
  where
Packit f46cda
    lgo z []     = z
Packit f46cda
    lgo z (x:xs) = let z' = f z x
Packit f46cda
                   in z' `seq` lgo z' xs
Packit f46cda
Packit f46cda
newtype RandBS = RandBS { unRandBS :: ByteString }
Packit f46cda
newtype RandLBS = RandLBS BL.ByteString
Packit f46cda
Packit f46cda
instance Arbitrary RandBS where
Packit f46cda
    arbitrary = fmap (RandBS . B.pack) arbitrary
Packit f46cda
    shrink (RandBS x) = fmap RandBS (go x)
Packit f46cda
      where
Packit f46cda
        go bs = zipWith B.append (B.inits bs) (tail $ B.tails bs)
Packit f46cda
Packit f46cda
instance Show RandBS where
Packit f46cda
    show (RandBS x) = "RandBS {len=" ++ show (B.length x)++"}"
Packit f46cda
Packit f46cda
instance Arbitrary RandLBS where
Packit f46cda
    arbitrary = fmap (RandLBS . BL.fromChunks . map unRandBS) arbitrary
Packit f46cda
Packit f46cda
instance Show RandLBS where
Packit f46cda
    show (RandLBS x) = "RandLBS {len=" ++ show (BL.length x) ++ ", chunks=" ++ show (length $ BL.toChunks x)++"}"
Packit f46cda
Packit f46cda
Packit f46cda
refImplTests :: [TestTree]
Packit f46cda
refImplTests =
Packit f46cda
    [ testProperty "hash" prop_hash
Packit f46cda
    , testProperty "hashlazy" prop_hashlazy
Packit f46cda
    , testProperty "hashlazyAndLength" prop_hashlazyAndLength
Packit f46cda
    , testProperty "hmac" prop_hmac
Packit f46cda
    , testProperty "hmaclazy" prop_hmaclazy
Packit f46cda
    , testProperty "hmaclazyAndLength" prop_hmaclazyAndLength
Packit f46cda
    ]
Packit f46cda
  where
Packit f46cda
    prop_hash (RandBS bs)
Packit f46cda
        = ref_hash bs == IUT.hash bs
Packit f46cda
Packit f46cda
    prop_hashlazy (RandLBS bs)
Packit f46cda
        = ref_hashlazy bs == IUT.hashlazy bs
Packit f46cda
Packit f46cda
    prop_hashlazyAndLength (RandLBS bs)
Packit f46cda
        = ref_hashlazyAndLength bs == IUT.hashlazyAndLength bs
Packit f46cda
Packit f46cda
    prop_hmac (RandBS k) (RandBS bs)
Packit f46cda
        = ref_hmac k bs == IUT.hmac k bs
Packit f46cda
Packit f46cda
    prop_hmaclazy (RandBS k) (RandLBS bs)
Packit f46cda
        = ref_hmaclazy k bs == IUT.hmaclazy k bs
Packit f46cda
Packit f46cda
    prop_hmaclazyAndLength (RandBS k) (RandLBS bs)
Packit f46cda
        = ref_hmaclazyAndLength k bs == IUT.hmaclazyAndLength k bs
Packit f46cda
Packit f46cda
    ref_hash :: ByteString -> ByteString
Packit f46cda
    ref_hash = ref_hashlazy . fromStrict
Packit f46cda
Packit f46cda
    ref_hashlazy :: BL.ByteString -> ByteString
Packit f46cda
    ref_hashlazy = toStrict . REF.bytestringDigest . REF.sha256
Packit f46cda
Packit f46cda
    ref_hashlazyAndLength :: BL.ByteString -> (ByteString,Word64)
Packit f46cda
    ref_hashlazyAndLength x = (ref_hashlazy x, fromIntegral (BL.length x))
Packit f46cda
Packit f46cda
    ref_hmac :: ByteString -> ByteString -> ByteString
Packit f46cda
    ref_hmac secret = ref_hmaclazy secret . fromStrict
Packit f46cda
Packit f46cda
    ref_hmaclazy :: ByteString -> BL.ByteString -> ByteString
Packit f46cda
    ref_hmaclazy secret = toStrict . REF.bytestringDigest . REF.hmacSha256 (fromStrict secret)
Packit f46cda
Packit f46cda
    ref_hmaclazyAndLength :: ByteString -> BL.ByteString -> (ByteString,Word64)
Packit f46cda
    ref_hmaclazyAndLength secret msg = (ref_hmaclazy secret msg, fromIntegral (BL.length msg))
Packit f46cda
Packit f46cda
    -- toStrict/fromStrict only available with bytestring-0.10 and later
Packit f46cda
    toStrict = B.concat . BL.toChunks
Packit f46cda
    fromStrict = BL.fromChunks . (:[])
Packit f46cda
Packit f46cda
main :: IO ()
Packit f46cda
main = defaultMain $ testGroup "cryptohash-sha256"
Packit f46cda
    [ testGroup "KATs" katTests
Packit f46cda
    , testGroup "RFC4231" rfc4231Tests
Packit f46cda
    , testGroup "RFC5869" rfc5869Tests
Packit f46cda
    , testGroup "REF" refImplTests
Packit f46cda
    ]