-- | Simple abstraction for message digests {-# LANGUAGE TypeSynonymInstances #-} module Digest ( Digest , digest , digestBS ) where import Control.Applicative import Control.DeepSeq import Control.Monad.State import Data.Word import Foreign.Ptr import qualified Data.ByteString as B import Data.ByteString.Unsafe import qualified Data.ByteString.Lazy as L import qualified OpenSSL.Digest as SSL -- Consider newtyping this type Digest = B.ByteString instance NFData Digest digest :: L.ByteString -> IO B.ByteString digest bs = {-# SCC "sha1_digest" #-} B.pack <$> digestLBS SSL.SHA1 bs digestBS :: B.ByteString -> IO B.ByteString digestBS bs = digest . L.fromChunks $ [bs] digestLBS :: SSL.MessageDigest -> L.ByteString -> IO [Word8] digestLBS mdType xs = SSL.mkDigest mdType $ evalStateT (updateLBS xs >> SSL.final) updateBS :: B.ByteString -> SSL.Digest () updateBS bs = do SSL.DST ctx <- get _ <- liftIO $ unsafeUseAsCStringLen bs $ \(ptr, len) -> SSL.digestUpdate ctx (castPtr ptr) (fromIntegral len) return () updateLBS :: L.ByteString -> SSL.Digest () updateLBS lbs = mapM_ updateBS chunked where chunked = {-# SCC "sha1_updateLBS_chunked" #-} L.toChunks lbs