crypto-api 0.2.1 → 0.3
raw patch · 2 files changed
+72/−17 lines, 2 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Crypto.Random: NeedsInfiniteSeed :: GenError
+ Crypto.Random: data SystemRandom
+ Crypto.Random: instance CryptoRandomGen SystemRandom
+ Crypto.Random: splitGen :: CryptoRandomGen g => g -> Either GenError (g, g)
Files
- Crypto/Random.hs +71/−16
- crypto-api.cabal +1/−1
Crypto/Random.hs view
@@ -20,18 +20,24 @@ -} module Crypto.Random- ( CryptoRandomGen(..)+ ( -- * Basic Interface+ CryptoRandomGen(..) , GenError (..)- , newGenIO+ -- * Helper functions and expanded interface+ , splitGen+ -- * Instances+ , SystemRandom ) where -import System.Crypto.Random (getEntropy)+import System.Crypto.Random import Crypto.Types import Control.Monad (liftM) import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as L import Data.Tagged import Data.Bits (xor, setBit, shiftR, shiftL, (.&.)) import Data.List (foldl')+import System.IO.Unsafe(unsafeInterleaveIO) -- |many generators have these error conditions in common data GenError =@@ -40,6 +46,7 @@ | RangeInvalid -- ^ When using @genInteger g (l,h)@ and @logBase 2 (h - l) > (maxBound :: Int)@. | NeedReseed -- ^ Some generators cease operation after too high a count without a reseed (ex: NIST SP 800-90) | NotEnoughEntropy -- ^ For instantiating new generators (or reseeding)+ | NeedsInfiniteSeed -- ^ This generator can not be instantiated or reseeded with a finite seed (ex: 'SystemRandom') deriving (Eq, Ord, Show) -- |A class of random bit generators that allows for the possibility of failure,@@ -98,19 +105,67 @@ -- can result in an error (`NotEnoughEntropy`). reseed :: B.ByteString -> g -> Either GenError g --- |Use "System.Crypto.Random" to obtain entropy for `newGen`.-newGenIO :: CryptoRandomGen g => IO g-newGenIO = go 0- where- go 1000 = error "The generator instance requested by newGenIO never instantiates (1000 tries). It must be broken."- go i = do- let p = Proxy- getTypedGen :: (CryptoRandomGen g) => Proxy g -> IO (Either GenError g)- getTypedGen pr = liftM newGen (getEntropy $ proxy genSeedLength pr)- res <- getTypedGen p- case res of- Left _ -> go (i+1)- Right g -> return (g `asProxyTypeOf` p)+ -- |By default this uses "System.Crypto.Random" to obtain entropy for `newGen`.+ newGenIO :: IO g+ newGenIO = go 0+ where+ go 1000 = error "The generator instance requested by newGenIO never instantiates (1000 tries). It must be broken."+ go i = do+ let p = Proxy+ getTypedGen :: (CryptoRandomGen g) => Proxy g -> IO (Either GenError g)+ getTypedGen pr = liftM newGen (getEntropy $ proxy genSeedLength pr)+ res <- getTypedGen p+ case res of+ Left _ -> go (i+1)+ Right g -> return (g `asProxyTypeOf` p)++-- |get a random number generator based on the standard system entropy source+getSystemGen :: IO SystemRandom+getSystemGen = do+ ch <- openHandle+ let getBS = unsafeInterleaveIO $ do+ bs <- hGetEntropy ch ((2^15) - 16)+ more <- getBS+ return (bs:more)+ liftM (SysRandom . L.fromChunks) getBS++-- |Not that it is technically correct as an instance of 'CryptoRandomGen', but simply because+-- it's a reasonable engineering choice here is a CryptoRandomGen which streams the system randoms. Take note:+-- +-- * It uses the default definition of 'genByteWithEntropy'+--+-- * 'newGen' will always fail!+--+-- * 'reseed' will always fail!+--+-- * the handle to the system random is never closed+data SystemRandom = SysRandom L.ByteString++instance CryptoRandomGen SystemRandom where+ newGen _ = Left NeedsInfiniteSeed+ genSeedLength = Tagged 0+ genBytes req (SysRandom bs) =+ let reqI = fromIntegral req+ rnd = L.take reqI bs+ rest = L.drop reqI bs+ in if L.length rnd == reqI+ then Right (B.concat $ L.toChunks rnd, SysRandom rest)+ else Left $ GenErrorOther "Error obtaining enough bytes from system random for given request"+ reseed _ _ = Left NeedsInfiniteSeed+ newGenIO = getSystemGen++-- | 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 ~ Sept, Oct 2010)+splitGen :: CryptoRandomGen g => g -> Either GenError (g,g)+splitGen g = do+ let e = genBytes (genSeedLength `for` g) g+ case e of+ Left e -> Left e+ Right (ent,g') -> + case newGen ent of+ Right new -> Right (g',new)+ Left e -> Left e -- |Obtain a tagged value for a particular instantiated type. for :: Tagged a b -> a -> b
crypto-api.cabal view
@@ -1,5 +1,5 @@ name: crypto-api-version: 0.2.1+version: 0.3 license: BSD3 license-file: LICENSE copyright: Thomas DuBuisson <thomas.dubuisson@gmail.com>, Dominic Steinitz (see Data.LargeWord module)