{-# LANGUAGE Rank2Types #-} -- from base import Control.Applicative ((<$>)) import Control.Monad.ST (runST) import Data.Word (Word8) -- from bytestring import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as L -- from crypto-api import Crypto.Classes ((.::.)) import qualified Crypto.Classes as C import qualified Crypto.HMAC as C import qualified Crypto.Modes as CM --import qualified Crypto.Padding as C --import qualified Crypto.Random as C import qualified Crypto.Types as C -- from conduit import Data.Conduit import Data.Conduit.Binary (isolate) import Data.Conduit.List (sourceList, consume) -- from cryptohash-cryptoapi import Crypto.Hash.CryptoAPI ( MD2, MD4, MD5, RIPEMD160, SHA1, SHA224 , SHA256, SHA384, SHA512, Tiger ) -- from skein import qualified Crypto.Skein as Skein -- from hspec import Test.Hspec import Test.Hspec.QuickCheck -- from this package import Crypto.Conduit main :: IO () main = hspec $ do describe "cryptohash's MD2" $ testHash (undefined :: MD2) describe "cryptohash's MD4" $ testHash (undefined :: MD4) describe "cryptohash's MD5" $ testHash (undefined :: MD5) describe "cryptohash's RIPEMD160" $ testHash (undefined :: RIPEMD160) describe "cryptohash's SHA1" $ testHash (undefined :: SHA1) describe "cryptohash's SHA224" $ testHash (undefined :: SHA224) describe "cryptohash's SHA256" $ testHash (undefined :: SHA256) describe "cryptohash's SHA384" $ testHash (undefined :: SHA384) describe "cryptohash's SHA512" $ testHash (undefined :: SHA512) describe "cryptohash's Tiger" $ testHash (undefined :: Tiger) describe "skein's Skein_512_512" $ testHash (undefined :: Skein.Skein_512_512) describe "skein's Skein_1024_1024" $ testHash (undefined :: Skein.Skein_1024_1024) describe "skein's Skein_256_256" $ testHash (undefined :: Skein.Skein_256_256) describe "skein's Skein_256_128" $ testHash (undefined :: Skein.Skein_256_128) describe "skein's Skein_256_160" $ testHash (undefined :: Skein.Skein_256_160) describe "skein's Skein_256_224" $ testHash (undefined :: Skein.Skein_256_224) describe "skein's Skein_512_128" $ testHash (undefined :: Skein.Skein_512_128) describe "skein's Skein_512_160" $ testHash (undefined :: Skein.Skein_512_160) describe "skein's Skein_512_224" $ testHash (undefined :: Skein.Skein_512_224) describe "skein's Skein_512_256" $ testHash (undefined :: Skein.Skein_512_256) describe "skein's Skein_512_384" $ testHash (undefined :: Skein.Skein_512_384) describe "skein's Skein_1024_384" $ testHash (undefined :: Skein.Skein_1024_384) describe "skein's Skein_1024_512" $ testHash (undefined :: Skein.Skein_1024_512) ---------------------------------------------------------------------- testHash :: C.Hash ctx d => d -> Spec testHash d = do prop "works with sinkHash" $ \str -> prop_sinkHash d (L.pack str) prop "works with sinkHmac" $ \key str -> prop_sinkHmac d (C.MacKey $ B.pack key) (L.pack str) prop_sinkHash :: C.Hash ctx d => d -> L.ByteString -> Bool prop_sinkHash d input = let d1 = runPureResource $ sourceList (L.toChunks input) $$ sinkHash d2 = C.hashFunc d input in d1 == d2 prop_sinkHmac :: C.Hash ctx d => d -> C.MacKey ctx d -> L.ByteString -> Bool prop_sinkHmac d mackey input = let d1 = runPureResource $ sourceList (L.toChunks input) $$ sinkHmac mackey d2 = C.hmac mackey input `asTypeOf` d in d1 == d2 ---------------------------------------------------------------------- testBlockCipher :: C.BlockCipher k => k -> Spec testBlockCipher undefinedKey = do let Just k = let len = (C.keyLength .::. k) `div` 8 in C.buildKey (B.replicate len 0xFF) `asTypeOf` Just undefinedKey blockSize = (C.blockSize .::. k) `div` 8 prop "works with conduitEncryptEcb" $ testBlockCipherConduit (Just blockSize) (conduitEncryptEcb k) (C.ecb k) prop "works with conduitDecryptEcb" $ testBlockCipherConduit (Just blockSize) (conduitDecryptEcb k) (C.unEcb k) prop "works with conduitEncryptCbc" $ testBlockCipherConduit (Just blockSize) (conduitEncryptCbc k C.zeroIV) (fst . C.cbc k C.zeroIV) prop "works with conduitDecryptCbc" $ testBlockCipherConduit (Just blockSize) (conduitDecryptCbc k C.zeroIV) (fst . C.unCbc k C.zeroIV) prop "works with conduitEncryptCfb" $ testBlockCipherConduit (Just blockSize) (conduitEncryptCfb k C.zeroIV) (fst . C.cfb k C.zeroIV) prop "works with conduitDecryptCfb" $ testBlockCipherConduit (Just blockSize) (conduitDecryptCfb k C.zeroIV) (fst . C.unCfb k C.zeroIV) prop "works with conduitEncryptOfb" $ testBlockCipherConduit (Just blockSize) (conduitEncryptOfb k C.zeroIV) (fst . C.ofb k C.zeroIV) prop "works with conduitDecryptOfb" $ testBlockCipherConduit (Just blockSize) (conduitDecryptOfb k C.zeroIV) (fst . C.unOfb k C.zeroIV) prop "works with conduitEncryptCtr" $ testBlockCipherConduit Nothing (conduitEncryptCtr k C.zeroIV C.incIV) (fst . C.ctr k C.zeroIV) prop "works with conduitDecryptCtr" $ testBlockCipherConduit Nothing (conduitDecryptCtr k C.zeroIV C.incIV) (fst . C.unCtr k C.zeroIV) it "works with sourceCtr" $ let len :: Num a => a len = 1024 * 1024 -- 1 MiB r1 = runPureResource $ sourceCtr k C.zeroIV $$ isolate len =$ consumeAsStrict r2 = fst $ C.ctr k C.zeroIV (B.replicate len 0) in r1 == r2 prop "works with sinkCbcMac" $ \input -> let inputL = fixBlockedSize blockSize (L.pack input) r1 = runPureResource $ sourceList (L.toChunks inputL) $$ sinkCbcMac k r2 = C.encode $ snd $ C.cbc k C.zeroIV $ B.pack input in r1 == r2 testBlockCipherConduit :: Maybe C.ByteLength -- ^ Fix input length to be a multiple of the block size? -> (forall m. Monad m => Conduit B.ByteString m B.ByteString) -> (B.ByteString -> B.ByteString) -> [Word8] -> Bool testBlockCipherConduit mblockSize conduit strictfun input = let inputL = maybe id fixBlockedSize mblockSize (L.pack input) r1 = runPureResource $ sourceList (L.toChunks inputL) $$ conduit =$ consumeAsStrict r2 = strictfun $ B.pack input in r1 == r2 ---------------------------------------------------------------------- runPureResource :: (forall m. Monad m => m a) -> a runPureResource r = runST r consumeAsLazy :: Monad m => Sink B.ByteString m L.ByteString consumeAsLazy = L.fromChunks <$> consume consumeAsStrict :: Monad m => Sink B.ByteString m B.ByteString consumeAsStrict = B.concat <$> consume fixBlockedSize :: C.ByteLength -> L.ByteString -> L.ByteString fixBlockedSize blockSize lbs = let blockSize' = fromIntegral blockSize toFill = let leftovers = L.length lbs `mod` blockSize' in if leftovers == 0 then 0 else blockSize' - leftovers in L.append lbs $ L.replicate toFill 0xFF