packages feed

automitive-cse-0.0.1.0: src/Backport/Crypto/ConstructHash/MiyaguchiPreneel.hs

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Backport.Crypto.ConstructHash.MiyaguchiPreneel
       ( mp, mp'
       , MiyaguchiPreneel(..)
       , cipherInit'
       ) where

import           Data.List (foldl')

import           Crypto.Cipher.Types
import           Crypto.Error (eitherCryptoError)
import           Data.ByteArray (ByteArrayAccess, ByteArray, Bytes)
import qualified Data.ByteArray as B


newtype MiyaguchiPreneel a = MP { chashGetBytes :: Bytes }
    deriving ByteArrayAccess

instance Eq (MiyaguchiPreneel a) where
    MP b1 == MP b2  =  B.constEq b1 b2


-- | Compute Miyaguchi-Preneel one way compress using the supplied block cipher.
mp' :: (ByteArrayAccess bin, BlockCipher cipher)
    => (Bytes -> cipher)       -- ^ key build function to compute Miyaguchi-Preneel. care about block-size and key-size
    -> bin                     -- ^ input message
    -> MiyaguchiPreneel cipher -- ^ output tag
mp' g = MP . foldl' (step $ g) (B.replicate bsz 0) . chunks . B.convert
  where
    bsz = blockSize ( g B.empty {- dummy to get block size -} )
    chunks msg
      | B.null tl  =  [hd :: Bytes]
      | otherwise  =   hd : chunks tl
      where
        (hd, tl) = B.splitAt bsz msg

-- | Simple key build function, which may raise size error.
cipherInit' :: (ByteArray ba, Cipher k) => ba -> k
cipherInit' = either (error . show) id . eitherCryptoError . cipherInit

-- | Compute Miyaguchi-Preneel one way compress using the infered block cipher.
--   Only safe when KEY-SIZE equals to BLOCK-SIZE.
--
--   Simple usage /mp' msg :: MiyaguchiPreneel AES128/
mp :: (ByteArrayAccess bin, BlockCipher cipher)
   => bin                     -- ^ input message
   -> MiyaguchiPreneel cipher -- ^ output tag
mp = mp' cipherInit'

-- | computation step of Miyaguchi-Preneel
step :: (ByteArray ba, BlockCipher k)
     => (ba -> k)
     -> ba
     -> ba
     -> ba
step g iv msg =
    ecbEncrypt k pmsg `bxor` iv `bxor` pmsg
  where
    k = g iv
    pmsg = pad0 k msg

pad0 :: (ByteArray ba, BlockCipher k) => k -> ba -> ba
pad0 k s = s `B.append` B.replicate (blockSize k - B.length s) 0

bxor :: ByteArray ba => ba -> ba -> ba
bxor = B.xor