securemem-0.1.9/0000755000000000000000000000000012533330634011676 5ustar0000000000000000securemem-0.1.9/LICENSE0000644000000000000000000000272712533330634012713 0ustar0000000000000000Copyright (c) 2013-2014 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.9/README.md0000644000000000000000000000174412533330634013163 0ustar0000000000000000securemem ========= [![Build Status](https://travis-ci.org/vincenthz/hs-securemem.png?branch=master)](https://travis-ci.org/vincenthz/hs-securemem) [![BSD](http://b.repl.ca/v1/license-BSD-blue.png)](http://en.wikipedia.org/wiki/BSD_licenses) [![Haskell](http://b.repl.ca/v1/language-haskell-lightgrey.png)](http://haskell.org) Securemem provides memory chunks that allow auto-scrubbing of the memory after use, and constant time equality. Documentation: [securemem on hackage](http://hackage.haskell.org/package/securemem) Interacting with securemem -------------------------- It's recommended to use the [Byteable instance](http://hackage.haskell.org/package/byteable) when providing an interface that takes a securemem. It allow legacy code, and work in progress code to interface with securemem more easily. older base ---------- On older base, the memory is not scrubbed: upgrade your GHC to 7.6.0 or above. TODO ---- * add a custom memory allocator that give mlocked memory chunks. securemem-0.1.9/securemem.cabal0000644000000000000000000000210612533330634014646 0ustar0000000000000000Name: securemem Version: 0.1.9 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 extra-doc-files: README.md Library Exposed-modules: Data.SecureMem Build-depends: base >= 4 && < 5 , bytestring , byteable >= 0.1.1 , memory >= 0.7 , ghc-prim C-sources: cbits/utils.c ghc-options: -Wall -fwarn-tabs source-repository head type: git location: https://github.com/vincenthz/hs-securemem securemem-0.1.9/Setup.hs0000644000000000000000000000005612533330634013333 0ustar0000000000000000import Distribution.Simple main = defaultMain securemem-0.1.9/cbits/0000755000000000000000000000000012533330634013002 5ustar0000000000000000securemem-0.1.9/cbits/utils.c0000644000000000000000000000431312533330634014307 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 compare_eq(uint32_t size, uint8_t *p1, uint8_t *p2) { uint32_t i; int acc = 1; for (i = 0; i < size; 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.9/Data/0000755000000000000000000000000012533330634012547 5ustar0000000000000000securemem-0.1.9/Data/SecureMem.hs0000644000000000000000000001273512533330634015000 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 , secureMemFromByteable ) where import Foreign.ForeignPtr (withForeignPtr) import Foreign.Ptr import Data.Word (Word8) import Data.Monoid import Control.Applicative import Data.Byteable import Data.ByteString (ByteString) import Data.ByteArray (ScrubbedBytes) import qualified Data.ByteArray as B import qualified Data.Memory.PtrMethods as B (memSet) import qualified Data.ByteString.Internal as BS #if MIN_VERSION_base(4,4,0) import System.IO.Unsafe (unsafeDupablePerformIO) #else import System.IO.Unsafe (unsafePerformIO) #endif pureIO :: IO a -> a #if MIN_VERSION_base(4,4,0) pureIO = unsafeDupablePerformIO #else pureIO = unsafePerformIO #endif -- | 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 ScrubbedBytes secureMemGetSize :: SecureMem -> Int secureMemGetSize (SecureMem scrubbedBytes) = B.length scrubbedBytes secureMemEq :: SecureMem -> SecureMem -> Bool secureMemEq (SecureMem sm1) (SecureMem sm2) = sm1 == sm2 secureMemAppend :: SecureMem -> SecureMem -> SecureMem secureMemAppend (SecureMem s1) (SecureMem s2) = SecureMem (s1 `mappend` s2) secureMemConcat :: [SecureMem] -> SecureMem secureMemConcat = SecureMem . mconcat . map unSecureMem where unSecureMem (SecureMem sb) = sb secureMemCopy :: SecureMem -> IO SecureMem secureMemCopy (SecureMem src) = SecureMem `fmap` B.copy src (\_ -> return ()) withSecureMemCopy :: SecureMem -> (Ptr Word8 -> IO ()) -> IO SecureMem withSecureMemCopy (SecureMem src) f = SecureMem `fmap` B.copy src f 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 -- | 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 -- | 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 <$> B.create sz (\_ -> return ()) -- | Create a new secure mem and running an initializer function createSecureMem :: Int -> (Ptr Word8 -> IO ()) -> IO SecureMem createSecureMem sz f = SecureMem `fmap` B.create sz f -- | Create a new secure mem using inline perform IO to create a pure -- result. unsafeCreateSecureMem :: Int -> (Ptr Word8 -> IO ()) -> SecureMem unsafeCreateSecureMem sz f = pureIO (createSecureMem sz f) {-# NOINLINE unsafeCreateSecureMem #-} -- | 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 sm) f = B.withByteArray sm f -- | similar to withSecureMem but also include the size of the pointed memory. withSecureMemPtrSz :: SecureMem -> (Int -> Ptr Word8 -> IO b) -> IO b withSecureMemPtrSz (SecureMem sm) f = B.withByteArray sm (f (B.length sm)) -- | Finalize a SecureMem early finalizeSecureMem :: SecureMem -> IO () finalizeSecureMem (SecureMem sb) = B.withByteArray sb $ \p -> B.memSet p 0 (B.length sb) -- | Create a bytestring from a Secure Mem secureMemToByteString :: SecureMem -> ByteString secureMemToByteString sm = BS.unsafeCreate sz $ \dst -> withSecureMemPtr sm $ \src -> BS.memcpy dst src (fromIntegral sz) where !sz = secureMemGetSize sm -- | Create a SecureMem from a bytestring secureMemFromByteString :: ByteString -> SecureMem secureMemFromByteString b = pureIO $ do sm <- allocateSecureMem len withSecureMemPtr sm $ \dst -> withBytestringPtr $ \src -> BS.memcpy dst src (fromIntegral len) return sm where (fp, off, !len) = BS.toForeignPtr b withBytestringPtr f = withForeignPtr fp $ \p -> f (p `plusPtr` off) {-# NOINLINE secureMemFromByteString #-} -- | Create a SecureMem from any byteable object secureMemFromByteable :: Byteable b => b -> SecureMem secureMemFromByteable bs = pureIO $ do sm <- allocateSecureMem len withSecureMemPtr sm $ \dst -> withBytePtr bs $ \src -> BS.memcpy dst src (fromIntegral len) return sm where len = byteableLength bs {-# NOINLINE secureMemFromByteable #-}