module Network.Fernet.Crypto ( sign , aesEncrypt , aesDecrypt , genIV , cipherBlockSize ) where import Data.ByteString (ByteString) import Data.ByteArray (ByteArray, ByteArrayAccess, convert) import Crypto.Data.Padding (Format(PKCS7), pad, unpad) import Crypto.Hash.Algorithms (SHA256 (..)) import Crypto.Cipher.AES (AES128) import Crypto.MAC.HMAC (HMAC(..), hmac, hmacGetDigest) import Crypto.Cipher.Types import Crypto.Error import Crypto.Random (getRandomBytes) import Network.Fernet.Token (Signature) sign :: ByteArrayAccess a => a -> ByteString -> Signature sign key t = convert $ hmacGetDigest (hmac key t :: HMAC SHA256) aesEncrypt :: ByteArray a => a -- ^ The encryption key -> ByteString -- ^ Initialization Vector -> ByteString -- ^ Plain text -> Maybe ByteString aesEncrypt key iv text = cbcEncrypt <$> ctx <*> iv' <*> text' where ctx = maybeCryptoError (cipherInit key) :: Maybe AES128 iv' = makeIV iv p = fmap (PKCS7 . blockSize) ctx text' = pad <$> p <*> pure text aesDecrypt :: ByteArray a => a -- ^ The encryption key -> ByteString -- ^ Initialization Vector -> ByteString -- ^ Cipher text -> Maybe ByteString aesDecrypt key iv ct = do (ctx, iv', p) <- aesSetup key iv let text' = cbcDecrypt ctx iv' ct unpad p text' -- | Block size for AES128 cipherBlockSize :: Int cipherBlockSize = 16 genIV :: IO ByteString genIV = getRandomBytes cipherBlockSize aesSetup :: ByteArray a => a -> ByteString -> Maybe (AES128, IV AES128, Format) aesSetup key iv = (,,) <$> ctx <*> iv' <*> p where ctx = maybeCryptoError (cipherInit key) iv' = makeIV iv p = PKCS7 . blockSize <$> ctx