-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Securely allocated and deallocated memory. -- -- Securely allocated and deallocated memory. -- -- When handling sensitive data in your program, you want to be extra -- careful and make sure that it is gone as soon as you are done working -- with it. In a garbage-collected language like Haskell this is not so -- easy, since the garbage collector can move your bytes around and -- create copies of it. In addition to that, even if the memory gets -- eventually deallocated, it is not guaranteed that the data will -- actually be zeroed-out or overriden. -- -- To make matters even worse, if the operating system runs out of RAM -- while your sensitive data remains in the memory, the page that -- contains your data can get swapped out and, thus, end up on the disk, -- which you, of course, absolutely want to never happen. -- -- This library provides a (relatively) easy to use interface for working -- with data allocated in a secure memory location that is guaranteed to -- never end up on the disk and that will be zeroed-out as soon as you -- finish using it. @package secure-memory @version 0.0.0.2 -- | Internal utilities for reading passwords. module Data.SensitiveBytes.IO.Internal.Password -- | Flush stdout, disable echo, and read user input from stdin. readPassword :: Handle -> Handle -> Text -> Ptr () -> Int -> IO Int -- | The sensitive data type internals. module Data.SensitiveBytes.Internal -- | This function performs the initialisation steps required for -- allocating data in secure memory regions. -- -- The basic usage is to call this function and provide to it a block of -- code that will be allocating memory for sensitive data. The type of -- withSensitiveBytes is such that it can only be called withing -- such a code block. -- -- Ideally, you should call withSecureMemory only once and deal -- with all your sensitive data within this single code block, however it -- is not a requirement – you can call it as many times as you wish and -- the only downside to doing so is that it will incur a tiny performance -- penalty. -- -- In some rare circumstances this function secure memory initialisation -- may fail, in which case this function will throw -- SecureMemoryInitException. withSecureMemory :: forall m r. MonadIO m => (WithSecureMemory => m r) -> m r -- | A constraint for functions that require access to secure memory. The -- only way to satisfy it is to call withSecureMemory. type WithSecureMemory = Given SodiumInitialised -- | A trivial proof that sodium_init has been called. data SodiumInitialised -- | Exception thrown by withSecureMemory. data SecureMemoryInitException -- | Bytes that will be allocated in a secure memory location such that -- they will never be moved by the garbage collector and, hopefully, -- never swapped out to the disk (if the operating system supports this -- kind of protection). data SensitiveBytes s SensitiveBytes :: Int -> Int -> Ptr () -> SensitiveBytes s -- | Size of the allocated buffer. [allocSize] :: SensitiveBytes s -> Int -- | Size of the actual data stored. [dataSize] :: SensitiveBytes s -> Int -- | Buffer pointer. [bufPtr] :: SensitiveBytes s -> Ptr () -- | Allocate bytes in a protected memory region. -- -- Just as regular malloc, this function can fail, for example, -- if there is not enough memory. In this case, it will throw -- SensitiveBytesAllocException. allocate :: forall s m. (MonadIO m, WithSecureMemory) => Int -> m (SensitiveBytes s) -- | Free bytes previously allocated in a protected memory region. free :: forall s m. (MonadIO m, WithSecureMemory) => SensitiveBytes s -> m () -- | Get the underlying data pointer. -- -- This function is unsafe, because it discards the second-order context -- and thus can allow the pointer to escape its scope and be used after -- free. unsafePtr :: SensitiveBytes s -> Ptr () -- | Rewrite the recorded size of the data. -- -- This is a very dangerous internal-only function. It is essentially a -- hack that allows other functions exported from this library to -- efficiently read data of unknown size by first allocating a large -- buffer and then tweaking the ByteArrayAccess instance to return -- the size that is smaller than what was actually allocated. resized :: forall s. () => Int -> SensitiveBytes s -> SensitiveBytes s -- | Allocate a byte array in a secure memory region. -- -- This function guarantees that: -- --
    --
  1. The garbage collector will not touch the allocated memory and will -- not try to copy the sensitive data.
  2. --
  3. The memory will be zeroed-out and freed as soon as the computation -- finishes.
  4. --
-- -- Additionally, it will try its best (subject to the support from the -- operating system) to do the following: -- --
    --
  1. Allocate the buffer at the end of a page and make sure that the -- following page is not mapped, so trying to access past the end of the -- buffer will crash the program.
  2. --
  3. Place a canary immediately before the buffer, check that it was -- not modified before deallocating the memory, and crash the program -- otherwise.
  4. --
  5. mlock the memory to make sure it will not be paged to the -- disk.
  6. --
  7. Ask the operating system not to include this memory in core -- dumps.
  8. --
