Description
crypto/rand
exposes an io.Reader
variable Reader
as "a global, shared instance of a cryptographically strong pseudo-random generator." Furthermore, crypto/rand.Read
implicitly uses Reader
for its crypto source.
This seems problematic to me because then any package can just overwrite crypto/rand.Reader
to point to some other object, affecting the security of any packages that rely on crypto/rand.Read
or crypto/rand.Reader
for security, e.g. x/crypto/nacl
.
One can say that a language can never ultimately defend against code running in your same process, but I think it should be possible to write something that depends on crypto/rand
for security that wouldn't require auditing other packages for a single malicious variable write.[1]
The main API flaw here, IMO, is that Reader
is an io.Reader
variable, whereas it should be a function that returns an io.Reader
. A new API would look something like:
// Reader returns an io.Reader that reads from a cryptographically strong pseudo-random number generator.
func Reader() io.Reader
// Read is a helper function that calls Reader() and then passes it to io.ReadFull.
func Read(b []byte) (n int, err error)
Alas, with the Go 1 compatibility guarantee Reader
would have to remain, and Read
would still have to use Reader
. But the above could be added as new functions, say MakeReader()
and SafeRead()
. And the standard library (and other important external packages like x/crypto/nacl
) could be changed to use those safe functions.
[1] Without this flaw, a malicious package would have to use the unsafe package to poke around in the internals of crypto/rand
, or call out to the external OS to e.g. try to redirect access to the random device, which seems easier to audit for than a write to crypto/rand.Reader
. Of course, I'm already assuming that a project worried about this is vendoring all of its dependencies.