Skip to content

crypto/rand: use the userland CSPRNG by default #13820

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
mmcco opened this issue Jan 5, 2016 · 2 comments
Closed

crypto/rand: use the userland CSPRNG by default #13820

mmcco opened this issue Jan 5, 2016 · 2 comments

Comments

@mmcco
Copy link

mmcco commented Jan 5, 2016

This idea originated in #13785 when using OpenBSD's precedent with arc4random(3).

The Go crypto code includes a CSPRNG by default (see src/crypto/rand/rand_unix.go:85). However, it is only used on operating systems that Go doesn't determine to have a reliable, non-blocking randomness sources. Examples of reliable non-blocking randomness sources include a modern /dev/urandom, Linux's getrandom(2), and OpenBSD's getentropy(2).

Many cryptography guides suggest userland CSPRNGs. The possible benefits include:

  • improving performance by avoiding the vast majority of randomness-related syscalls
    • Go's CSPRNG fetches 16 bytes of seed entropy for every 1 MB of generated randomness
  • easing up on the kernel, which may expend considerable effort when serving a Go process's randomness-related syscalls
    • I remember seeing Poul-Henning Kamp quoted that FreeBSD kernel spends 15% of its time on random number generation
  • adding some additional mixing to potentially weak OS-supplied randomness
    • This would be a minimal stopgap. However, the Go currently uses ANSI X9.31 which mixes via AES and kneads in the current nanosecond time, which is better than nothing.
  • potentially being able to replace math/rand with crypto/rand, which would simplify the codebase and prevent misuse of math/rand
    • code for deterministic pseudo-randomness could be condensed, and the ability to seed it could be removed

Network applications that use forward secret encryption make the peformance concerns more relevant.

The primary risk is that we would then rely on the soundness and safety of Go's CSPRNG logic. I don't know whether timing attacks are a risk, but that's one issue that came to mind. The CSPRNG backs up to Go's AES implementation, though, so any risks unique to the CSPRNG would have to be outside of that. The fact that uses a standard algorithm (ANSI X9.31) and a strong crypto primitive (AES) gives me confidence. I'm definitely not qualified to rigorously review something like this, though.

This ticket could also entail a review of the existing CSPRNG and whether it could be stronger.

Thoughts? Also, if anyone knows of relevant profiling techniques and targets, please share. I plan on investigating what kind of performance impact this switch would have.

@mmcco
Copy link
Author

mmcco commented Jan 9, 2016

cc @mdempsky

@bradfitz bradfitz added this to the Unplanned milestone Jan 21, 2016
@agl
Copy link
Contributor

agl commented Mar 11, 2016

Reading from the kernel without caching is simple and safe against things like forks, VM migrations etc(*). There are cases where the amount of entropy needed is very high thus a local PRNG can make sense. It's possible that someone is hitting that and, given evidence of a problem, we might want to ponder the best option. But, short of that, I think the simple and safe behaviour is good.

(*) Assuming that the migration bothers to address the duplication of the kernel's entropy pools.

@agl agl closed this as completed Aug 19, 2016
@golang golang locked and limited conversation to collaborators Aug 19, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants