1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
|
{-# LANGUAGE CPP #-}
{-# LANGUAGE PackageImports #-}
-- |
-- Module : Crypto.Hash
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : experimental
-- Portability : unknown
--
-- Generalized cryptographic hash interface, that you can use with cryptographic hash
-- algorithm that belong to the HashAlgorithm type class.
--
-- > import Crypto.Hash
-- >
-- > sha1 :: ByteString -> Digest SHA1
-- > sha1 = hash
-- >
-- > hexSha3_512 :: ByteString -> String
-- > hexSha3_512 bs = show (hash bs :: Digest SHA3_512)
--
module Crypto.Hash
(
-- * Types
HashAlgorithm(..)
, HashFunctionBS
, HashFunctionLBS
, Context
, Digest
-- * Functions
, digestToByteString
, digestToHexByteString
, hash
, hashlazy
, hashUpdate
, hashInitAlg
-- * hash algorithms
, H.MD2(..)
, H.MD4(..)
, H.MD5(..)
, H.SHA1(..)
, H.SHA224(..)
, H.SHA256(..)
, H.SHA384(..)
, H.SHA512(..)
, H.RIPEMD160(..)
, H.Tiger(..)
, H.SHA3_224(..)
, H.SHA3_256(..)
, H.SHA3_384(..)
, H.SHA3_512(..)
, H.Skein256_224(..)
, H.Skein256_256(..)
, H.Skein512_224(..)
, H.Skein512_256(..)
, H.Skein512_384(..)
, H.Skein512_512(..)
, H.Whirlpool(..)
-- * MAC algorithms
, HMAC(..)
, hmac
, hmacAlg
) where
import Crypto.Hash.Types
import Data.ByteString (ByteString)
import Data.Byteable
import Data.Bits (xor)
import qualified Data.ByteString as B
import qualified Data.ByteArray.Encoding as B
import qualified Data.ByteString.Lazy as L
import qualified "cryptonite" Crypto.Hash as H
-- | 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]
-- | Hash a strict bytestring into a digest.
hash :: HashAlgorithm a => ByteString -> Digest a
hash bs = hashFinalize $ hashUpdate hashInit bs
-- | Hash a lazy bytestring into a digest.
hashlazy :: HashAlgorithm a => L.ByteString -> Digest a
hashlazy lbs = hashFinalize $ hashUpdates hashInit (L.toChunks lbs)
-- | Return the hexadecimal (base16) bytestring of the digest
digestToHexByteString :: Digest a -> ByteString
digestToHexByteString = B.convertToBase B.Base16 . toBytes
-- | Class representing hashing algorithms.
--
-- The hash algorithm is built over 3 primitives:
--
-- * init : create a new hashing context
--
-- * updates : update the hashing context with some strict bytestrings
-- and return the new context
--
-- * finalize : finalize the context into a digest
--
class HashAlgorithm a where
-- | Block size in bytes the hash algorithm operates on
hashBlockSize :: Context a -> Int
-- | Initialize a new context for this hash algorithm
hashInit :: Context a
-- | Update the context with a list of strict bytestring,
-- and return a new context with the updates.
hashUpdates :: Context a -> [ByteString] -> Context a
-- | Finalize a context and return a digest.
hashFinalize :: Context a -> Digest a
-- | Try to convert a binary digest bytestring to a digest.
digestFromByteString :: ByteString -> Maybe (Digest a)
#define DEFINE_INSTANCE(NAME, MODULENAME, BLOCKSIZE) \
instance HashAlgorithm H.NAME where \
{ hashInit = Context $ H.hashInit \
; hashBlockSize ~(Context _) = BLOCKSIZE \
; hashUpdates (Context c) bs = Context $ H.hashUpdates c bs \
; hashFinalize (Context c) = Digest $ H.hashFinalize c \
; digestFromByteString bs = Digest `fmap` H.digestFromByteString bs \
};
#define DEFINE_INSTANCE_LEN(NAME, MODULENAME, LEN, BLOCKSIZE) \
instance HashAlgorithm H.NAME where \
{ hashInit = Context $ H.hashInit \
; hashBlockSize ~(Context _) = BLOCKSIZE \
; hashUpdates (Context c) bs = Context $ H.hashUpdates c bs \
; hashFinalize (Context c) = Digest $ H.hashFinalize c \
; digestFromByteString bs = Digest `fmap` H.digestFromByteString bs \
};
-- | MD2 cryptographic hash
DEFINE_INSTANCE(MD2, MD2, 16)
-- | MD4 cryptographic hash
DEFINE_INSTANCE(MD4, MD4, 64)
-- | MD5 cryptographic hash
DEFINE_INSTANCE(MD5, MD5, 64)
-- | SHA1 cryptographic hash
DEFINE_INSTANCE(SHA1, SHA1, 64)
-- | SHA224 cryptographic hash
DEFINE_INSTANCE(SHA224, SHA224, 64)
-- | SHA256 cryptographic hash
DEFINE_INSTANCE(SHA256, SHA256, 64)
-- | SHA384 cryptographic hash
DEFINE_INSTANCE(SHA384, SHA384, 128)
-- | SHA512 cryptographic hash
DEFINE_INSTANCE(SHA512, SHA512, 128)
-- | RIPEMD160 cryptographic hash
DEFINE_INSTANCE(RIPEMD160, RIPEMD160, 64)
-- | Whirlpool cryptographic hash
DEFINE_INSTANCE(Whirlpool, Whirlpool, 64)
-- | Tiger cryptographic hash
DEFINE_INSTANCE(Tiger, Tiger, 64)
-- | SHA3 (224 bits version) cryptographic hash
DEFINE_INSTANCE_LEN(SHA3_224, SHA3, 224, 144)
-- | SHA3 (256 bits version) cryptographic hash
DEFINE_INSTANCE_LEN(SHA3_256, SHA3, 256, 136)
-- | SHA3 (384 bits version) cryptographic hash
DEFINE_INSTANCE_LEN(SHA3_384, SHA3, 384, 104)
-- | SHA3 (512 bits version) cryptographic hash
DEFINE_INSTANCE_LEN(SHA3_512, SHA3, 512, 72)
-- | Skein256 (224 bits version) cryptographic hash
DEFINE_INSTANCE_LEN(Skein256_224, Skein256, 224, 32)
-- | Skein256 (256 bits version) cryptographic hash
DEFINE_INSTANCE_LEN(Skein256_256, Skein256, 256, 32)
-- | Skein512 (224 bits version) cryptographic hash
DEFINE_INSTANCE_LEN(Skein512_224, Skein512, 224, 64)
-- | Skein512 (256 bits version) cryptographic hash
DEFINE_INSTANCE_LEN(Skein512_256, Skein512, 256, 64)
-- | Skein512 (384 bits version) cryptographic hash
DEFINE_INSTANCE_LEN(Skein512_384, Skein512, 384, 64)
-- | Skein512 (512 bits version) cryptographic hash
DEFINE_INSTANCE_LEN(Skein512_512, Skein512, 512, 64)
-- | Initialize a new context for a specified hash algorithm
hashInitAlg :: HashAlgorithm alg => alg -> Context alg
hashInitAlg _ = hashInit
-- | Represent an HMAC that is a phantom type with the hash used to produce the mac.
--
-- The Eq instance is constant time.
newtype HMAC a = HMAC { hmacGetDigest :: Digest a }
instance Byteable (HMAC a) where
toBytes (HMAC b) = toBytes b
instance Eq (HMAC a) where
(HMAC b1) == (HMAC b2) = constEqBytes (toBytes b1) (toBytes b2)
-- | compute a MAC using the supplied hashing function
hmac :: HashAlgorithm a
=> ByteString -- ^ Secret key
-> ByteString -- ^ Message to MAC
-> HMAC a
hmac secret msg = doHMAC hashInit
where doHMAC :: HashAlgorithm a => Context a -> HMAC a
doHMAC ctxInit = HMAC $ hashF $ B.append opad (toBytes $ 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 toBytes (hashF secret) else secret
pad = B.replicate (fromIntegral blockSize - B.length kt) 0
hashF = hashFinalize . hashUpdate ctxInit
blockSize = hashBlockSize ctxInit
-- | compute a HMAC using a specified algorithm
hmacAlg :: HashAlgorithm a
=> a -- ^ the hash algorithm the actual value is unused.
-> ByteString -- ^ Secret key
-> ByteString -- ^ Message to MAC
-> HMAC a
hmacAlg _ secret msg = hmac secret msg
|