securemem (empty) → 0.1.0
raw patch · 6 files changed
+386/−0 lines, 6 filesdep +basedep +byteabledep +bytestringsetup-changed
Dependencies added: base, byteable, bytestring, ghc-prim
Files
- Data/SecureMem.hs +190/−0
- LICENSE +27/−0
- README.md +4/−0
- Setup.hs +2/−0
- cbits/utils.c +133/−0
- securemem.cabal +30/−0
+ Data/SecureMem.hs view
@@ -0,0 +1,190 @@+-- |+-- Module : Data.SecureMem+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : Stable+-- Portability : GHC+--+{-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE MagicHash #-}+module Data.SecureMem+ ( SecureMem+ , secureMemGetSize+ , ToSecureMem(..)+ -- * Allocation and early termination+ , allocateSecureMem+ , createSecureMem+ , unsafeCreateSecureMem+ , finalizeSecureMem+ -- * Pointers manipulation+ , withSecureMemPtr+ , withSecureMemPtrSz+ -- * convertion+ , secureMemFromByteString+ ) where++import Foreign.C.Types+import Foreign.ForeignPtr (withForeignPtr, finalizeForeignPtr)+import Foreign.Ptr+import GHC.Types (Int(..))+import GHC.ForeignPtr (ForeignPtr(..), ForeignPtrContents(..), mallocForeignPtrBytes, addForeignPtrConcFinalizer)+import GHC.Prim (sizeofMutableByteArray#)+import GHC.Ptr (Ptr(..))+import Data.Word (Word8)+import Data.Monoid+import Control.Applicative ((<$>))+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+newtype SecureMem = SecureMem (ForeignPtr Word8)++-- | 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"++instance Show SecureMem where+ show _ = "<secure-mem>"++instance Byteable SecureMem where+ toBytes = secureMemToByteString++instance Eq SecureMem where+ 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)++instance Monoid SecureMem where+ mempty = unsafeCreateSecureMem 0 (\_ -> return ())+ mappend 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++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++-- | 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)++-- | 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+ fptr@(ForeignPtr addr _) <- mallocForeignPtrBytes sz+ addForeignPtrConcFinalizer fptr (scruber (Ptr addr))+ return fptr+ where !scruber = szToScruber sz++-- | Allocate a new SecureMem+--+-- The memory is allocated on the haskell heap, and will be scrubed+-- before being released.+allocateSecureMem :: Int -> IO SecureMem+allocateSecureMem sz = SecureMem <$> allocateScrubedForeignPtr sz++-- | 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 (SecureMem fptr) f = withForeignPtr fptr f++-- | similar to withSecureMem but also include the size of the pointed memory.+withSecureMemPtrSz :: SecureMem -> (Int -> Ptr Word8 -> IO b) -> IO b+withSecureMemPtrSz sm@(SecureMem fptr) f = withForeignPtr fptr (f (secureMemGetSize sm))++-- | Finalize a SecureMem early+finalizeSecureMem :: SecureMem -> IO ()+finalizeSecureMem (SecureMem fptr) = finalizeForeignPtr fptr++-- | 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)
+ LICENSE view
@@ -0,0 +1,27 @@+Copyright (c) 2013 Vincent Hanquez <vincent@snarc.org>++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.
+ README.md view
@@ -0,0 +1,4 @@+securemem+=======++Documentation: [securemem on hackage](http://hackage.haskell.org/package/securemem)
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ cbits/utils.c view
@@ -0,0 +1,133 @@+#include <stdint.h>+#include <stdlib.h>+#include <string.h>++#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.cabal view
@@ -0,0 +1,30 @@+Name: securemem+Version: 0.1.0+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 <vincent@snarc.org>+Author: Vincent Hanquez <vincent@snarc.org>+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+ , ghc-prim+ C-sources: cbits/utils.c+ ghc-options: -Wall -fwarn-tabs++source-repository head+ type: git+ location: git://github.com/vincenthz/hs-securemem