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

feature request: deterministic randomness? #275

Closed
dkg opened this issue Nov 5, 2020 · 8 comments
Closed

feature request: deterministic randomness? #275

dkg opened this issue Nov 5, 2020 · 8 comments

Comments

@dkg
Copy link
Collaborator

dkg commented Nov 5, 2020

One of my major use cases for faketime is deterministic output of tools that read from the clock. This is typically for test suites i'm trying to make deterministic (e.g., when generating X.509 certificates).

However, some of these tools also invoke getrandom(2) and include the bytes it returns in their output. (e.g., X.509 certificate generation typically includes a randomized serial number; or, secret key generation selecting large primes).

It would be nice to be able to use faketime's preload shim to also be able to replace the output provided by getrandom with deterministic bytes generated from a known seed.

Note: doing so in production would definitely be cryptographically disastrous, so i wouldn't want this to happen by default. I'm imagining that the command line would look something like:

faketime --getrandom-deterministic-seed=<seed> <timestamp> <program> [arguments]

I recognize that some programs still also use the legacy /dev/random and /dev/urandom filesystem interfaces for entropy. But I'd be happy with an implementation that just makes the output of getrandom(2) deterministic as a starting point.

The choice of PRNG to used here (and how to interpret the seed so that it works correctly) seem like implementation details that aren't super critical as long as they choices are well-documented and stable. For example, yarrow 256, with no online sources, fed with an initial seed that's a sha512 digest of the bytes of the null-terminated <seed> argument, would be fine.

@wolfcw
Copy link
Owner

wolfcw commented Nov 5, 2020

That's an interesting suggestion in the wider "deterministic" context. We haven't considered it yet, since it's not directly related to date or time functions, but I get your point. I'm not sure (lib)faketime is the best place for it, or whether there rather should be a similar (lib)fakerandom for that purpose, but it's something that might be worth trying out and then we can see whether it evolves within (lib)faketime or separately.

It would require twofold preparations. First, we need a list of function calls to intercept; I'm not sure whether getrandom() is the only one, but at least some others like getentropy() are flagged as glibc test and seem to be based on getrandom(). Also, we'll need a CPRNG implementation that is available on the target platform or which we can integrate in the libfaketime source, so the implementation, not only the design license will have to be safe to use for that purpose. I'll look into Yarrow.

@dkg
Copy link
Collaborator Author

dkg commented Nov 5, 2020

yep, i considered a (lib)fakerandom as a distinct thing from (lib)faketime -- but it seems similar enough in both implementation and use cases that seemed weird to try to repeat all the setup, portability, and infrastructure work that (lib)faketime already does well.

@wolfcw
Copy link
Owner

wolfcw commented Nov 10, 2020

After looking at Yarrow, its successor Fortuna, and some other CPRNG implementations, I assume that the biggest obstacle here is the dependencies (on cryptographic hash functions or symmetric block ciphers) most of them bring. I wonder what your opinion about something more lightweight would be, for example Bernard Widynski's Middle Square Weyl Sequence Random Number Generator (see https://mswsrng.wixsite.com/rand). The generated numbers presumably pass quality checks the applications perform, and since the specific purpose here is to arbitrarily re-create the same sequence of random-looking numbers over and over again (based on a user-specific seed), it might be sufficient.

@dkg
Copy link
Collaborator Author

dkg commented Nov 13, 2020

I don't know enough about that particular PRNG to verify it one way or another, but i agree that anything running with this intervention in place isn't going to be cryptographically secure anyway, so it seems plausible that it would be an acceptable approach to use a non-cryptographic PRNG here.

@wolfcw
Copy link
Owner

wolfcw commented Nov 15, 2020

Current HEAD is up for preliminary testing.

Required steps:

  • add -DFAKE_RANDOM, e.g., to CFLAGS in src/Makefile
  • for testing, test/getrandom_test.c may be used, after compiling it, e.g., with gcc -o getrandom_test getrandom_test.c
  • when LD_PRELOADing libfaketime, set environment variable FAKERANDOM_SEED to a 64-bit value of choice. For example, run LD_PRELOAD=src/libfaketime.so.1 FAKERANDOM_SEED="0x12345678DEADBEEF" test/getrandom_test.

getrandom_test should output 100 zero-bytes first, then 100 random bytes. If libfaketime is not used or FAKERANDOM_SEED is not set, the real getrandom() is used. Otherwise, the same 100 "random" bytes should be repeated whenever the same seed value is used.

@dkg
Copy link
Collaborator Author

dkg commented Feb 18, 2021

Just wanted to follow up that this feature is working well for me. I'm using it to coax deterministic PKCS#12 artifacts out of certtool for generating an Internet Draft containing sample objects for S/MIME (see the build scripts if you're interested).

I'd be happy to see a release with this feature available ☺

@wolfcw
Copy link
Owner

wolfcw commented Feb 20, 2021

Thanks for the feedback, and interesting use case. :-) The feature will be part of the next tagged release.

@wolfcw wolfcw closed this as completed Feb 20, 2021
@dkg
Copy link
Collaborator Author

dkg commented Feb 23, 2021

(see the followup bug reports about this on #295)

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

No branches or pull requests

2 participants