{-# LANGUAGE GeneralizedNewtypeDeriving #-} -- | Interface for cryptographically secure random byte generators. module Raaz.Random ( -- * Cryptographically secure randomness. -- $randomness$ RandM, RT, liftMT , randomByteString -- ** Types that can be generated randomly , Random(..) -- * Low level access to randomness. , fillRandomBytes , unsafeStorableRandom , reseed ) where import Control.Applicative import Control.Monad import Control.Monad.IO.Class import Data.ByteString ( ByteString ) import Data.Int import Data.Vector.Unboxed hiding ( replicateM, create ) import Data.Word import Foreign.Ptr ( Ptr , castPtr) import Foreign.Storable ( Storable, peek ) import Prelude import Raaz.Core import Raaz.Cipher.ChaCha20.Internal(KEY, IV) import Raaz.Random.ChaCha20PRG -- $randomness$ -- -- The raaz library gives a relatively high level interface to -- randomness. The monad `RandM` captures a batch of actions that -- generate/use cryptographically secure random bytes. In particular, -- you can use the functions `random` and `randomByteString` to -- actually generate random elements. -- -- -- = Running a random action -- -- Depending on whether the random bytes generated are sensitive or -- not, you can use either of the combinators `securely` or -- `insecurely`. The combinator `securely` ensures that the seed of -- the PRG is stored in a locked memory and hence will not be swapped -- out to the disk. A use case for this is when you use the random -- bytes to generate say a long term public key. On the other hand -- locked memory is limited on most systems. So for cases where the -- secrecy of the bytes are not important, we would recommend using -- `insecurely`. -- -- > -- Generate a pair of random Word8's -- > import Raaz -- > import Data.Word -- > -- > main :: IO () -- > main = insecurely rPair >>= print -- > where rPair :: RandM (Word8, Word8) -- > rPair = (,) <$> random <$> random -- > -- -- -- > -- A version of hello world that has gone nuts. Printed in base16 -- > -- to save some terminal grief. -- > -- > main = insecurely who >>= \ w -> putStrLn $ "hello " ++ showBase16 w -- > where who :: RandM ByteString -- > who = randomByteString 10 -- > -- -- Some times you need additional memory to keep track of other -- stuff. The monad @`RT` mem@ is meant for such uses. It should be -- seen as the analogue of the monad @`MT` mem@ which in addition -- allows you to pick cryptographically secure random data. In fact, -- the combinator `liftMT` allows you to lift an `MT` action to the -- corresponding `RT` action. -- -- = Internal details -- -- Generating unpredictable stream of bytes is one task that has burnt -- the fingers of a lot of programmers. Unfortunately, getting it -- correct is something of a black art. Raaz uses a stream cipher -- (chacha20), initialised with a starting random key/iv. The starting -- seed is then drawn from the system entropy pool. -- -- TODO: For system entropy we use @\/dev\/urandom@ on a posix systems -- (no windows support yet). Even on posix systems, depending on -- underlying operating system, there are better options. The -- recommended way to generate randomness on an OpenBSD system is -- through the function `arc4random` (note that arc4random does not -- use rc4 cipher anymore). Recent Linux kernels support the -- `getrandom` system call which unfortunately is not yet -- popular. These system specific calls are better because they take -- into consideration many edge cases like for example -- @\/dev\/urandom@ not being accessible or protection from interrupts -- Eventually we will be supporting these calls. -- | A batch of actions on the memory element @mem@ that uses some -- randomness. newtype RT mem a = RT { unMT :: MT (RandomState, mem) a } deriving (Functor, Applicative, Monad, MonadIO) -- | The monad for generating cryptographically secure random data. type RandM = RT VoidMemory -- | Lift a memory action to the corresponding RT action. liftMT :: MT mem a -> RT mem a liftMT = RT . onSubMemory snd -- | Run a randomness thread. In particular, this combinator takes -- care of seeding the internal prg at the start. runRT :: RT m a -> MT (RandomState, m) a runRT action = onSubMemory fst reseedMT >> unMT action instance Memory mem => MonadMemory (RT mem) where insecurely = insecurely . runRT securely = securely . runRT -- | Reseed from the system entropy pool. There is never a need to -- explicitly seed your generator. The insecurely and securely calls -- makes sure that your generator is seed before -- starting. Furthermore, the generator also reseeds after every few -- GB of random bytes generates. Generating random data from the -- system entropy is usually an order of magnitude slower than using a -- fast stream cipher. Reseeding often can slow your program -- considerably without any additional security advantage. -- reseed :: RT mem () reseed = RT $ onSubMemory fst reseedMT -- | Fill the given input pointer with random bytes. fillRandomBytes :: LengthUnit l => l -> Pointer -> RT mem () fillRandomBytes l = RT . onSubMemory fst . fillRandomBytesMT l -- | Types that can be generated at random. It might appear that all -- storables should be an instance of this class, after all we know -- the size of the element why not write that many random bytes. In -- fact, this module provides an `unsafeStorableRandom` which does -- exactly that. However, we do not give a blanket definition for all -- storables because for certain refinements of a given type, like for -- example, Word8's modulo 10, `unsafeStorableRandom` introduces -- unacceptable skews. class Random a where random :: Memory mem => RT mem a -- | Generate a random element. The element picked is -- crypto-graphically pseudo-random. -- -- This is a helper function that has been exported to simplify the -- definition of a `Random` instance for `Storable` types. However, -- there is a reason why we do not give a blanket instance for all -- instances `Storable` and why this function is unsafe? This function -- generates a random element of type @a@ by generating @n@ random -- bytes where @n@ is the size of the elements of @a@. For instances -- that range the entire @n@ byte space this is fine. However, if the -- type is actually a refinement of such a type --- consider for -- example, @`Word8`@ modulo @10@ -- this function generates an -- unacceptable skew in the distribution. Hence this function is -- prefixed unsafe. -- unsafeStorableRandom :: (Memory mem, Storable a) => RT mem a unsafeStorableRandom = RT $ onSubMemory fst retA where retA = liftPointerAction alloc $ getIt . castPtr getIt :: Storable a => Ptr a -> MT RandomState a getIt ptr = unsafePokeManyRandom 1 ptr >> liftIO (peek ptr) getElement :: MT RandomState a -> a getElement _ = undefined algn = alignment $ getElement retA sz = sizeOf $ getElement retA alloc = allocaAligned algn sz -- | Generate a random byteString. randomByteString :: LengthUnit l => l -> RT mem ByteString randomByteString l = RT $ onSubMemory fst $ liftPointerAction (create l) $ fillRandomBytesMT l ------------------------------- Some instances of Random ------------------------ instance Random Word8 where random = unsafeStorableRandom instance Random Word16 where random = unsafeStorableRandom instance Random Word32 where random = unsafeStorableRandom instance Random Word64 where random = unsafeStorableRandom instance Random Word where random = unsafeStorableRandom instance Random Int8 where random = unsafeStorableRandom instance Random Int16 where random = unsafeStorableRandom instance Random Int32 where random = unsafeStorableRandom instance Random Int64 where random = unsafeStorableRandom instance Random Int where random = unsafeStorableRandom instance Random KEY where random = unsafeStorableRandom instance Random IV where random = unsafeStorableRandom instance Random w => Random (LE w) where random = littleEndian <$> random instance Random w => Random (BE w) where random = bigEndian <$> random instance (Dimension d, Unbox w, Random w) => Random (Tuple d w) where random = repeatM random -------------------------- Now comes the boring tuples ----------------- instance (Random a, Random b) => Random (a,b) where random = (,) <$> random <*> random instance (Random a, Random b, Random c) => Random (a,b,c) where random = (,,) <$> random <*> random <*> random instance (Random a, Random b, Random c, Random d) => Random (a,b,c,d) where random = (,,,) <$> random <*> random <*> random <*> random instance (Random a, Random b, Random c, Random d, Random e) => Random (a,b,c,d,e) where random = (,,,,) <$> random <*> random <*> random <*> random <*> random -- | The action @unsafePokeManyRandom n ptr@ pokes @n@ random elements -- at the location starting at ptr. If the underlying type does not -- saturate its entire binary size (think of say Word8 modulo 5), the -- distribution of elements can be rather skewed . Hence the prefix -- unsafe. This function is exported to simplify the definition -- `Random` instance. Do not use it unwisely. unsafePokeManyRandom :: Storable a => Int -> Ptr a -> MT RandomState () unsafePokeManyRandom n ptr = fillRandomBytesMT totalSz $ castPtr ptr where totalSz = fromIntegral n * sizeOf (getElement ptr) getElement :: Ptr a -> a getElement _ = undefined