{-# LANGUAGE OverloadedStrings #-}
-- |
-- Module      : Crypto.PubKey.HashDescr
-- License     : BSD-style
-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
-- Stability   : experimental
-- Portability : Good
--
-- Standard digests wrapped in ASN1 structure
--
module Crypto.PubKey.HashDescr
    (
    -- * Types
      HashFunction
    , HashDescr(..)
    -- * List of known hash description
    , hashDescrMD2
    , hashDescrMD5
    , hashDescrSHA1
    , hashDescrSHA224
    , hashDescrSHA256
    , hashDescrSHA384
    , hashDescrSHA512
    , hashDescrRIPEMD160
    ) where

import Data.ByteString (ByteString)
import Data.Byteable (toBytes)
import qualified Data.ByteString as B
import Crypto.Hash

-- | A standard hash function returning a digest object
type HashFunction = ByteString -> ByteString

-- | Describe a hash function and a way to wrap the digest into
-- an DER encoded ASN1 marshalled structure.
data HashDescr = HashDescr { HashDescr -> HashFunction
hashFunction :: HashFunction             -- ^ hash function
                           , HashDescr -> HashFunction
digestToASN1 :: ByteString -> ByteString -- ^ convertion to an ASN1 wrapped digest bytestring
                           }

-- | Describe the MD2 hashing algorithm
hashDescrMD2 :: HashDescr
hashDescrMD2 :: HashDescr
hashDescrMD2 =
    HashDescr :: HashFunction -> HashFunction -> HashDescr
HashDescr { hashFunction :: HashFunction
hashFunction = Digest MD2 -> ByteString
forall a. Byteable a => a -> ByteString
toBytes (Digest MD2 -> ByteString)
-> (ByteString -> Digest MD2) -> HashFunction
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ByteString -> Digest MD2
forall a. HashAlgorithm a => ByteString -> Digest a
hash :: ByteString -> Digest MD2)
              , digestToASN1 :: HashFunction
digestToASN1 = ByteString -> HashFunction
toHashWithInfo "\x30\x20\x30\x0c\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x02\x05\x00\x04\x10"
              }
-- | Describe the MD5 hashing algorithm
hashDescrMD5 :: HashDescr
hashDescrMD5 :: HashDescr
hashDescrMD5 =
    HashDescr :: HashFunction -> HashFunction -> HashDescr
HashDescr { hashFunction :: HashFunction
hashFunction = Digest MD5 -> ByteString
forall a. Byteable a => a -> ByteString
toBytes (Digest MD5 -> ByteString)
-> (ByteString -> Digest MD5) -> HashFunction
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ByteString -> Digest MD5
forall a. HashAlgorithm a => ByteString -> Digest a
hash :: ByteString -> Digest MD5)
              , digestToASN1 :: HashFunction
digestToASN1 = ByteString -> HashFunction
toHashWithInfo "\x30\x20\x30\x0c\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x05\x05\x00\x04\x10"
              }
-- | Describe the SHA1 hashing algorithm
hashDescrSHA1 :: HashDescr
hashDescrSHA1 :: HashDescr
hashDescrSHA1 =
    HashDescr :: HashFunction -> HashFunction -> HashDescr
HashDescr { hashFunction :: HashFunction
hashFunction = Digest SHA1 -> ByteString
forall a. Byteable a => a -> ByteString
toBytes (Digest SHA1 -> ByteString)
-> (ByteString -> Digest SHA1) -> HashFunction
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ByteString -> Digest SHA1
forall a. HashAlgorithm a => ByteString -> Digest a
hash :: ByteString -> Digest SHA1)
              , digestToASN1 :: HashFunction
digestToASN1 = ByteString -> HashFunction
toHashWithInfo "\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14"
              }
-- | Describe the SHA224 hashing algorithm
hashDescrSHA224 :: HashDescr
hashDescrSHA224 :: HashDescr
hashDescrSHA224 =
    HashDescr :: HashFunction -> HashFunction -> HashDescr
HashDescr { hashFunction :: HashFunction
hashFunction = Digest SHA224 -> ByteString
forall a. Byteable a => a -> ByteString
toBytes (Digest SHA224 -> ByteString)
-> (ByteString -> Digest SHA224) -> HashFunction
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ByteString -> Digest SHA224
forall a. HashAlgorithm a => ByteString -> Digest a
hash :: ByteString -> Digest SHA224)
              , digestToASN1 :: HashFunction
digestToASN1 = ByteString -> HashFunction
toHashWithInfo "\x30\x2d\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x04\x05\x00\x04\x1c"
              }
-- | Describe the SHA256 hashing algorithm
hashDescrSHA256 :: HashDescr
hashDescrSHA256 :: HashDescr
hashDescrSHA256 =
    HashDescr :: HashFunction -> HashFunction -> HashDescr
HashDescr { hashFunction :: HashFunction
hashFunction = Digest SHA256 -> ByteString
forall a. Byteable a => a -> ByteString
toBytes (Digest SHA256 -> ByteString)
-> (ByteString -> Digest SHA256) -> HashFunction
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ByteString -> Digest SHA256
forall a. HashAlgorithm a => ByteString -> Digest a
hash :: ByteString -> Digest SHA256)
              , digestToASN1 :: HashFunction
digestToASN1 = ByteString -> HashFunction
toHashWithInfo "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20"
              }
-- | Describe the SHA384 hashing algorithm
hashDescrSHA384 :: HashDescr
hashDescrSHA384 :: HashDescr
hashDescrSHA384 =
    HashDescr :: HashFunction -> HashFunction -> HashDescr
HashDescr { hashFunction :: HashFunction
hashFunction = Digest SHA384 -> ByteString
forall a. Byteable a => a -> ByteString
toBytes (Digest SHA384 -> ByteString)
-> (ByteString -> Digest SHA384) -> HashFunction
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ByteString -> Digest SHA384
forall a. HashAlgorithm a => ByteString -> Digest a
hash :: ByteString -> Digest SHA384)
              , digestToASN1 :: HashFunction
digestToASN1 = ByteString -> HashFunction
toHashWithInfo "\x30\x41\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02\x05\x00\x04\x30"
              }
-- | Describe the SHA512 hashing algorithm
hashDescrSHA512 :: HashDescr
hashDescrSHA512 :: HashDescr
hashDescrSHA512 =
    HashDescr :: HashFunction -> HashFunction -> HashDescr
HashDescr { hashFunction :: HashFunction
hashFunction = Digest SHA512 -> ByteString
forall a. Byteable a => a -> ByteString
toBytes (Digest SHA512 -> ByteString)
-> (ByteString -> Digest SHA512) -> HashFunction
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ByteString -> Digest SHA512
forall a. HashAlgorithm a => ByteString -> Digest a
hash :: ByteString -> Digest SHA512)
              , digestToASN1 :: HashFunction
digestToASN1 = ByteString -> HashFunction
toHashWithInfo "\x30\x51\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03\x05\x00\x04\x40"
              }

-- | Describe the RIPEMD160 hashing algorithm
hashDescrRIPEMD160 :: HashDescr
hashDescrRIPEMD160 :: HashDescr
hashDescrRIPEMD160 =
    HashDescr :: HashFunction -> HashFunction -> HashDescr
HashDescr { hashFunction :: HashFunction
hashFunction = Digest RIPEMD160 -> ByteString
forall a. Byteable a => a -> ByteString
toBytes (Digest RIPEMD160 -> ByteString)
-> (ByteString -> Digest RIPEMD160) -> HashFunction
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ByteString -> Digest RIPEMD160
forall a. HashAlgorithm a => ByteString -> Digest a
hash :: ByteString -> Digest RIPEMD160)
              , digestToASN1 :: HashFunction
digestToASN1 = ByteString -> HashFunction
toHashWithInfo "\x30\x21\x30\x09\x06\x05\x2b\x24\x03\x02\x01\x05\x00\x04\x14"
              }

-- | Generate the marshalled structure with the following ASN1 structure:
--
--   Start Sequence
--     ,Start Sequence
--       ,OID oid
--       ,Null
--     ,End Sequence
--     ,OctetString digest
--   ,End Sequence
--
toHashWithInfo :: ByteString -> ByteString -> ByteString
toHashWithInfo :: ByteString -> HashFunction
toHashWithInfo pre :: ByteString
pre digest :: ByteString
digest = ByteString
pre ByteString -> HashFunction
`B.append` ByteString
digest