securemem-0.1.3/0000755000000000000000000000000012204500362011660 5ustar0000000000000000securemem-0.1.3/securemem.cabal0000644000000000000000000000204112204500362014626 0ustar0000000000000000Name: securemem Version: 0.1.3 Synopsis: abstraction to an auto scrubbing and const time eq, memory chunk. Description: SecureMem is similar to ByteString, except that it provides a memory chunk that will be auto-scrubbed after it run out of scope. License: BSD3 License-file: LICENSE Copyright: Vincent Hanquez Author: Vincent Hanquez Maintainer: vincent@snarc.org Category: Data Stability: experimental Build-Type: Simple Homepage: http://github.com/vincenthz/hs-securemem Cabal-Version: >=1.8 data-files: README.md Library Exposed-modules: Data.SecureMem Build-depends: base >= 4 && < 5 , bytestring , byteable >= 0.1.1 , ghc-prim C-sources: cbits/utils.c ghc-options: -Wall -fwarn-tabs source-repository head type: git location: git://github.com/vincenthz/hs-securemem securemem-0.1.3/LICENSE0000644000000000000000000000272212204500362012670 0ustar0000000000000000Copyright (c) 2013 Vincent Hanquez All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. 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. 3. Neither the name of the author nor the names of his contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 AUTHORS 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. securemem-0.1.3/README.md0000644000000000000000000000031512204500362013136 0ustar0000000000000000securemem ======= Documentation: [securemem on hackage](http://hackage.haskell.org/package/securemem) older base ---------- An older base, the memory is not scrubed: upgrade your GHC to 7.6.0 or above. securemem-0.1.3/Setup.hs0000644000000000000000000000005612204500362013315 0ustar0000000000000000import Distribution.Simple main = defaultMain securemem-0.1.3/cbits/0000755000000000000000000000000012204500362012764 5ustar0000000000000000securemem-0.1.3/cbits/utils.c0000644000000000000000000000440312204500362014271 0ustar0000000000000000#include #include #include #define SCRUBVAR 0xa5a5a5a5a5a5a5a5ULL void finalizer_scrub8(void *ptr) { uint64_t *sz_ptr = (uint64_t *) ptr; sz_ptr[0] = SCRUBVAR; } void finalizer_scrub16(void *ptr) { uint64_t *sz_ptr = (uint64_t *) ptr; sz_ptr[0] = SCRUBVAR; sz_ptr[1] = SCRUBVAR; } void finalizer_scrub24(void *ptr) { uint64_t *sz_ptr = (uint64_t *) ptr; sz_ptr[0] = SCRUBVAR; sz_ptr[1] = SCRUBVAR; sz_ptr[2] = SCRUBVAR; } void finalizer_scrub32(void *ptr) { uint64_t *sz_ptr = (uint64_t *) ptr; sz_ptr[0] = SCRUBVAR; sz_ptr[1] = SCRUBVAR; sz_ptr[2] = SCRUBVAR; sz_ptr[3] = SCRUBVAR; } void finalizer_scrub64(void *ptr) { uint64_t *sz_ptr = (uint64_t *) ptr; sz_ptr[0] = SCRUBVAR; sz_ptr[1] = SCRUBVAR; sz_ptr[2] = SCRUBVAR; sz_ptr[3] = SCRUBVAR; sz_ptr[4] = SCRUBVAR; sz_ptr[5] = SCRUBVAR; sz_ptr[6] = SCRUBVAR; sz_ptr[7] = SCRUBVAR; } void finalizer_scrub128(void *ptr) { uint64_t *sz_ptr = (uint64_t *) ptr; int i; for (i = 0; i < 16; i++) sz_ptr[i] = SCRUBVAR; } void finalizer_scrub256(void *ptr) { uint64_t *sz_ptr = (uint64_t *) ptr; int i; for (i = 0; i < 32; i++) sz_ptr[i] = SCRUBVAR; } void finalizer_scrubvar(uint32_t sz, void *ptr) { memset(ptr, 0xa5, sz); } int constant_memeq16(uint8_t *p1, uint8_t *p2) { } int compare_eq(uint32_t size, uint8_t *p1, uint8_t *p2) { uint32_t i; int acc = 1; for (i = 0; i < size / 8; i++) acc &= (p1[i] == p2[i]); return acc; } #define COMPARE_LOOP(n) \ uint64_t *sp1, *sp2; \ int i, acc; \ sp1 = (uint64_t *) p1; sp2 = (uint64_t *) p2; \ acc = 1; \ for (i = 0; i < n; i++) \ acc &= (sp1[i] == sp2[i]); \ return acc; \ int compare_eq8(uint8_t *p1, uint8_t *p2) { uint64_t *sp1, *sp2; sp1 = (uint64_t *) p1; sp2 = (uint64_t *) p2; return (p1[0] == p2[0]); } int compare_eq16(uint8_t *p1, uint8_t *p2) { uint64_t *sp1, *sp2; sp1 = (uint64_t *) p1; sp2 = (uint64_t *) p2; return ((p1[0] == p2[0]) & (p1[1] == p2[1])) == 1; } int compare_eq24(uint8_t *p1, uint8_t *p2) { COMPARE_LOOP(3); } int compare_eq32(uint8_t *p1, uint8_t *p2) { COMPARE_LOOP(4); } int compare_eq64(uint8_t *p1, uint8_t *p2) { COMPARE_LOOP(8); } int compare_eq128(uint8_t *p1, uint8_t *p2) { COMPARE_LOOP(16); } int compare_eq256(uint8_t *p1, uint8_t *p2) { COMPARE_LOOP(32); } securemem-0.1.3/Data/0000755000000000000000000000000012204500362012531 5ustar0000000000000000securemem-0.1.3/Data/SecureMem.hs0000644000000000000000000002143512204500362014757 0ustar0000000000000000-- | -- Module : Data.SecureMem -- License : BSD-style -- Maintainer : Vincent Hanquez -- Stability : Stable -- Portability : GHC -- {-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE BangPatterns #-} {-# LANGUAGE MagicHash #-} {-# LANGUAGE CPP #-} module Data.SecureMem ( SecureMem , secureMemGetSize , secureMemCopy , ToSecureMem(..) -- * Allocation and early termination , allocateSecureMem , createSecureMem , unsafeCreateSecureMem , finalizeSecureMem -- * Pointers manipulation , withSecureMemPtr , withSecureMemPtrSz , withSecureMemCopy -- * convertion , secureMemFromByteString ) where import Foreign.C.Types import Foreign.ForeignPtr (withForeignPtr, finalizeForeignPtr) import Foreign.Ptr #if MIN_VERSION_base(4,6,0) import GHC.Types (Int(..)) import GHC.ForeignPtr (ForeignPtr(..), ForeignPtrContents(..), mallocForeignPtrBytes, addForeignPtrConcFinalizer) import GHC.Prim (sizeofMutableByteArray#) import GHC.Ptr (Ptr(..)) #else import Foreign.ForeignPtr (ForeignPtr, mallocForeignPtrBytes) #endif import Data.Word (Word8) import Data.Monoid import Control.Applicative import Control.Monad (foldM, void) import Data.ByteString (ByteString) import Data.Byteable import qualified Data.ByteString.Internal as B -- | SecureMem is a memory chunk which have the properties of: -- -- * Being scrubbed after its goes out of scope. -- * A Show instance that doesn't actually show any content -- * A Eq instance that is constant time #if MIN_VERSION_base(4,6,0) newtype SecureMem = SecureMem { getForeignPtr :: ForeignPtr Word8 } #else data SecureMem = SecureMem { getForeignPtr :: ForeignPtr Word8, secureMemGetSize :: Int } #endif #if MIN_VERSION_base(4,6,0) -- | Return the size of the memory allocated by this secure mem. secureMemGetSize :: SecureMem -> Int secureMemGetSize (SecureMem (ForeignPtr _ fpc)) = case fpc of MallocPtr mba _ -> I# (sizeofMutableByteArray# mba) _ -> error "cannot happen" #endif secureMemEq :: SecureMem -> SecureMem -> Bool secureMemEq sm1 sm2 = sz1 == sz2 && B.inlinePerformIO meq where meq = withSecureMemPtr sm1 $ \ptr1 -> withSecureMemPtr sm2 $ \ptr2 -> feq ptr1 ptr2 !sz1 = secureMemGetSize sm1 !sz2 = secureMemGetSize sm2 feq | sz1 == 8 = compareEq8 | sz1 == 16 = compareEq16 | sz1 == 24 = compareEq24 | sz1 == 32 = compareEq32 | sz1 == 64 = compareEq64 | sz1 == 128 = compareEq128 | sz1 == 256 = compareEq256 | otherwise = compareEq (fromIntegral sz1) secureMemAppend :: SecureMem -> SecureMem -> SecureMem secureMemAppend s1 s2 = unsafeCreateSecureMem (sz1+sz2) $ \dst -> do withSecureMemPtr s1 $ \sp1 -> B.memcpy dst sp1 (fromIntegral sz1) withSecureMemPtr s2 $ \sp2 -> B.memcpy (dst `plusPtr` sz1) sp2 (fromIntegral sz2) where !sz1 = secureMemGetSize s1 !sz2 = secureMemGetSize s2 secureMemConcat :: [SecureMem] -> SecureMem secureMemConcat l = unsafeCreateSecureMem total $ \dst -> void $ foldM copy dst l where total = sum $ map secureMemGetSize l copy dst s = withSecureMemPtr s $ \sp -> do B.memcpy dst sp (fromIntegral sz) return (dst `plusPtr` sz) where sz = secureMemGetSize s secureMemCopy :: SecureMem -> IO SecureMem secureMemCopy src = createSecureMem sz $ \dst -> withSecureMemPtr src $ \s -> B.memcpy dst s (fromIntegral sz) where sz = secureMemGetSize src withSecureMemCopy :: SecureMem -> (Ptr Word8 -> IO ()) -> IO SecureMem withSecureMemCopy sm f = do sm2 <- secureMemCopy sm withSecureMemPtr sm2 f return sm2 instance Show SecureMem where show _ = "" instance Byteable SecureMem where toBytes = secureMemToByteString byteableLength = secureMemGetSize withBytePtr = withSecureMemPtr instance Eq SecureMem where (==) = secureMemEq instance Monoid SecureMem where mempty = unsafeCreateSecureMem 0 (\_ -> return ()) mappend = secureMemAppend mconcat = secureMemConcat type Finalizer = Ptr Word8 -> IO () type FinalizerWithSize = CInt -> Ptr Word8 -> IO () -- | Types that can be converted to a secure mem object. class ToSecureMem a where toSecureMem :: a -> SecureMem instance ToSecureMem SecureMem where toSecureMem a = a instance ToSecureMem ByteString where toSecureMem bs = secureMemFromByteString bs -- | Generic eq function foreign import ccall "compare_eq" compareEq :: CInt -> Ptr Word8 -> Ptr Word8 -> IO Bool -- | Specialized eq functions which are much faster foreign import ccall "compare_eq8" compareEq8 :: Ptr Word8 -> Ptr Word8 -> IO Bool foreign import ccall "compare_eq16" compareEq16 :: Ptr Word8 -> Ptr Word8 -> IO Bool foreign import ccall "compare_eq24" compareEq24 :: Ptr Word8 -> Ptr Word8 -> IO Bool foreign import ccall "compare_eq32" compareEq32 :: Ptr Word8 -> Ptr Word8 -> IO Bool foreign import ccall "compare_eq64" compareEq64 :: Ptr Word8 -> Ptr Word8 -> IO Bool foreign import ccall "compare_eq128" compareEq128 :: Ptr Word8 -> Ptr Word8 -> IO Bool foreign import ccall "compare_eq256" compareEq256 :: Ptr Word8 -> Ptr Word8 -> IO Bool #if MIN_VERSION_base(4,6,0) -- | Scruber finalizers foreign import ccall "finalizer_scrub8" finalizerScrub8 :: Finalizer foreign import ccall "finalizer_scrub16" finalizerScrub16 :: Finalizer foreign import ccall "finalizer_scrub24" finalizerScrub24 :: Finalizer foreign import ccall "finalizer_scrub32" finalizerScrub32 :: Finalizer foreign import ccall "finalizer_scrub64" finalizerScrub64 :: Finalizer foreign import ccall "finalizer_scrub128" finalizerScrub128 :: Finalizer foreign import ccall "finalizer_scrub256" finalizerScrub256 :: Finalizer foreign import ccall "finalizer_scrubvar" finalizerScrubVar :: FinalizerWithSize szToScruber :: Int -> Ptr Word8 -> IO () szToScruber 0 = \_ -> return () szToScruber 8 = finalizerScrub8 szToScruber 16 = finalizerScrub16 szToScruber 24 = finalizerScrub24 szToScruber 32 = finalizerScrub32 szToScruber 64 = finalizerScrub64 szToScruber 128 = finalizerScrub128 szToScruber 256 = finalizerScrub256 szToScruber n = finalizerScrubVar (fromIntegral n) #endif -- | Allocate a foreign ptr which will be scrubed before memory free. -- the memory is allocated on the haskell heap allocateScrubedForeignPtr :: Int -> IO (ForeignPtr a) allocateScrubedForeignPtr sz = do #if MIN_VERSION_base(4,6,0) fptr@(ForeignPtr addr _) <- mallocForeignPtrBytes sz addForeignPtrConcFinalizer fptr (scruber (Ptr addr)) return fptr where !scruber = szToScruber sz #else mallocForeignPtrBytes sz #endif -- | Allocate a new SecureMem -- -- The memory is allocated on the haskell heap, and will be scrubed -- before being released. allocateSecureMem :: Int -> IO SecureMem #if MIN_VERSION_base(4,6,0) allocateSecureMem sz = SecureMem <$> allocateScrubedForeignPtr sz #else allocateSecureMem sz = SecureMem <$> allocateScrubedForeignPtr sz <*> pure sz #endif -- | Create a new secure mem and running an initializer function createSecureMem :: Int -> (Ptr Word8 -> IO ()) -> IO SecureMem createSecureMem sz f = do sm <- allocateSecureMem sz withSecureMemPtr sm f return sm -- | Create a new secure mem using inline perform IO to create a pure -- result. unsafeCreateSecureMem :: Int -> (Ptr Word8 -> IO ()) -> SecureMem unsafeCreateSecureMem sz f = B.inlinePerformIO (createSecureMem sz f) -- | This is a way to look at the pointer living inside a foreign object. This -- function takes a function which is applied to that pointer. The resulting IO -- action is then executed -- -- this is similary to withForeignPtr for a ForeignPtr withSecureMemPtr :: SecureMem -> (Ptr Word8 -> IO b) -> IO b withSecureMemPtr sm f = withForeignPtr (getForeignPtr sm) f -- | similar to withSecureMem but also include the size of the pointed memory. withSecureMemPtrSz :: SecureMem -> (Int -> Ptr Word8 -> IO b) -> IO b withSecureMemPtrSz sm f = withForeignPtr (getForeignPtr sm) (f (secureMemGetSize sm)) -- | Finalize a SecureMem early finalizeSecureMem :: SecureMem -> IO () finalizeSecureMem sm = finalizeForeignPtr $ getForeignPtr sm -- | Create a bytestring from a Secure Mem secureMemToByteString :: SecureMem -> ByteString secureMemToByteString sm = B.unsafeCreate sz $ \dst -> withSecureMemPtr sm $ \src -> B.memcpy dst src (fromIntegral sz) where !sz = secureMemGetSize sm -- | Create a SecureMem from a bytestring secureMemFromByteString :: ByteString -> SecureMem secureMemFromByteString b = B.inlinePerformIO $ do sm <- allocateSecureMem len withSecureMemPtr sm $ \dst -> withBytestringPtr $ \src -> B.memcpy dst src (fromIntegral len) return sm where (fp, off, !len) = B.toForeignPtr b withBytestringPtr f = withForeignPtr fp $ \p -> f (p `plusPtr` off)