Skip to content
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

Evaluate the correct built-in RNG implementation #620

Closed
codefromthecrypt opened this issue Jun 4, 2022 · 4 comments
Closed

Evaluate the correct built-in RNG implementation #620

codefromthecrypt opened this issue Jun 4, 2022 · 4 comments
Labels
enhancement New feature or request

Comments

@codefromthecrypt
Copy link
Contributor

codefromthecrypt commented Jun 4, 2022

Is your feature request related to a problem? Please describe.
A while back, we switched from math to crypto RNG. This seemed correct at the time, but go's docs hint at a sandbox problem

// Reader is a global, shared instance of a cryptographically
// secure random number generator.
//
// On Linux and FreeBSD, Reader uses getrandom(2) if available, /dev/urandom otherwise.
// On OpenBSD, Reader uses getentropy(2).
// On other Unix-like systems, Reader reads from /dev/urandom.
// On Windows systems, Reader uses the RtlGenRandom API.

What I'm concerned with is a WebAssembly module exhausting the host entropy source. Elsewhere, such as clocks (#616) we don't expose something that can be used as a covert channel, or break the sandbox.

Moreover, there's a tacit "capabilities" approach in how people describe WASI, though implementation is very inconsistent across projects. A capabilities approach would default to a fake random, or at least something that can't exhaust the host.

Describe the solution you'd like

I'd like advice on if we should change the default and what it would change to. If we are to stay the same, that's also fine, but we should raise a PR to update RATIONALE.md on it.

So, I think we need to clarify for the API

  • what the value users should supply, which satisfies what imports need?
    • ex an adaquately seeded CSPRNG vs something else
  • what is the default when one was never supplied?

Related context

Imports that will consume this:

Related imports we can address now or another way, possibly arch-specific, later:

@codefromthecrypt codefromthecrypt added the enhancement New feature or request label Jun 4, 2022
@codefromthecrypt
Copy link
Contributor Author

@knqyf263 @sam-at-luther if both of you have time to contribute a suggestion, much obliged

@codefromthecrypt codefromthecrypt mentioned this issue Jun 4, 2022
13 tasks
@inkeliz
Copy link
Contributor

inkeliz commented Jun 4, 2022

Maybe there's a better way, but an easy one is to use hashes. Hashes are PRF by default; In that particular cases seems that XOF (Extendable-Output Functions) can be used as "DRBG", and will do the job just fine.

Personally, I use that quite alot with Blake2, something like (error checks removed for simplicity):

import (
	"crypto/rand"
	"fmt"

	"golang.org/x/crypto/blake2b"
)

type rngGenerator struct {
	blake2b.XOF
}

func newRNGGenereator() (rng rngGenerator) {
	key := make([]byte, 64)
	rand.Read(key)
	rng.XOF, _ = blake2b.NewXOF(blake2b.OutputLengthUnknown, key)
	return rng
}

func main() {

	rng := newRNGGenereator()

	output := make([]byte, 123)
	for i := 0; i < 10; i++ {
		rng.Read(output) // can read many times, up to 256GiB, I think. The size can vary, it's not fixed.
		fmt.Printf("%X \n", output)
	}
}

You need rand for the initialization, but after that each Read is independent from the rand and the XOF is used to generate random data. In that case, the guest can request bunch for random data and that will be random and independent from the host entropy and others guests. You may need to re-initialize the XOF once and while (due to 256Gib limits), but that still saving from reading rand everytime, it's also possible to extend itself, using the output as seed to the next XOF.

EDIT: To make it easier to undestand: random_get function will read from the XOF, instead of getting it from rand. On each new module, it will create one new XOF "session" and use rand just once.


It's possible to use SHA-3 too. In that case it's ShakeHash (https://pkg.go.dev/golang.org/x/crypto/sha3#ShakeHash), same concept. I'm not sure if SHA-3 have such limitation on the stream size.

However, both imports packages from golang.org/x/crypto, and maybe there's a simple and better way to do the thing.

@codefromthecrypt
Copy link
Contributor Author

Thanks @inkeliz. I'll defer until other end users chime in. Commenting only because you mentioned something I left out of the desc. the consumers of this api (and we may need more than one, similar to how we have wall time and nanotime)

So, I think we need to clarify for the API

  • what the value users should supply, which satisfies what imports need?
    • ex an adaquately seeded CSPRNG vs something else
  • what is the default when one was never supplied?

Here are the use cases I've added to the desc

We also have some related imports, too

@mathetake
Copy link
Member

what's the next action on this issue, given that no one has chimed in since Jun 2022?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants