packages feed

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 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