cryptonite-0.24: Cryptography Primitives sink

Safe Haskell | Safe
Language | Haskell2010

Crypto.Tutorial

Contents

- Symmetric block ciphers

Description

Examples of how to use `cryptonite`.

Synopsis

# 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