crypto-rng (empty) → 0.1.0.0
raw patch · 7 files changed
+285/−0 lines, 7 filesdep +DRBGdep +basedep +bytestringsetup-changed
Dependencies added: DRBG, base, bytestring, crypto-api, exceptions, monad-control, mtl, transformers-base
Files
- ChangeLog.md +5/−0
- LICENSE +30/−0
- Setup.hs +2/−0
- crypto-rng.cabal +38/−0
- src/Crypto/RNG.hs +167/−0
- src/Crypto/RNG/Class.hs +30/−0
- src/Crypto/RNG/Utils.hs +13/−0
+ ChangeLog.md view
@@ -0,0 +1,5 @@+# Revision history for crypto-rng++## 0.1.0.0 -- 2016-12-06++* First version. Released on an unsuspecting world.
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2016, Scrive AB++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Scrive AB nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ crypto-rng.cabal view
@@ -0,0 +1,38 @@+name: crypto-rng+version: 0.1.0.0+synopsis: Cryptographic random number generator.++description: Convenient wrapper for the cryptographic random generator+ provided by the DRBG package.++homepage: https://github.com/scrive/crypto-rng+license: BSD3+license-file: LICENSE+author: Scrive AB+maintainer: Mikhail Glushenkov <mikhail.glushenkov@scrive.com>,+ Jonathan Jouty <jonathan@scrive.com>+copyright: Scrive AB+category: Crypto+build-type: Simple+tested-with: GHC == 7.8.4, GHC == 7.10.3, GHC == 8.0.1+extra-source-files: ChangeLog.md+cabal-version: >=1.10++source-repository head+ type: git+ location: https://github.com/scrive/crypto-rng.git++library+ exposed-modules: Crypto.RNG+ Crypto.RNG.Class+ Crypto.RNG.Utils+ build-depends: base < 5,+ DRBG,+ bytestring,+ exceptions,+ crypto-api,+ monad-control,+ mtl,+ transformers-base+ hs-source-dirs: src+ default-language: Haskell2010
+ src/Crypto/RNG.hs view
@@ -0,0 +1,167 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE ExplicitForAll #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UndecidableInstances #-}++#if __GLASGOW_HASKELL__ < 710+{-# LANGUAGE OverlappingInstances #-}+#endif++-- | Support for generation of cryptographically secure random+-- numbers, based on the DRBG package.+--+-- This is a convenience layer on top of DRBG, which allows you to+-- pull random values by means of the method 'random', while keeping+-- the state of the random number generator (RNG) inside a monad. The+-- state is protected by an MVar, which means that concurrent+-- generation of random values from several threads works straight out+-- of the box.+--+-- The access to the RNG state is captured by a class. By making+-- instances of this class, client code can enjoy RNG generation from+-- their own monads.+module Crypto.RNG (+ -- * CryproRNG class+ module Crypto.RNG.Class+ -- * Generation of strings and numbers+ , CryptoRNGState+ , newCryptoRNGState+ , unsafeCryptoRNGState+ , randomBytesIO+ , randomR+ -- * Generation of values in other types+ , Random(..)+ , boundedIntegralRandom+ -- * Monad transformer for carrying rng state+ , CryptoRNGT+ , mapCryptoRNGT+ , runCryptoRNGT+ , withCryptoRNGState+ ) where++import Control.Applicative+import Control.Concurrent+import Control.Monad.Base+import Control.Monad.Catch+import Control.Monad.Cont+import Control.Monad.Reader+import Control.Monad.Trans.Control+import Crypto.Random+import Crypto.Random.DRBG+import Data.Bits+import Data.ByteString (ByteString, unpack)+import Data.Int+import Data.List+import Data.Word++import Crypto.RNG.Class++-- | The random number generator state. It sits inside an MVar to+-- support concurrent thread access.+newtype CryptoRNGState = CryptoRNGState (MVar (GenAutoReseed HashDRBG HashDRBG))++-- | Create a new 'CryptoRNGState', based on system entropy.+newCryptoRNGState :: MonadIO m => m CryptoRNGState+newCryptoRNGState = liftIO $ newGenIO >>= fmap CryptoRNGState . newMVar++-- | Create a new 'CryptoRNGState', based on a bytestring seed.+-- Should only be used for testing.+unsafeCryptoRNGState :: MonadIO m => ByteString -> m CryptoRNGState+unsafeCryptoRNGState s = liftIO $+ either (fail . show) (fmap CryptoRNGState . newMVar) (newGen s)++-- | Generate given number of cryptographically secure random bytes.+randomBytesIO :: ByteLength -- ^ number of bytes to generate+ -> CryptoRNGState+ -> IO ByteString+randomBytesIO n (CryptoRNGState gv) = do+ liftIO $ modifyMVar gv $ \g -> do+ (bs, g') <- either (fail "Crypto.GlobalRandom.genBytes") return $+ genBytes n g+ return (g', bs)++-- | Generate a cryptographically secure random number in given,+-- closed range.+randomR :: (CryptoRNG m, Integral a) => (a, a) -> m a+randomR (minb', maxb') = do+ bs <- randomBytes byteLen+ return . fromIntegral $+ minb + foldl1' (\r a -> shiftL r 8 .|. a) (map toInteger (unpack bs))+ `mod` range+ where+ minb, maxb, range :: Integer+ minb = fromIntegral minb'+ maxb = fromIntegral maxb'+ range = maxb - minb + 1+ byteLen = ceiling $ logBase 2 (fromIntegral range) / (8 :: Double)++-- | Helper function for making Random instances.+boundedIntegralRandom :: forall m a. (CryptoRNG m, Integral a, Bounded a) => m a+boundedIntegralRandom = randomR (minBound :: a, maxBound :: a)++-- | Class for generating cryptographically secure random values.+class Random a where+ random :: CryptoRNG m => m a++instance Random Int16 where+ random = boundedIntegralRandom++instance Random Int32 where+ random = boundedIntegralRandom++instance Random Int64 where+ random = boundedIntegralRandom++instance Random Int where+ random = boundedIntegralRandom++instance Random Word8 where+ random = boundedIntegralRandom++instance Random Word16 where+ random = boundedIntegralRandom++instance Random Word32 where+ random = boundedIntegralRandom++instance Random Word64 where+ random = boundedIntegralRandom++instance Random Word where+ random = boundedIntegralRandom++type InnerCryptoRNGT = ReaderT CryptoRNGState++-- | Monad transformer with RNG state.+newtype CryptoRNGT m a = CryptoRNGT { unCryptoRNGT :: InnerCryptoRNGT m a }+ deriving (Alternative, Applicative, Functor, Monad, MonadBase b, MonadCatch, MonadIO, MonadMask, MonadPlus, MonadThrow, MonadTrans)++mapCryptoRNGT :: (m a -> n b) -> CryptoRNGT m a -> CryptoRNGT n b+mapCryptoRNGT f m = withCryptoRNGState $ \s -> f (runCryptoRNGT s m)++runCryptoRNGT :: CryptoRNGState -> CryptoRNGT m a -> m a+runCryptoRNGT gv m = runReaderT (unCryptoRNGT m) gv++withCryptoRNGState :: (CryptoRNGState -> m a) -> CryptoRNGT m a+withCryptoRNGState = CryptoRNGT . ReaderT++instance MonadTransControl CryptoRNGT where+ type StT CryptoRNGT a = StT InnerCryptoRNGT a+ liftWith = defaultLiftWith CryptoRNGT unCryptoRNGT+ restoreT = defaultRestoreT CryptoRNGT+ {-# INLINE liftWith #-}+ {-# INLINE restoreT #-}++instance MonadBaseControl b m => MonadBaseControl b (CryptoRNGT m) where+ type StM (CryptoRNGT m) a = ComposeSt CryptoRNGT m a+ liftBaseWith = defaultLiftBaseWith+ restoreM = defaultRestoreM+ {-# INLINE liftBaseWith #-}+ {-# INLINE restoreM #-}++instance {-# OVERLAPPABLE #-} MonadIO m => CryptoRNG (CryptoRNGT m) where+ randomBytes n = CryptoRNGT ask >>= liftIO . randomBytesIO n
+ src/Crypto/RNG/Class.hs view
@@ -0,0 +1,30 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE ConstrainedClassMethods #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE UndecidableInstances #-}++#if __GLASGOW_HASKELL__ < 710+{-# LANGUAGE OverlappingInstances #-}+#endif++module Crypto.RNG.Class where++import Control.Monad.Trans+import Crypto.Random.DRBG+import Data.ByteString (ByteString)++-- | Monads carrying around the RNG state.+class Monad m => CryptoRNG m where+ -- | Generate given number of cryptographically secure random bytes.+ randomBytes :: CryptoRNG m+ => ByteLength -- ^ number of bytes to generate+ -> m ByteString++-- | Generic, overlapping instance.++instance {-# OVERLAPPABLE #-} (+ Monad (t m)+ , MonadTrans t+ , CryptoRNG m+ ) => CryptoRNG (t m) where+ randomBytes = lift . randomBytes
+ src/Crypto/RNG/Utils.hs view
@@ -0,0 +1,13 @@+module Crypto.RNG.Utils where++import Control.Monad++import Crypto.RNG++-- | Generate random string of specified length that contains allowed+-- chars.+randomString :: CryptoRNG m => Int -> [Char] -> m String+randomString n allowed_chars =+ sequence $ replicate n $ ((!!) allowed_chars `liftM` randomR (0, len))+ where+ len = length allowed_chars - 1