packages feed

cryptohash 0.8.2 → 0.8.3

raw patch · 4 files changed

+117/−30 lines, 4 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Crypto.Hash: HMAC :: ByteString -> HMAC a
+ Crypto.Hash: data HMAC a
+ Crypto.Hash: hmac :: HashFunctionBS a -> Int -> ByteString -> ByteString -> HMAC a
+ Crypto.Hash: hmacToByteString :: HMAC a -> ByteString
+ Crypto.Hash: instance Eq (HMAC a)
+ Crypto.Hash: type HashFunctionBS a = ByteString -> Digest a
+ Crypto.Hash: type HashFunctionLBS a = ByteString -> Digest a

Files

Crypto/Hash.hs view
@@ -13,6 +13,8 @@     (     -- * Types       HashAlgorithm(..)+    , HashFunctionBS+    , HashFunctionLBS     , Context     , Digest     -- * Functions@@ -43,12 +45,17 @@     , Skein512_384     , Skein512_512     , Whirlpool+    -- * MAC algorithms+    , HMAC(..)+    , hmac     )     where  import Crypto.Hash.Types import Crypto.Hash.Utils import Data.ByteString (ByteString)+import Data.Bits (xor)+import Data.List (foldl') import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as L @@ -67,6 +74,12 @@ import qualified Crypto.Hash.Skein512 as Skein512 import qualified Crypto.Hash.Whirlpool as Whirlpool +-- | Alias to a single pass hash function that operate on a strict bytestring+type HashFunctionBS a = ByteString -> Digest a++-- | Alias to a single pass hash function that operate on a lazy bytestring+type HashFunctionLBS a = L.ByteString -> Digest a+ -- | run hashUpdates on one single bytestring and return the updated context. hashUpdate :: HashAlgorithm a => Context a -> ByteString -> Context a hashUpdate ctx b = hashUpdates ctx [b]@@ -126,3 +139,32 @@ DEFINE_INSTANCE_LEN(Skein512_256, Skein512, 256) DEFINE_INSTANCE_LEN(Skein512_384, Skein512, 384) DEFINE_INSTANCE_LEN(Skein512_512, Skein512, 512)++-- | Represent an HMAC that is phantom types with the hash used to produce the mac.+--+-- The Eq instance is constant time.+data HMAC a = HMAC { hmacToByteString :: ByteString -- ^ return the binary HMAC+                   }++instance Eq (HMAC a) where+    (HMAC b1) == (HMAC b2)+        | B.length b1 /= B.length b2 = False+        | otherwise                  = foldl' (&&!) True $ B.zipWith (==) b1 b2+            where True  &&! True  = True+                  True  &&! False = False+                  False &&! True  = False+                  False &&! False = False++-- | compute a MAC using the supplied hashing function+hmac :: HashFunctionBS a -- ^ Hash function to use+     -> Int              -- ^ Block size in bytes of the hash function+     -> ByteString       -- ^ Secret key+     -> ByteString       -- ^ Message to MAC+     -> HMAC a+hmac hashF blockSize secret msg = HMAC $ digestToByteString $ hashF $ B.append opad (digestToByteString $ hashF $ B.append ipad msg)+    where opad = B.map (xor 0x5c) k'+          ipad = B.map (xor 0x36) k'++          k'  = B.append kt pad+          kt  = if B.length secret > fromIntegral blockSize then digestToByteString (hashF secret) else secret+          pad = B.replicate (fromIntegral blockSize - B.length kt) 0
Crypto/MAC/HMAC.hs view
@@ -18,10 +18,10 @@  -- | compute a MAC using the supplied hashing function hmac :: (ByteString -> ByteString) -> Int -> ByteString -> ByteString -> ByteString-hmac f blockSize secret msg = f $ B.append opad (f $ B.append ipad msg) where-    opad = B.map (xor 0x5c) k'-    ipad = B.map (xor 0x36) k'+hmac hashF blockSize secret msg = hashF $ B.append opad (hashF $ B.append ipad msg)+    where opad = B.map (xor 0x5c) k'+          ipad = B.map (xor 0x36) k' -    k' = B.append kt pad-    kt = if B.length secret > fromIntegral blockSize then f secret else secret-    pad = B.replicate (fromIntegral blockSize - B.length kt) 0+          k'  = B.append kt pad+          kt  = if B.length secret > fromIntegral blockSize then hashF secret else secret+          pad = B.replicate (fromIntegral blockSize - B.length kt) 0
Tests/KAT.hs view
@@ -1,8 +1,11 @@-import Test.HUnit+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ViewPatterns #-} import Data.Char import Data.Bits import Data.Word+import Data.ByteString (ByteString) import qualified Data.ByteString as B+import qualified Data.ByteString.Char8 as BC import qualified Crypto.Hash.MD2 as MD2 import qualified Crypto.Hash.MD4 as MD4 import qualified Crypto.Hash.MD5 as MD5@@ -19,7 +22,14 @@ import qualified Crypto.Hash.Skein512 as Skein512 import qualified Crypto.Hash.Whirlpool as Whirlpool import Crypto.Hash+import qualified Crypto.MAC.HMAC as HMAC +import Test.Framework (Test, defaultMain, testGroup)+import Test.Framework.Providers.QuickCheck2 (testProperty)+import Test.Framework.Providers.HUnit+import Test.HUnit ((@=?))++v0,v1,v2 :: ByteString v0 = "" v1 = "The quick brown fox jumps over the lazy dog" v2 = "The quick brown fox jumps over the lazy cog"@@ -161,6 +171,7 @@ hexaliseB :: B.ByteString -> B.ByteString hexaliseB = B.pack . hexalise . B.unpack +splitB :: Int -> ByteString -> [ByteString] splitB l b =     if B.length b > l         then@@ -175,36 +186,70 @@ runhash hash v = showHash $ (fctHash hash) $ v runhashinc hash v = showHash $ (fctInc hash) $ v -makeTestAlg (name, hash, results) = concatMap maketest $ zip3 [0..] vectors results+makeTestAlg (name, hash, results) = testGroup name $ concatMap maketest (zip3 [0..] vectors results)     where-        testname i = name ++ " " ++ show i-        runtest v = runhash hash $ B.pack $ map (toEnum.fromEnum) v+        runtest :: ByteString -> String+        runtest v = runhash hash v -        runtestinc i v = runhashinc hash $ splitB i $ B.pack $ map (toEnum.fromEnum) v+        runtestinc :: Int -> ByteString -> String+        runtestinc i v = runhashinc hash $ splitB i v          maketest (i, v, r) =-            [ testname i ~: r ~=? (runtest v),-              testname i ~: r ~=? (runtestinc 1 v),-              testname i ~: r ~=? (runtestinc 2 v),-              testname i ~: r ~=? (runtestinc 3 v),-              testname i ~: r ~=? (runtestinc 4 v),-              testname i ~: r ~=? (runtestinc 5 v),-              testname i ~: r ~=? (runtestinc 9 v),-              testname i ~: r ~=? (runtestinc 16 v) ]+            [ testCase (show i ++ " one-pass") (r @=? runtest v)+            , testCase (show i ++ " inc 1") (r @=? runtestinc 1 v)+            , testCase (show i ++ " inc 2") (r @=? runtestinc 2 v)+            , testCase (show i ++ " inc 3") (r @=? runtestinc 3 v)+            , testCase (show i ++ " inc 4") (r @=? runtestinc 4 v)+            , testCase (show i ++ " inc 5") (r @=? runtestinc 5 v)+            , testCase (show i ++ " inc 9") (r @=? runtestinc 9 v)+            , testCase (show i ++ " inc 16") (r @=? runtestinc 16 v)+            ] -mapTests :: [Test]-mapTests = concatMap makeTestAlg results+katTests :: [Test]+katTests = map makeTestAlg results  apiTests :: [Test] apiTests =-    [ "sha1 api" ~: runhash sha1Hash B.empty ~=? show (hash B.empty :: Digest SHA1)-    , "sha256 api" ~: runhash sha256Hash B.empty ~=? show (hash B.empty :: Digest SHA256)-    , "sha512 api" ~: runhash sha512Hash B.empty ~=? show (hash B.empty :: Digest SHA512)-    , "sha3-224 api" ~: runhash (sha3Hash 224) B.empty ~=? show (hash B.empty :: Digest SHA3_224)-    , "sha3-256 api" ~: runhash (sha3Hash 256) B.empty ~=? show (hash B.empty :: Digest SHA3_256)-    , "sha3-512 api" ~: runhash (sha3Hash 512) B.empty ~=? show (hash B.empty :: Digest SHA3_512)+    [ testCase "sha1 api" (runhash sha1Hash B.empty @=? show (hash B.empty :: Digest SHA1))+    , testCase "sha256 api" (runhash sha256Hash B.empty @=? show (hash B.empty :: Digest SHA256))+    , testCase "sha512 api" (runhash sha512Hash B.empty @=? show (hash B.empty :: Digest SHA512))+    , testCase "sha3-224 api" (runhash (sha3Hash 224) B.empty @=? show (hash B.empty :: Digest SHA3_224))+    , testCase "sha3-256 api" (runhash (sha3Hash 256) B.empty @=? show (hash B.empty :: Digest SHA3_256))+    , testCase "sha3-512 api" (runhash (sha3Hash 512) B.empty @=? show (hash B.empty :: Digest SHA3_512))     ] -tests = TestList (mapTests ++ apiTests) -main = runTestTT tests+data MACVector = MACVector { macKey :: ByteString+                           , macSecret :: ByteString+                           , macResult :: ByteString+                           }++md5MACVectors =+    [ MACVector B.empty B.empty "\x74\xe6\xf7\x29\x8a\x9c\x2d\x16\x89\x35\xf5\x8c\x00\x1b\xad\x88"+    , MACVector "key"   v1      "\x80\x07\x07\x13\x46\x3e\x77\x49\xb9\x0c\x2d\xc2\x49\x11\xe2\x75"+    ]++sha1MACVectors =+    [ MACVector B.empty B.empty "\xfb\xdb\x1d\x1b\x18\xaa\x6c\x08\x32\x4b\x7d\x64\xb7\x1f\xb7\x63\x70\x69\x0e\x1d"+    , MACVector "key"   v1      "\xde\x7c\x9b\x85\xb8\xb7\x8a\xa6\xbc\x8a\x7a\x36\xf7\x0a\x90\x70\x1c\x9d\xb4\xd9"+    ]++sha256MACVectors =+    [ MACVector B.empty B.empty "\xb6\x13\x67\x9a\x08\x14\xd9\xec\x77\x2f\x95\xd7\x78\xc3\x5f\xc5\xff\x16\x97\xc4\x93\x71\x56\x53\xc6\xc7\x12\x14\x42\x92\xc5\xad"+    , MACVector "key"   v1      "\xf7\xbc\x83\xf4\x30\x53\x84\x24\xb1\x32\x98\xe6\xaa\x6f\xb1\x43\xef\x4d\x59\xa1\x49\x46\x17\x59\x97\x47\x9d\xbc\x2d\x1a\x3c\xd8"+    ]++macTests :: [Test]+macTests =+    [ testGroup "hmac-md5" $ map (toMACTest MD5.hash 64) $ zip [0..] md5MACVectors+    , testGroup "hmac-sha1" $ map (toMACTest SHA1.hash 64) $ zip [0..] sha1MACVectors+    , testGroup "hmac-sha256" $ map (toMACTest SHA256.hash 64) $ zip [0..] sha256MACVectors+    ]+    where toMACTest hashF blockSize (i, macVector) =+            testCase (show i) (macResult macVector @=? HMAC.hmac hashF blockSize (macKey macVector) (macSecret macVector))++main = defaultMain+    [ testGroup "KATs" katTests+    , testGroup "API" apiTests+    , testGroup "MACs" macTests+    ]
cryptohash.cabal view
@@ -1,5 +1,5 @@ Name:                cryptohash-Version:             0.8.2+Version:             0.8.3 Description:     A collection of crypto hashes, with a practical incremental and one-pass, pure APIs,     with performance close to the fastest implementations available in others languages.