
{- How to use @cryptonite@ with symmetric block ciphers 

> {-# LANGUAGE OverloadedStrings #-}
> {-# LANGUAGE ScopedTypeVariables #-}
> {-# LANGUAGE GADTs #-}
> 
> import           Crypto.Cipher.AES (AES256)
> import           Crypto.Cipher.Types (BlockCipher(..), Cipher(..), nullIV, KeySizeSpecifier(..), IV, makeIV)
> import           Crypto.Error (CryptoFailable(..), CryptoError(..))
> 
> import qualified Crypto.Random.Types as CRT
> 
> import           Data.ByteArray (ByteArray)
> import           Data.ByteString (ByteString)
> 
> -- | Not required, but most general implementation
> data Key c a where
>   Key :: (BlockCipher c, ByteArray a) => a -> Key c a 
> 
> -- | Generates a string of bytes (key) of a specific length for a given block cipher 
> genSecretKey :: forall m c a. (CRT.MonadRandom m, BlockCipher c, ByteArray a) => c -> Int -> m (Key c a) 
> genSecretKey _ = fmap Key . CRT.getRandomBytes 
>   
> -- | Generate a random initialization vector for a given block cipher
> genRandomIV :: forall m c. (CRT.MonadRandom m, BlockCipher c) => c -> m (Maybe (IV c)) 
> genRandomIV _ = do
>   bytes :: ByteString <- CRT.getRandomBytes $ blockSize (undefined :: c) 
>   return $ makeIV bytes 
> 
> -- | Initialize a block cipher
> initCipher :: (BlockCipher c, ByteArray a) => Key c a -> Either CryptoError c
> initCipher (Key k) = case cipherInit k of
>   CryptoFailed e -> Left e
>   CryptoPassed a -> Right a
> 
> encrypt :: (BlockCipher c, ByteArray a) => Key c a -> IV c -> a -> Either CryptoError a
> encrypt secretKey initIV msg = 
>   case initCipher secretKey of
>     Left e -> Left e
>     Right c -> Right $ ctrCombine c initIV msg
>     
> decrypt :: (BlockCipher c, ByteArray a) => Key c a -> IV c -> a -> Either CryptoError a 
> decrypt = encrypt
> 
> exampleAES256 :: ByteString -> IO ()
> exampleAES256 msg = do
>   -- secret key needs 256 bits (32 * 8) 
>   secretKey <- genSecretKey (undefined :: AES256) 32
>   mInitIV <- genRandomIV (undefined :: AES256) 
>   case mInitIV of
>     Nothing -> error "Failed to generate and initialization vector."
>     Just initIV -> do
>       let encryptedMsg = encrypt secretKey initIV msg
>           decryptedMsg = decrypt secretKey initIV =<< encryptedMsg
>       case (,) <$> encryptedMsg <*> decryptedMsg of
>         Left err -> error $ show err
>         Right (eMsg, dMsg) -> do
>           putStrLn $ "Original Message: " ++ show msg
>           putStrLn $ "Message after encryption: " ++ show eMsg 
>           putStrLn $ "Message after decryption: " ++ show dMsg

|-}

module Crypto.Tutorial where
