4 ms·
Go Cryptography State of the Union
- edoceo 11mo agoI'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?
- Thaxll 11mo agoIf you have access to the local machine no language will save you.
- edoceo 11mo agoTo oversimplifiy, it's like the same-ish risk level as JS or PHP or Ruby? (assuming the underlying algorithm is good)
- OhMeadhbh 11mo agoSure. 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.
- OhMeadhbh 11mo agoWhat 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."
- alphazard 11mo agoIt 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.
- FiloSottile 11mo agoIt'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.
- FiloSottile 11mo agoYou might find this proposal and the upcoming runtime/secret package interesting. https://github.com/golang/go/issues/21865 https://github.com/golang/go/issues/21865
- networked 11mo agoI evaluated but didn't adopt https://github.com/awnumar/memguard 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 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 https://pkg.go.dev/syscall#Mlockall.
- gethly 11mo agoclear([]byte) if you want to go to the extreme and clean your own memory.
- kbolino 11mo agoThis only wipes one copy. The GC is free to move the allocation around, and is not required to clear the old copies.
- gethly 11mo agoWrong, 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).
- kbolino 11mo agoGo 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.
- stackghost 11mo agoI'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.
- edoceo 11mo agoCause I was ignorant, until the helpful responses.
- OhMeadhbh 11mo agoI'm more of a C person than a Go person, but I am unbelievably happy that someone in that community is using the word "cryptography" to mean cryptography and not Bitcoin.
- jsheard 11mo agoWasn't it just the shorthand "crypto" that got co-opted by the Shitcoin Industrial Complex? I think "cryptography" still means what it always meant regardless of who you ask.
- OhMeadhbh 11mo agoThat's mostly the case, but I've seen job postings for "cryptography experts" that are, as best I can tell, looking for block chain hucksters. But I'm unlikely to work for Microsoft, so I just ignore them.
- jsheard 11mo agoWell yeah, someone hired to work with the low-level nuts and bolts of blockchains would ideally need to know their way around actual bona-fide cryptography.
- OhMeadhbh 11mo agoRespectfully disagree. My experience is that they've read a couple chapters from Applied Cryptography and think "IACR" is a router manufacturer. But we all see different parts of the industry. Happy to hear you're encountering more capable people in that industry.
- FiloSottile 11mo agoThere are definitely better cryptographers than me working at Zcash, for example.
- 11mo ago
- alphazard 11mo agoI don't know why the standard library crypto packages insist on passing around `[]byte` for things like a seed value, or why we can't just pass in a seed value to a single unambiguous constructor when generating asymmetric keys. Or how the constructor for a key pair could possibly return an error, when the algorithm is supposed to be deterministic. It all just seems a bit sloppy. Asking for a seed value like `[32]byte` could at least communicate to me that the level of security is at most 256 bits. And removing all dependencies on rand would make it obvious where the entropy must be coming from (the seed parameter). Cloudflare's CIRCL[0] library does a bit better, but shares some of the same problems. [0] https://github.com/cloudflare/circl https://github.com/cloudflare/circl
- FiloSottile 11mo ago> I don't know why the standard library crypto packages insist on passing around `[]byte` for things like a seed value These are actually very deliberate choices, based on maybe unintuitive experience. We use []byte instead of e.g. [32]byte because generally you start with a []byte that's coming from somewhere: the network, a file format, a KDF. Then you have two options to get a [32]byte: cast or copy. They both have bad failure modes. If you do a ([32]byte)(foo) cast, you risk a panic if the file/packet/whatever is not the size you expected (e.g. because it's actually attacker controlled). If you do a copy(seed, foo) it's WAY WORSE, because you risk copying only 5 bytes and leaving the rest to zero and not noticing. Instead, we decided to move the length check into the library everywhere we take bytes, so at worst you get an error, which presumably you know how to handle. > why we can't just pass in a seed value to a single unambiguous constructor when generating asymmetric keys I am not sure what you are referring to here. For e.g. ML-KEM, you pass the seed to NewDecapsulationKey768 and you get an opaque *DecapsulationKey768 to pass around. We've been moving everything we can to that. > Or how the constructor for a key pair could possibly return an error, when the algorithm is supposed to be deterministic. Depends. If it takes a []byte, we want to return an error to force handling of incorrect lengths. If the key is not a seed (which is only an option for private keys), it can also be invalid, deterministic or not. (This is why I like seeds. https://words.filippo.io/ml-kem-seeds/ https://words.filippo.io/ml-kem-seeds/) > removing all dependencies on rand would make it obvious where the entropy must be coming from (the seed parameter) Another place where experience taught us otherwise. Algorithms that take a well-specified seed should indeed just take that (like NewDecapsulationKey768 does!), but where the spec annoyingly takes "randomness from the sky" (https://words.filippo.io/avoid-the-randomness-from-the-sky/ https://words.filippo.io/avoid-the-randomness-from-the-sky/) in an unspecified way, taking a io.Reader gave folks the wrong impression that they could use that for deterministic key generation, which then breaks as soon as we change the internals. There is only one place to get entropy from in a Go program, anyway: crypto/rand. Anything else is a testing need, and it can be handled with test affordances like the upcoming crypto/mlkem/mlkemtest or testing/cryptotest.SetGlobalRandom.
- Aman_Kalwar 11mo ago[flagged]
- pregnenolone 11mo agoI agree with the author’s sentiment about FIPS 140. I find NIST to be incredibly slow. I understand there must be some stability, but they are too slow. For example, I think it's horrible that they are still recommending PBKDF2 in 2025.
- SAI_Peregrinus 11mo agoA big part of the problem I have with it is that it's a "ceiling" on security. Things like electrical code or building code are a "floor" on quality, you have to be at least as good as the code requirements, but can freely be better. FIPS-140 bounds you both ways. If you could more easily do better it'd be much less of a problem that NIST are slow.
- fl0ki 11mo agoIn fairness, it's one thing for an implementation like a building to be as over-enginereed as possible in its own right, but it's another when a standard has to ensure that multiple implementations can interoperate. I'm not saying FIPS-140 has only that kind of limitation (far from it), just that this isn't the best analogy.
- akerl_ 11mo agoIs any of FIPS about ensuring interoperability?
- dlgeek 11mo agoYeah, there's a ton of correctness testing involved. That's mostly at the algorithm, rather than the module level, so it'll fall under CAVP/ACVP rather than CMVP.
- akerl_ 11mo agoThat's not for interop, that's for "are you actually doing the crypto you said you'd do". It's designed to prevent broken crypto, not to ensure coordination between parties.
- Shelby-Thomas 11mo ago[flagged]
- Shelby-Thomas 11mo ago[flagged]
- deleted 11mo ago[deleted]
- Steve-Tony 11mo ago[flagged]
- Brian-Watkins 11mo ago[flagged]
- leoqa 11mo agoWhat’s up with all these bots posting 3-4 sentence summaries in the comment section?
- ronsor 11mo agoFarming points for later shilling.
- qiufeng111 11mo ago[dead]