|
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 |
]
|