packages feed

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 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