{-# LANGUAGE CApiFFI #-} {-# LANGUAGE ScopedTypeVariables #-} -- | -- -- Module: LibSodium.Bindings.SecureMemory -- Description: Direct bindings to the libsodium secure memory functions -- Copyright: (C) Hécate Moonlight 2022 -- License: BSD-3-Clause -- Maintainer: The Haskell Cryptography Group -- Portability: GHC only module LibSodium.Bindings.SecureMemory ( -- ** Introduction -- $introduction -- ** Zeroing memory sodiumMemZero -- ** Locking memory , sodiumMlock , sodiumMunlock -- ** Allocating memory , sodiumMalloc , sodiumAllocArray , sodiumFree , finalizerSodiumFree ) where import Data.Word (Word8) import Foreign (FinalizerPtr, Ptr) import Foreign.C.Types (CInt (CInt), CSize (CSize)) -- $introduction -- This module provides bindings to the secure memory functions provided by Libsodium. -- It is intended to be qualified on import: -- -- > import qualified LibSodium.Bindings.SecureMemory as SecureMemory -- -- It is recommended to disable swap partitions on machines processing sensitive -- data or, as a second choice, use encrypted swap partitions. -- -- For similar reasons, on Unix systems, one should also disable core dumps when -- running crypto code outside a development environment. -- This can be achieved using a shell built-in such as @ulimit@ or programmatically -- using [@setResourceLimit@](https://hackage.haskell.org/package/unix/docs/System-Posix-Resource.html#v:setResourceLimit): -- -- >>> setResourceLimit ResourceCoreFileSize (ResourceLimits 0 0) -- -- On operating systems where this feature is implemented, kernel crash dumps -- should also be disabled. -- -- The 'sodiumMlock' function wraps @mlock(2)@ and -- [@VirtualLock()@](https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtuallock). -- -- Note: Many systems place limits on the amount of memory that may be locked -- by a process. Care should be taken to raise those limits (e.g. Unix ulimits) -- where necessary. -- | Overwrite the memory region starting at the pointer -- address with zeros. -- -- @memset()@ and hand-written code can be silently stripped out by -- an optimizing compiler or the linker. -- -- This function tries to effectively zero the amount of bytes starting -- at the provided pointer, even if optimizations are being applied to the code. -- -- /See:/ [sodium_memzero()](https://doc.libsodium.org/memory_management) -- -- @since 0.0.1.0 foreign import capi "sodium.h sodium_memzero" sodiumMemZero :: Ptr Word8 -- ^ Start pointer -> CSize -- ^ Length in bytes of the area to zero -> IO () -- | Lock a memory region starting at the pointer -- address. This can help avoid swapping sensitive -- data to disk. -- -- /See:/ [sodium_mlock()](https://doc.libsodium.org/memory_management) -- -- @since 0.0.1.0 foreign import capi "sodium.h sodium_mlock" sodiumMlock :: Ptr Word8 -- ^ Start pointer -> CSize -- ^ Size of the memory region to lock -> IO CInt -- ^ Returns 0 on success, -1 if any system limit is reached. -- | Unlock the memory region by overwriting it with zeros and and flagging the -- pages as swappable again. Calling 'sodiumMemZero' prior to 'sodiumMunlock' is thus not required. -- -- On systems where it is supported, 'sodiumMlock' also wraps @madvise(2)@ and advises the kernel not to include the locked memory in core dumps. The 'sodiumMunlock' -- function also undoes this additional protection. -- -- /See:/ [sodium_munlock()](https://doc.libsodium.org/memory_management) -- -- @since 0.0.1.0 foreign import capi "sodium.h sodium_munlock" sodiumMunlock :: Ptr Word8 -- ^ Start pointer -> CSize -- ^ Size of the memory region to unlock -> IO CInt -- | This function takes an amount (called @size@) and returns a pointer from which -- exactly @size@ contiguous bytes of memory can be accessed. The pointer may be -- 'Foreign.Ptr.nullPtr' and there may be an error when allocating memory, -- through @errno@. Upon failure, @errno@ will be set to 'Foreign.C.Error.eNOMEM' -- -- It is recommended that the caller use "Foreign.C.Error" to handle potential failure. -- -- Moreover, 'LibSodium.Bindings.Main.sodiumInit' must be called before using this -- function. -- -- === Explanation -- The allocated region is placed at the end of a page boundary, -- immediately followed by a guard page (or an emulation, -- if unsupported by the platform). As a result, accessing memory past the end of the -- region will immediately terminate the application. -- -- A canary is also placed right before the returned pointer. Modifications of this -- canary are detected when trying to free the allocated region with 'sodiumFree' -- and cause the application to immediately terminate. -- -- If supported by the platform, an additional guard page is placed before this canary -- to make it less likely for sensitive data to be accessible when reading past the end -- of an unrelated region. -- The allocated region is filled with 0xdb bytes to help catch bugs due to -- uninitialized data. -- -- In addition, @mlock(2)@ is called on the region to help avoid it being swapped to disk. -- Note however that @mlock(2)@ may not be supported, may fail or may be a no-op, -- in which case 'sodiumMalloc' will return the memory regardless, but it will not be -- locked. If you specifically need to rely on memory locking, consider calling -- 'sodiumMlock' and checking its return value. -- -- On operating systems supporting @MAP_NOCORE@ or @MADV_DONTDUMP@, memory allocated this -- way will also not be part of core dumps. -- The returned address will not be aligned if the allocation size is not a multiple -- of the required alignment. -- For this reason, 'sodiumMalloc' should not be used with packed or variable-length -- structures unless the size given to 'sodiumMalloc' is rounded up to ensure proper -- alignment. -- -- All the structures used by libsodium can safely be allocated using -- 'sodiumMalloc'. -- -- Allocating 0 bytes is a valid operation. It returns a pointer that can be -- successfully passed to 'sodiumFree'. -- -- ⚠️ This is not a general-purpose allocation function, and requires 3 or 4 extra -- pages of virtual memory. Since it is very expensive, do not use it to allocate -- every-day memory. -- -- /See:/ [sodium_malloc()](https://doc.libsodium.org/memory_management) -- -- @since 0.0.1.0 foreign import capi "sodium.h sodium_malloc" sodiumMalloc :: forall a . CSize -- ^ Amount of memory to allocate -> IO (Ptr a) -- | This function takes an amount of objects and the size of each object, and -- returns a pointer from which this amount of objects that are of the specified -- size each can be accessed. -- -- It provides the same guarantees as 'sodiumMalloc' but also protects against -- arithmetic overflows when @count * size@ exceeds @SIZE_MAX@. -- -- /See:/ [sodium_allocarray()](https://doc.libsodium.org/memory_management) -- -- @since 0.0.1.0 foreign import capi "sodium.h sodium_allocarray" sodiumAllocArray :: forall a . CSize -- ^ Amount of objects -> CSize -- ^ Size of each objects -> IO (Ptr a) -- | Unlock and deallocate memory allocated using 'sodiumMalloc' or 'sodiumAllocArray'. -- -- The memory region is filled with zeros before the deallocation. -- -- /See:/ [sodium_free()](https://doc.libsodium.org/memory_management) -- -- @since 0.0.1.0 foreign import capi "sodium.h sodium_free" sodiumFree :: forall a . Ptr a -> IO () -- | Function pointer to use as 'Foreign.ForeignPtr' finalizer for sodium-allocated memory. -- -- The memory region is filled with zeros before the deallocation. -- -- /See:/ [sodium_free()](https://doc.libsodium.org/memory_management) -- -- @since 0.0.1.0 foreign import capi "sodium.h &sodium_free" finalizerSodiumFree :: forall a . FinalizerPtr a