-- |The module mirrors "Crypto.Classes" except that errors are thrown as -- exceptions instead of having returning types of @Either error result@ -- or @Maybe result@. -- -- NB This module is experimental and might go away or be re-arranged. {-# LANGUAGE DeriveDataTypeable #-} module Crypto.Classes.Exceptions ( -- * Classes C.Hash(..), C.AsymCipher, R.CryptoRandomGen, C.BlockCipher -- * Hashing Operations , C.hashFunc', C.hashFunc -- * Symmetric Cryptographic Operations -- ** Helpers , C.blockSize, C.blockSizeBytes , C.keyLength, C.keyLengthBytes , C.incIV -- ** Primitives , C.encryptBlock, C.decryptBlock -- * Key and IV construction , buildKey, C.buildKeyIO, buildKeyGen , getIV ,C.getIVIO, C.zeroIV -- ** Block Cipher Modes of Operation , C.ecb, C.unEcb, C.cbc, C.unCbc, C.ctr, C.unCtr, C.ctrLazy, C.unCtrLazy , C.cfb, C.unCfb, C.ofb, C.unOfb, C.cbcLazy, C.unCbcLazy, C.sivLazy, C.unSivLazy , C.siv, C.unSiv, C.ecbLazy, C.unEcbLazy, C.cfbLazy, C.unCfbLazy, C.ofbLazy , C.unOfbLazy -- * RNG Operations , newGen, genBytes, genBytesWithEntropy, reseed, splitGen , R.genSeedLength, R.reseedInfo, R.reseedPeriod, R.newGenIO -- * Info Types , R.GenError(..), R.ReseedInfo(..), CipherError(..) -- * Asymmetric cryptographic operations , buildKeyPair, encryptAsym, decryptAsym , C.Signing, C.signingKeyLength, C.verifyingKeyLength, C.verify , C.publicKeyLength, C.privateKeyLength, C.buildKeyPairIO ) where import qualified Crypto.Random as R import Crypto.Random (CryptoRandomGen) import Crypto.Types import qualified Crypto.Classes as C import qualified Control.Exception as X import qualified Data.ByteString as B import Data.Data import Data.Typeable data CipherError = GenError R.GenError | KeyGenFailure deriving (Show, Read, Eq, Ord, Data, Typeable) instance X.Exception CipherError mExcept :: (X.Exception e) => e -> Maybe a -> a mExcept e = maybe (X.throw e) id eExcept :: (X.Exception e) => Either e a -> a eExcept = either X.throw id -- |Key construction from raw material (typically including key expansion) -- -- This is a wrapper that can throw a 'CipherError' on exception. buildKey :: C.BlockCipher k => B.ByteString -> k buildKey = mExcept KeyGenFailure . C.buildKey -- |Random 'IV' generation -- -- This is a wrapper that can throw a 'GenError' on exception. getIV :: (C.BlockCipher k, CryptoRandomGen g) => g -> (IV k, g) getIV = eExcept . C.getIV -- |Symmetric key generation -- -- This is a wrapper that can throw a 'GenError' on exception. buildKeyGen :: (CryptoRandomGen g, C.BlockCipher k) => g -> (k, g) buildKeyGen = eExcept . C.buildKeyGen -- |Asymetric key generation -- -- This is a wrapper that can throw a 'GenError' on exception. buildKeyPair :: (CryptoRandomGen g, C.AsymCipher p v) => g -> BitLength -> ((p,v), g) buildKeyPair g = eExcept . C.buildKeyPair g -- |Asymmetric encryption -- -- This is a wrapper that can throw a 'GenError' on exception. encryptAsym :: (CryptoRandomGen g, C.AsymCipher p v) => g -> p -> B.ByteString -> (B.ByteString, g) encryptAsym g p = eExcept . C.encryptAsym g p -- |Asymmetric decryption -- -- This is a wrapper that can throw a GenError on exception. decryptAsym :: (CryptoRandomGen g, C.AsymCipher p v) => g -> v -> B.ByteString -> (B.ByteString, g) decryptAsym g v = eExcept . C.decryptAsym g v -- |Instantiate a new random bit generator. The provided -- bytestring should be of length >= genSeedLength. If the -- bytestring is shorter then the call may fail (suggested -- error: `NotEnoughEntropy`). If the bytestring is of -- sufficent length the call should always succeed. -- -- This is a wrapper that can throw 'GenError' types as exceptions. newGen :: CryptoRandomGen g => B.ByteString -> g newGen = eExcept . R.newGen -- | @genBytes len g@ generates a random ByteString of length -- @len@ and new generator. The 'MonadCryptoRandom' package -- has routines useful for converting the ByteString to -- commonly needed values (but 'cereal' or other -- deserialization libraries would also work). -- -- This is a wrapper that can throw 'GenError' types as exceptions. genBytes :: CryptoRandomGen g => ByteLength -> g -> (B.ByteString, g) genBytes l = eExcept . R.genBytes l -- |@genBytesWithEntropy g i entropy@ generates @i@ random bytes and use -- the additional input @entropy@ in the generation of the requested data -- to increase the confidence our generated data is a secure random stream. -- -- This is a wrapper that can throw 'GenError' types as exceptions. genBytesWithEntropy :: CryptoRandomGen g => ByteLength -> B.ByteString -> g -> (B.ByteString, g) genBytesWithEntropy l b = eExcept . R.genBytesWithEntropy l b -- |If the generator has produced too many random bytes on its existing -- seed it will throw a `NeedReseed` exception. In that case, reseed the -- generator using this function and a new high-entropy seed of length >= -- `genSeedLength`. Using bytestrings that are too short can result in an -- exception (`NotEnoughEntropy`). reseed :: CryptoRandomGen g => B.ByteString -> g -> g reseed l = eExcept . R.reseed l -- | While the safety and wisdom of a splitting function depends on the -- properties of the generator being split, several arguments from -- informed people indicate such a function is safe for NIST SP 800-90 -- generators. (see libraries\@haskell.org discussion around Sept, Oct -- 2010). You can find implementations of such generators in the 'DRBG' -- package. -- -- This is a wrapper for 'Crypto.Random.splitGen' which throws errors as -- exceptions. splitGen :: CryptoRandomGen g => g -> (g,g) splitGen = eExcept . R.splitGen