Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign upcrypto: facility for key erasure #21865
Comments
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
|
Related to #21374 |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
anitgandhi
Sep 13, 2017
Contributor
Just as another example of what was mentioned at the end, even creating an AES block primitive causes an allocation right before key expansion, which shows wiping the key is inadequate, including how memguard does it.
https://github.com/golang/go/blob/master/src/crypto/aes/cipher.go#L46-L47
The key expansion is a deterministic process so once c.enc and c.dec are set, if the system was compromised such that memory could be scanned, even on a system where memguard is used, an attacker could get the contents of c.enc or c.dec, reverse the key expansion process, and now they have the original key. If I'm not mistaken, you could currently call aes.NewCipher(key) where key points to a memguard buffer, immediately wipe key, then continue to use the instantiated cipher "object" for calls to Encrypt and Decrypt calls, since now only the internally expanded key is required.
This comment explains that as well. Effectively, you'd have to create custom implementations of all the existing crypto code in the standard lib, supplementary x/crypto libs, even indirect packages like math/big would end up getting into scope.
In one sense, you'd have to replace make itself to using manually managed memory, like how memguard does it, but that of course is fundamental change to Golang itself, and would make the niceties of GC pointless
|
Just as another example of what was mentioned at the end, even creating an AES block primitive causes an allocation right before key expansion, which shows wiping the key is inadequate, including how memguard does it. https://github.com/golang/go/blob/master/src/crypto/aes/cipher.go#L46-L47 The key expansion is a deterministic process so once This comment explains that as well. Effectively, you'd have to create custom implementations of all the existing crypto code in the standard lib, supplementary x/crypto libs, even indirect packages like In one sense, you'd have to replace |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
FiloSottile
Sep 14, 2017
Member
This is going to be extremely hard to obtain as a generic guarantee, for all the reasons mentioned here, at #21374 and at awnumar/memguard#3. In particular there is no way to retroactively enforce that an interface implementation does not copy key material on the heap (at least outside of the stdlib, and we don't want a security guarantee that breaks when you use external implementations).
But how about a smaller problem:
- add a
Wipe()method to the implementation (saychacha20poly1305); the method might exist or not based on the platform since implementations can differ, the application can decide to warn or bail out ifWipe()is unavailable by doing an interface-upgrade fromAEAD, or not to compile at all by calling it directly on the concrete type - make an implementation with a
Wipe()method guaranteed not to make copies of the key - if necessary, add a
NewWithAllocator(makeSlice func(size int) []byte)function so that key material is placed in manually allocated memory exempt from GC and swapping (for example viamemguard)- alternatively,
unsafecan be used to instantiate thechacha20poly1305object, but then you'd need aInit()method
- alternatively,
Would that solve your problem enough?
|
This is going to be extremely hard to obtain as a generic guarantee, for all the reasons mentioned here, at #21374 and at awnumar/memguard#3. In particular there is no way to retroactively enforce that an interface implementation does not copy key material on the heap (at least outside of the stdlib, and we don't want a security guarantee that breaks when you use external implementations). But how about a smaller problem:
Would that solve your problem enough? |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
FiloSottile
Sep 14, 2017
Member
Actually, forget Wipe(), it makes no sense if you have NewWithAllocator(makeSlice func(size int) []byte) since you can just use the allocator wiping feature (which memguard offers). Moreover, if you don't have neither NewWithAllocator nor a #21374 solution, Wipe() is useless because of GC copies and swapping.
|
Actually, forget |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
yahesh
Mar 24, 2018
A possibility to reliably wipe secrets used by the crypto library would be highly appreciated. For example, gocryptfs has tried to solve this problem as far as is currently possible by wiping the memory locations it has access to.
However, as the crypto library creates copies of the encryption secrets by deriving encryption keys from the provided secrets it's currently not possible to completely wipe said secrets (and derived keys) from memory.
yahesh
commented
Mar 24, 2018
|
A possibility to reliably wipe secrets used by the crypto library would be highly appreciated. For example, gocryptfs has tried to solve this problem as far as is currently possible by wiping the memory locations it has access to. However, as the crypto library creates copies of the encryption secrets by deriving encryption keys from the provided secrets it's currently not possible to completely wipe said secrets (and derived keys) from memory. |
zx2c4 commentedSep 13, 2017
•
edited
Edited 1 time
-
zx2c4
edited Sep 13, 2017 (most recent)
Forward secrecy is usually only a thing if it's possible to ensure keys aren't actually in memory anymore. Other security properties, too, often require the secure erasure of keys from memory.
The typical way of doing this is through a function such as
explicit_bzero,memzero_explicit, or the various other functions that C library writers provide that ensure an optimization-free routine for zeroing buffers.For the most part, the same is possible in Go application code. However, it is not easily possible to do so with crypto API interfaces that internally manage a key buffer, such as the AEAD interface.
In the Go implementation of WireGuard, @rot256 has been forced to resort to unholy hacks such as:
Having to resort to this kind of reflection is a bit unsettling and something we'd much rather not do.
So, this issue is to request and track the addition of a consistent "Clear()" interface for parts of the Go crypto API that store keys in internal buffers.
Furthermore, even if real clearing is deemed to be an abject failure due to Go's GC, and one must instead mmap/mlock or use a library such as memguard, the AEAD interface still is inadequate, because it appears that SetKey winds up allocating its own buffer internally. So again, big problem.
cc: @agl