-- |
-- Module      : Amazonka.Crypto
-- Copyright   : (c) 2013-2021 Brendan Hay
-- License     : Mozilla Public License, v. 2.0.
-- Maintainer  : Brendan Hay <brendan.g.hay+amazonka@gmail.com>
-- Stability   : provisional
-- Portability : non-portable (GHC extensions)
module Amazonka.Crypto
  ( -- * HMAC
    Key,
    hmacSHA1,
    hmacSHA256,

    -- * Hashing
    hashSHA256,
    hashMD5,
    Hash.hash,
    --- * Incremental Hashing
    sinkSHA256,
    sinkMD5,

    -- * Re-exported
    Hash.HashAlgorithm,
    Hash.Digest,
    Hash.SHA256,
    Hash.MD5,
  )
where

import Amazonka.Prelude
import qualified Crypto.Hash as Hash
import qualified Crypto.MAC.HMAC as HMAC
import Data.ByteArray (ByteArrayAccess)
import Data.Conduit (ConduitM)
import qualified Data.Conduit as Conduit

type Key = ByteString

hmacSHA1 :: ByteArrayAccess a => Key -> a -> HMAC.HMAC Hash.SHA1
hmacSHA1 :: Key -> a -> HMAC SHA1
hmacSHA1 = Key -> a -> HMAC SHA1
forall key message a.
(ByteArrayAccess key, ByteArrayAccess message, HashAlgorithm a) =>
key -> message -> HMAC a
HMAC.hmac

hmacSHA256 :: ByteArrayAccess a => Key -> a -> HMAC.HMAC Hash.SHA256
hmacSHA256 :: Key -> a -> HMAC SHA256
hmacSHA256 = Key -> a -> HMAC SHA256
forall key message a.
(ByteArrayAccess key, ByteArrayAccess message, HashAlgorithm a) =>
key -> message -> HMAC a
HMAC.hmac

hashSHA256 :: ByteArrayAccess a => a -> Hash.Digest Hash.SHA256
hashSHA256 :: a -> Digest SHA256
hashSHA256 = SHA256 -> a -> Digest SHA256
forall ba alg.
(ByteArrayAccess ba, HashAlgorithm alg) =>
alg -> ba -> Digest alg
Hash.hashWith SHA256
Hash.SHA256

hashMD5 :: ByteArrayAccess a => a -> Hash.Digest Hash.MD5
hashMD5 :: a -> Digest MD5
hashMD5 = MD5 -> a -> Digest MD5
forall ba alg.
(ByteArrayAccess ba, HashAlgorithm alg) =>
alg -> ba -> Digest alg
Hash.hashWith MD5
Hash.MD5

-- | Incrementally calculate a 'MD5' 'Digest'.
sinkMD5 :: Monad m => ConduitM ByteString o m (Hash.Digest Hash.MD5)
sinkMD5 :: ConduitM Key o m (Digest MD5)
sinkMD5 = ConduitM Key o m (Digest MD5)
forall (m :: * -> *) a o.
(Monad m, HashAlgorithm a) =>
ConduitM Key o m (Digest a)
sinkHash

-- | Incrementally calculate a 'SHA256' 'Digest'.
sinkSHA256 :: Monad m => ConduitM ByteString o m (Hash.Digest Hash.SHA256)
sinkSHA256 :: ConduitM Key o m (Digest SHA256)
sinkSHA256 = ConduitM Key o m (Digest SHA256)
forall (m :: * -> *) a o.
(Monad m, HashAlgorithm a) =>
ConduitM Key o m (Digest a)
sinkHash

-- | A cryptonite compatible incremental hash sink.
sinkHash ::
  ( Monad m,
    Hash.HashAlgorithm a
  ) =>
  ConduitM ByteString o m (Hash.Digest a)
sinkHash :: ConduitM Key o m (Digest a)
sinkHash = Context a -> ConduitM Key o m (Digest a)
forall (m :: * -> *) a ba o.
(Monad m, HashAlgorithm a, ByteArrayAccess ba) =>
Context a -> ConduitT ba o m (Digest a)
sink Context a
forall a. HashAlgorithm a => Context a
Hash.hashInit
  where
    sink :: Context a -> ConduitT ba o m (Digest a)
sink Context a
ctx = do
      Maybe ba
mbs <- ConduitT ba o m (Maybe ba)
forall (m :: * -> *) i. Monad m => Consumer i m (Maybe i)
Conduit.await

      case Maybe ba
mbs of
        Maybe ba
Nothing -> Digest a -> ConduitT ba o m (Digest a)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Digest a -> ConduitT ba o m (Digest a))
-> Digest a -> ConduitT ba o m (Digest a)
forall a b. (a -> b) -> a -> b
$! Context a -> Digest a
forall a. HashAlgorithm a => Context a -> Digest a
Hash.hashFinalize Context a
ctx
        Just ba
bs -> Context a -> ConduitT ba o m (Digest a)
sink (Context a -> ConduitT ba o m (Digest a))
-> Context a -> ConduitT ba o m (Digest a)
forall a b. (a -> b) -> a -> b
$! Context a -> ba -> Context a
forall ba a.
(ByteArrayAccess ba, HashAlgorithm a) =>
Context a -> ba -> Context a
Hash.hashUpdate Context a
ctx ba
bs