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