
While I *think* GHC currently would do the right thing with a finaliser, these semantics aren't guaranteed anywhere and the correct way would really be to use something along the lines of "withSecureByteString :: (ByteString -> a) -> IO a" (whether the return value of the argument function should be 'a' or 'IO a' is open to discussion, although letting it be 'IO a' gives more opportunity to leak the secret. Cheers, Merijn
On 12 Jan 2015, at 5:16, David Feuer
wrote: I think this is a good idea too. I don't think a scrubbing finalizer can give Erik the timing guarantees he wants (at least not without forcing a major collection by hand, and worrying about stray references), but it does seem likely to be a good thing to have around anyway. Note that for something like a password, you also have to be careful about things like input buffers. I imagine a hypothetical SecureByteString and/or SecureText would have to offer special IO as well.
On Sun, Jan 11, 2015 at 11:08 PM, Carter Schonwald
wrote: David's idea is pretty cool!
wrt Erik's suggestion, I'd rather suggest instead something like what Vincent's secure memory does, which provides finalization support to a bytestring interface
https://hackage.haskell.org/package/securemem-0.1.4/docs/src/Data-SecureMem....
-- | 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
this code can totally be adapted to provide a scrubing finalizer to any foreign pointer of interest, and indeed, it could be done as a helper function for bytestrings a la
addFinalizer :: ByteString -> IO () -> IO ()
or something
On Sun, Jan 11, 2015 at 10:48 PM, David Feuer
wrote: -1. Breaking referential transparency is completely unnecessary here. The correct way to accomplish this, I believe, is to add a mutable ByteString interface, and then a SecureByteString module wrapping it and actually making the promises you want.
On Sun, Jan 11, 2015 at 10:42 PM, Erik de Castro Lopo
wrote: Discussion period: one month
When handling sensitive information (like a user's password) it is desirable to only keep the data around for as short a time as possible. Specifically, relying on the garbage collector to clean it up is simply not good enough.
I therefore propose that the following function to be added to the Data.ByteString.Unsafe module:
-- | Overwrites the contents of a ByteString with \0 bytes. unsafeWipe :: ByteString -> IO () unsafeWipe bs = BS.unsafeUseAsCStringLen bs $ \(ptr, len) -> let go i | i < 0 = return () | otherwise = pokeElemOff ptr i 0 >> go (i - 1) in go (len - 1)
It is added to the Unsafe module because it break referential transparency but since ByteStrings are always kept in pinned memory, it should not otherwise be considered unsafe.
It could be used as follows:
main = do passwd <- getPassword doSomethingWith passwd unsafeWipe passwd restOfProgram
Cheers, Erik -- ---------------------------------------------------------------------- Erik de Castro Lopo http://www.mega-nerd.com/ _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries