Blame Crypto/Hash.hs

Packit 141393
-- |
Packit 141393
-- Module      : Crypto.Hash
Packit 141393
-- License     : BSD-style
Packit 141393
-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
Packit 141393
-- Stability   : experimental
Packit 141393
-- Portability : unknown
Packit 141393
--
Packit 141393
-- Generalized cryptographic hash interface, that you can use with cryptographic hash
Packit 141393
-- algorithm that belong to the HashAlgorithm type class.
Packit 141393
--
Packit 141393
-- > import Crypto.Hash
Packit 141393
-- >
Packit 141393
-- > sha1 :: ByteString -> Digest SHA1
Packit 141393
-- > sha1 = hash
Packit 141393
-- >
Packit 141393
-- > hexSha3_512 :: ByteString -> String
Packit 141393
-- > hexSha3_512 bs = show (hash bs :: Digest SHA3_512)
Packit 141393
--
Packit 141393
{-# LANGUAGE ScopedTypeVariables #-}
Packit 141393
{-# LANGUAGE BangPatterns        #-}
Packit 141393
module Crypto.Hash
Packit 141393
    (
Packit 141393
    -- * Types
Packit 141393
      Context
Packit 141393
    , Digest
Packit 141393
    -- * Functions
Packit 141393
    , digestFromByteString
Packit 141393
    -- * hash methods parametrized by algorithm
Packit 141393
    , hashInitWith
Packit 141393
    , hashWith
Packit 141393
    -- * hash methods
Packit 141393
    , hashInit
Packit 141393
    , hashUpdates
Packit 141393
    , hashUpdate
Packit 141393
    , hashFinalize
Packit 141393
    , hashBlockSize
Packit 141393
    , hashDigestSize
Packit 141393
    , hash
Packit 141393
    , hashlazy
Packit 141393
    -- * Hash algorithms
Packit 141393
    , module Crypto.Hash.Algorithms
Packit 141393
    ) where
Packit 141393
Packit 141393
import           Control.Monad
Packit 141393
import           Crypto.Hash.Types
Packit 141393
import           Crypto.Hash.Algorithms
Packit 141393
import           Foreign.Ptr (Ptr)
Packit 141393
import           Crypto.Internal.ByteArray (ByteArrayAccess)
Packit 141393
import qualified Crypto.Internal.ByteArray as B
Packit 141393
import qualified Data.ByteString.Lazy as L
Packit 141393
Packit 141393
-- | Hash a strict bytestring into a digest.
Packit 141393
hash :: (ByteArrayAccess ba, HashAlgorithm a) => ba -> Digest a
Packit 141393
hash bs = hashFinalize $ hashUpdate hashInit bs
Packit 141393
Packit 141393
-- | Hash a lazy bytestring into a digest.
Packit 141393
hashlazy :: HashAlgorithm a => L.ByteString -> Digest a
Packit 141393
hashlazy lbs = hashFinalize $ hashUpdates hashInit (L.toChunks lbs)
Packit 141393
Packit 141393
-- | Initialize a new context for this hash algorithm
Packit 141393
hashInit :: forall a . HashAlgorithm a => Context a
Packit 141393
hashInit = Context $ B.allocAndFreeze (hashInternalContextSize (undefined :: a)) $ \(ptr :: Ptr (Context a)) ->
Packit 141393
    hashInternalInit ptr
Packit 141393
Packit 141393
-- | run hashUpdates on one single bytestring and return the updated context.
Packit 141393
hashUpdate :: (ByteArrayAccess ba, HashAlgorithm a) => Context a -> ba -> Context a
Packit 141393
hashUpdate ctx b
Packit 141393
    | B.null b  = ctx
Packit 141393
    | otherwise = hashUpdates ctx [b]
Packit 141393
Packit 141393
-- | Update the context with a list of strict bytestring,
Packit 141393
-- and return a new context with the updates.
Packit 141393
hashUpdates :: forall a ba . (HashAlgorithm a, ByteArrayAccess ba)
Packit 141393
            => Context a
Packit 141393
            -> [ba]
Packit 141393
            -> Context a
Packit 141393
hashUpdates c l
Packit 141393
    | null ls   = c
Packit 141393
    | otherwise = Context $ B.copyAndFreeze c $ \(ctx :: Ptr (Context a)) ->
Packit 141393
        mapM_ (\b -> B.withByteArray b $ \d -> hashInternalUpdate ctx d (fromIntegral $ B.length b)) ls
Packit 141393
  where
Packit 141393
    ls = filter (not . B.null) l
Packit 141393
Packit 141393
-- | Finalize a context and return a digest.
Packit 141393
hashFinalize :: forall a . HashAlgorithm a
Packit 141393
             => Context a
Packit 141393
             -> Digest a
Packit 141393
hashFinalize !c =
Packit 141393
    Digest $ B.allocAndFreeze (hashDigestSize (undefined :: a)) $ \(dig :: Ptr (Digest a)) -> do
Packit 141393
        ((!_) :: B.Bytes) <- B.copy c $ \(ctx :: Ptr (Context a)) -> hashInternalFinalize ctx dig
Packit 141393
        return ()
Packit 141393
Packit 141393
-- | Initialize a new context for a specified hash algorithm
Packit 141393
hashInitWith :: HashAlgorithm alg => alg -> Context alg
Packit 141393
hashInitWith _ = hashInit
Packit 141393
Packit 141393
-- | Run the 'hash' function but takes an explicit hash algorithm parameter
Packit 141393
hashWith :: (ByteArrayAccess ba, HashAlgorithm alg) => alg -> ba -> Digest alg
Packit 141393
hashWith _ = hash
Packit 141393
Packit 141393
-- | Try to transform a bytearray into a Digest of specific algorithm.
Packit 141393
--
Packit 141393
-- If the digest is not the right size for the algorithm specified, then
Packit 141393
-- Nothing is returned.
Packit 141393
digestFromByteString :: (HashAlgorithm a, ByteArrayAccess ba) => ba -> Maybe (Digest a)
Packit 141393
digestFromByteString = from undefined
Packit 141393
  where
Packit 141393
        from :: (HashAlgorithm a, ByteArrayAccess ba) => a -> ba -> Maybe (Digest a)
Packit 141393
        from alg bs
Packit 141393
            | B.length bs == (hashDigestSize alg) = (Just $ Digest $ B.convert bs)
Packit 141393
            | otherwise                           = Nothing