-- -- Just as with regular malloc, allocation can fail, for -- example, if there is not enough memory. In this case, the function -- will throw SensitiveBytesAllocException. withSensitiveBytes :: forall s m r. (MonadIO m, MonadMask m, WithSecureMemory) => Int -> (SensitiveBytes s -> m r) -> m r -- | Exception thrown by withSensitiveBytes. data SensitiveBytesAllocException instance GHC.Show.Show Data.SensitiveBytes.Internal.SensitiveBytesAllocException instance GHC.Exception.Type.Exception Data.SensitiveBytes.Internal.SensitiveBytesAllocException instance forall k (s :: k). Data.ByteArray.Types.ByteArrayAccess (Data.SensitiveBytes.Internal.SensitiveBytes s) instance GHC.Show.Show Data.SensitiveBytes.Internal.SecureMemoryInitException instance GHC.Exception.Type.Exception Data.SensitiveBytes.Internal.SecureMemoryInitException -- | The sensitive data type. -- -- A typical usage looks something like this: -- --
--   import Data.SensitiveBytes (SensitiveBytes, withSecureMemory, withSensitiveBytes)
--   
--   your_function = withSecureMemory $ do
--    {- some optional initialisation -}
--    withSensitiveBytes 128 $ sb -> do
--      {- work with sb using its ByteArrayAccess instance -}
--   
-- -- Note that withSensitiveBytes can only be called withing a code -- block passed to withSecureMemory and its type will prevent your -- from doing otherwise. -- -- You will typically read sensitive data into SensitiveBytes -- using functions in Data.SensitiveBytes.IO and then pass to some -- other function that will work with it using the ByteArrayAccess -- instance. Just make sure the function you pass it to does not copy the -- data and does not convert it to some other insecure byte-array-like -- type. module Data.SensitiveBytes -- | This function performs the initialisation steps required for -- allocating data in secure memory regions. -- -- The basic usage is to call this function and provide to it a block of -- code that will be allocating memory for sensitive data. The type of -- withSensitiveBytes is such that it can only be called withing -- such a code block. -- -- Ideally, you should call withSecureMemory only once and deal -- with all your sensitive data within this single code block, however it -- is not a requirement – you can call it as many times as you wish and -- the only downside to doing so is that it will incur a tiny performance -- penalty. -- -- In some rare circumstances this function secure memory initialisation -- may fail, in which case this function will throw -- SecureMemoryInitException. withSecureMemory :: forall m r. MonadIO m => (WithSecureMemory => m r) -> m r -- | A constraint for functions that require access to secure memory. The -- only way to satisfy it is to call withSecureMemory. type WithSecureMemory = Given SodiumInitialised -- | Exception thrown by withSecureMemory. data SecureMemoryInitException -- | Bytes that will be allocated in a secure memory location such that -- they will never be moved by the garbage collector and, hopefully, -- never swapped out to the disk (if the operating system supports this -- kind of protection). data SensitiveBytes s -- | Allocate a byte array in a secure memory region. -- -- This function guarantees that: -- --
    --
  1. The garbage collector will not touch the allocated memory and will -- not try to copy the sensitive data.
  2. --
  3. The memory will be zeroed-out and freed as soon as the computation -- finishes.
  4. --
-- -- Additionally, it will try its best (subject to the support from the -- operating system) to do the following: -- --
    --
  1. Allocate the buffer at the end of a page and make sure that the -- following page is not mapped, so trying to access past the end of the -- buffer will crash the program.
  2. --
  3. Place a canary immediately before the buffer, check that it was -- not modified before deallocating the memory, and crash the program -- otherwise.
  4. --
  5. mlock the memory to make sure it will not be paged to the -- disk.
  6. --
  7. Ask the operating system not to include this memory in core -- dumps.
  8. --
-- -- Just as with regular malloc, allocation can fail, for -- example, if there is not enough memory. In this case, the function -- will throw SensitiveBytesAllocException. withSensitiveBytes :: forall s m r. (MonadIO m, MonadMask m, WithSecureMemory) => Int -> (SensitiveBytes s -> m r) -> m r -- | Exception thrown by withSensitiveBytes. data SensitiveBytesAllocException -- | Reading and writing sensitive data. module Data.SensitiveBytes.IO -- | Ask the user to enter their password and read it securely. -- -- “Securely” means “following all the best pracrices”, such as: -- -- -- -- Since this function reads the data into securely allocated memory, -- which is very expensive to allocate, it needs to know the maximum -- possible length of the password to be read. If the user enters -- something longer, it will be silently discarded (similar to -- readpassphrase on BSD). In the future it is possible that -- this limitation will be removed at the cost of performing multiple -- expensive allocations. -- -- This function always writes prompt to stdout and then reads -- from stdin. -- -- Example: -- --
--   withSecureMemory $
--     withUserPassword 128 (Just "Enter your password: ") $ pw -> do
--       {- hash the pw or do something else with it -}
--   
withUserPassword :: forall m s r. (MonadIO m, MonadMask m, WithSecureMemory) => Int -> Maybe Text -> (SensitiveBytes s -> m r) -> m r