Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I'm curious about how GC languages handle crypto. Is it a risk that decrypted stuff or keys and things may be left in memory (heap?) before the next GC cycle?


What we did with Java (J/SAFE) was to add explicit methods to zero out sensitive info. It was a bit of a PITA because Java's never had consistent semantics about when final(ize,ly) methods were called. Later we added code to track which objects were allocated, but no longer needed, which also wasn't much fun.

Back in the Oak days Sun asked us (I was at RSADSI at the time) to review the language spec for security implications. Our big request was to add the "secure" storage specifier for data. The idea being a variable, const, whatever that was marked "secure" would be guaranteed not to be swapped out to disk (or one of a number of other system specific behaviors). But it was hard to find a concrete behavior that would work for all platforms they were targeting (mostly smaller systems at the time.)

My coworker Bob Baldwin had an existing relationship with Bill Joy and James Gosling (I'm assuming as part of the MIT mafia) so he led the meetings. Joy's response (or maybe Goslings, can't remember anymore) was "Language extension requests should be made on a kidney. Preferably a human kidney. Preferably yours. That way you'll think long and hard about it and you sure as hell won't submit 2."


You might find this proposal and the upcoming runtime/secret package interesting.

https://github.com/golang/go/issues/21865


If you have access to the local machine no language will save you.


Sure. But there are several graduations of threat between "zero access" and "complete access." On the intarwebs, every request is from a potential attacker. Attackers are known for violating RFC3514, so it is frequently useful to build a trust model and use existing access control mechanism to deny "sensitive" data (or control functions) to protocol participants who cannot verify their identity and/or access permission.

These models can get complex quickly, but are nevertheless important to evaluate a system's specified behaviour.

No system is perfect and your mileage may vary.


To oversimplifiy, it's like the same-ish risk level as JS or PHP or Ruby? (assuming the underlying algorithm is good)


I evaluated but didn't adopt https://github.com/awnumar/memguard in Go. No matter how well-implemented and reliable it is, I can't pass its secrets to https://github.com/FiloSottile/age.

I assume all process memory may contain residual secrets. As a mitigation in a password manager and an encrypted file editor, I prevent process memory from being swapped to disk with https://pkg.go.dev/syscall#Mlockall.


I'm pretty sure that C's free() and C++'s delete() will happily leave private data on the heap also.

Not sure why you'd think GC'd languages carry more risk.


Cause I was ignorant, until the helpful responses.


It can be, another risk it that a secret value is left on the stack, and is never overwritten because the stack doesn't get to that memory address again, so it's never overwritten or zerod.

Go really just needs a few `crypto.Secret` values of various sizes, or maybe a generic type that could wrap arrays. Then the runtime can handle all the best practices, like a single place in memory, and aggressive zeroing of any copies, etc.


It's not that simple! What about intermediate values during arithmetic computations? What about registers spilling during signal handling?

I honestly thought it could not be done safely, but the runtime/secret proposal discussion proved me wrong.


clear([]byte) if you want to go to the extreme and clean your own memory.


This only wipes one copy. The GC is free to move the allocation around, and is not required to clear the old copies.


Wrong, the []byte is a pointer. There is no copy anywhere. That's why using []byte in encryption makes sense - you can wipe it out whenever you need, whereas string, the only immutable type in Go, would be a problem. Same can be done with array([32]byte).


Go has a precise garbage collector that knows where all the pointers are. So while yes, []byte is a (fat) pointer, the GC is free to move its target to a new location, as long as it updates all the pointers to it. This means that you may observe the address returned by &s[0] for some slice s changing even though you did nothing to s yourself.

The process of actually moving allocated memory around by the GC is known as compaction. It's not done aggressively today but Go reserves the right to do so in the future.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: