Data.ByteString.Unsafe.unsafeWipe

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

Data.ByteString.Unsafe.unsafeWipe

Erik de Castro Lopo-34
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
[hidden email]
http://www.haskell.org/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: Data.ByteString.Unsafe.unsafeWipe

David Feuer
-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
<[hidden email]> 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
> [hidden email]
> http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________
Libraries mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: Data.ByteString.Unsafe.unsafeWipe

David Feuer
In fact, it looks like Michael Snoyman has done some work on this
already: https://www.fpcomplete.com/user/chad/snippets/random-code-snippets/mutable-bytestring
 Perhaps he could be convinced to finish/release it.

David

On Sun, Jan 11, 2015 at 10:48 PM, David Feuer <[hidden email]> 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
> <[hidden email]> 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
>> [hidden email]
>> http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________
Libraries mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: Data.ByteString.Unsafe.unsafeWipe

Carter Schonwald
In reply to this post by David Feuer
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




-- | 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 <[hidden email]> 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
<[hidden email]> 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
> [hidden email]
> http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________
Libraries mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/libraries


_______________________________________________
Libraries mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: Data.ByteString.Unsafe.unsafeWipe

David Feuer
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
<[hidden email]> 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.html
>
>
>
> -- | 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 <[hidden email]> 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
>> <[hidden email]> 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
>> > [hidden email]
>> > http://www.haskell.org/mailman/listinfo/libraries
>> _______________________________________________
>> Libraries mailing list
>> [hidden email]
>> http://www.haskell.org/mailman/listinfo/libraries
>
>
_______________________________________________
Libraries mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: Data.ByteString.Unsafe.unsafeWipe

Merijn Verstraaten
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 <[hidden email]> 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
> <[hidden email]> 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.html
>>
>>
>>
>> -- | 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 <[hidden email]> 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
>>> <[hidden email]> 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
>>>> [hidden email]
>>>> http://www.haskell.org/mailman/listinfo/libraries
>>> _______________________________________________
>>> Libraries mailing list
>>> [hidden email]
>>> http://www.haskell.org/mailman/listinfo/libraries
>>
>>
> _______________________________________________
> Libraries mailing list
> [hidden email]
> http://www.haskell.org/mailman/listinfo/libraries

_______________________________________________
Libraries mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/libraries

signature.asc (859 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Data.ByteString.Unsafe.unsafeWipe

Michael Snoyman
In reply to this post by David Feuer
Actually, after writing that I realized I'd just reinvented storable vectors, and that the entire API can really be summed up by just a pair of functions for converting `ByteString`s with `Vector Word8`s:

http://www.stackage.org/haddock/nightly-2015-01-12/mono-traversable-0.7.0/Data-ByteVector.html

On Mon Jan 12 2015 at 6:02:06 AM David Feuer <[hidden email]> wrote:
In fact, it looks like Michael Snoyman has done some work on this
already: https://www.fpcomplete.com/user/chad/snippets/random-code-snippets/mutable-bytestring
 Perhaps he could be convinced to finish/release it.

David

On Sun, Jan 11, 2015 at 10:48 PM, David Feuer <[hidden email]> 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
> <[hidden email]> 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
>> [hidden email]
>> http://www.haskell.org/mailman/listinfo/libraries

_______________________________________________
Libraries mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: Data.ByteString.Unsafe.unsafeWipe

Vincent Hanquez
In reply to this post by David Feuer

On 12/01/2015 04: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.
securemem has a finalizeSecureMem [1] which is just a wrapper for finalizeForeignPtr, which
run the finalizer immediately.

I agree though, that you might want the whole package of secure input/output functions
to be able to handle it end-to-end, and securemem was always a paving stone in this direction for me.

[1] finalizeSecureMem

--
Vincent

_______________________________________________
Libraries mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/libraries