Closed dhardy closed 5 years ago
I understand there would be resistance to moving JitterRng into rand_os. Is this really justified?
I do not consider JitterRng
as meeting the contract of an OsRng
. It is bespoke Rust code, as opposed to a system-provided CSRNG. Personally I would like something where if an OS / platform-specific RNG is not available, it will refuse to compile, as opposed to falling back to JitterRng
.
Personally I would like something where if an OS / platform-specific RNG is not available, it will refuse to compile
The current compile_error!
is not an option due to the required cfgs being over-complex, but (1) is close enough.
I am not proposing to adjust OsRng
in any other way; simply to add EntropyRng
and JitterRng
to the same crate.
the conclusion of #678 is that Rand should always build for wasm32-unknown-unknown, failing if necessary at run-time.
I disagree with it. I believe that rand_os
should fail at compile time for wasm32-unknown-unknown
if none of stdweb
or wasm_bindgen
features are enabled, or if they are enabled both.
The breakage caused by splitting code into rand_os
is indeed unfortunate, but I think we better do the following:
rand_os v0.1.1
which will use stdweb
as a "default"rand_os v0.1.0
rand_os v0.2.0
which will use compile error if both or none of the features are enabledYou can't have target specific features with cargo atm, therefore it is impossible to correctly implement failing to compile at the moment. I have indirect dependencies on rand through criterion and parking_lot. You can't realistically disable the rand_os dependency (via rand's std feature as far as I understand) for both of these crates. Therefore my use case will always (or at least until cargo can support target specific features) compile in rand_os without using stdweb or wasm_bindgen. So failing to compile is not a realistic option until then.
What is needed is either a split between the -unknown and a potential -web target and / or fixing cargo.
I disagree with it.
Noted, but the alternative is to keep telling those who complain about broken CI that they need more complex set-up to add the required feature on WASM... I guess this is possible, but it's a support nightmare.
@CryZe you can probably do this — force your CI tests to depend on WASM + stdweb (or -bindgen). However if you don't use Rand directly, you will need to add it (as a dev-dependency or via another crate only used for testing).
publish rand_os v0.2.0 which will use compile error if both or none of the features are enabled
Well, I disagree with that, because there is a plan to eventually make the two compatible.
What is needed is either a split between the -unknown and a potential -web target and / or fixing cargo.
Agreed; however for now we have to support wasm32-unknown-unknown
, and for that I think we're justified in deviating a little from how we normally do things.
It's not my tests that are broken, it's the actual compile (the tests work just fine). For my actual compile, I can't activate either stdweb or wasm-bindgen feature, because I'm not using them (I'm using a different binding generator, so this is kind of the truly "unknown" use case where I'm fine with rand not having a notion of an OS RNG). Also my crate does not exercise any code paths in the wasm compiled code that uses rand_os. However it gets compiled regardless because criterion is a dev-dependency, so cargo not separating features across different dependency kinds or targets is a big problem.
But you could work around this by adding one of the features in your build?
You can't have target specific features with cargo atm, therefore it is impossible to correctly implement failing to compile at the moment.
I'm confused why this can't be done with combinations of cfg(all(...))
/ cfg(all(not(...), ...))
, feature
, target
, and compile_error!
. It seems possible to implement correctly to me, albeit a bit onerous (and also seems like something to this effect is already happening).
The stdweb feature doesn't work as I'm not using cargo web (this wouldn't make sense for my unknown use case):
error: custom attribute panicked
--> C:\Users\Christopher Serr\.cargo\registry\src\github.com-1ecc6299db9ec823\stdweb-0.4.12\src\webcore\macros.rs:32:9
|
32 | #[$crate::private::js_raw_attr]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
::: C:\Users\Christopher Serr\.cargo\registry\src\github.com-1ecc6299db9ec823\stdweb-0.4.12\src\webcore\initialization.rs:20:5
|
20 | stdweb_internal_runtime_initialize!( __js_raw_asm );
| ---------------------------------------------------- in this macro invocation
|
= help: message: you need to use `cargo-web` to compile your project for the `wasm32-unknown-unknown` target
However I just tried the wasm-bindgen feature too and it does seem like it does not conflict with anything the unknown use case needs. So I'm actually fine with that.
I'm confused why this can't be done with combinations of cfg(all(...)) / cfg(all(not(...), ...)), feature, target, and compile_error!.
Cargo propagates features of any cfg combination in the Cargo.toml to all dev-dependencies / (normal-)dependencies and all cfg combinations. They are all in a shared feature space, the cfg'ing or dev-dependency-ing doesn't do anything. This is a bug which is not fixed. Therefore within your actual code your cfg will be against the wrong feature flags, that are actually coming from a different target of a different dependency kind. So here it is the dev-dependency criterion compiled for the host that needs OsRng, but the actual wasm32-unknown-unknown target that your code is targeting doesn't need or want OsRng, but criterion's rand/std feature gets propagated to rand regardless and thus OsRng gets compiled in, even though it's only needed in the dev-dependency on the host (x86, not wasm).
I'd prefer if ThreadRng
remained cryptographic, so I'm now more curious about insecurities in the fallback to JitterRng
. I suppose ThreadRng: CryptoRng
could become platform dependent though?
I've no opinion on rand_os
being a separate crate, but reverting that decision sounds doable. I love combining all this mess into one crate regardless, so I'd say throw JitterRng
, EntropyRng
, etc. all into rand_os
even if not required. OsRng
would never call JitterRng
of course, but JitterRng
exists due to OS shortcomings, so rand_os
makes sense. Anyone writing an OS PRNG could reuse this code inside their OS by providing a different build target for the kernel itself.
I think runtime failures sound perfectly acceptable here too. impl RngCore for OsRng
could just call debug_assert_eq!(true,false,"OsRng unavailable!");
everywhere. It triggers in debug builds and CI only if you use OsRng
. I'm curious though if pub type OsRng = !;
or pub enum OsRng {}
provides a compile time solution, preferably omitting OsRng: RngCore
or OsRng: CryptoRng
in those cases.
IIRC jitter fallback is only needed for Windows. One option will be to incorporate it into Windows OS RNG implementation inside rand_os
(feature gated maybe?). This way we can remove EntropyRng
altogether and use OsRng
directly.
I'm now more curious about insecurities in the fallback to JitterRng
In my understanding JitterRng should be cryptographically secure, the main issue with it is its performance. Citing JitterRng
docs:
A consequence is that it is orders of magnitude slower than
OsRng
and PRNGs (about 103..106 slower).
Interesting point about JitterRng
only being needed for Windows. We added it because of one observed problem, though don't know in general how widely useful it is — certainly, most of the time it will not be used.
We could put it behind a feature gate which is disabled by default — most people won't notice the difference, and those that do can consider enabling it.
I'd prefer if ThreadRng remained cryptographic
It will — at the very least we will avoid known security problems and only use things we have reason to believe are secure. Whether or not this meets your standards of security is another matter; currently we don't have formal standards and I don't really want to go there.
Before we get too carried away (#685) we should discuss what we actually want. One possible option, compatible with @vks's "rand is just a shim" goal, is:
rand_os
for nowrand_entropy
containing JitterRng
, EntropyRng
and FromEntropy
rand_os
crate and add OsRng
(as a simple wrapper around the std
function) into rand_entropy
Rationale:
OsRng
and no more; this lets them keep thatrand_entropy
our "get your entropy from here!" crate for users wanting seeding/random bytes without the rest of rand
JitterRng
is really just a backup option which may not always be compiled in anyway; it doesn't really need to be promoted to its own crateLimitation:
JitterRng
but with a custom nanosecond timer, and use that in EntropyRng
, it might be more difficult — though this isn't necessarily a problem (we need some configuration to enable no_std
sources anyway)add rand_entropy containing JitterRng, EntropyRng and FromEntropy
What is a rationale for having EntropyRng
assuming rand_os
will incorporate feature-gated JitterRng
fallback for windows? Why can't we seed RNGs directly from OsRng
?
if we are ever successful with the RFC in #648, we can deprecate the rand_os crate and add OsRng (as a simple wrapper around the std function) into rand_entropy
If we'll get getrandom
-like funciton into std
, we will still need rand_os
to implement rand_core
traits, I highly doubt we will get RngCore
into std. Though rand_os
will become much-much thinner, as most of the complexity will move into std
.
JitterRng is really just a backup option which may not always be compiled in anyway; it doesn't really need to be promoted to its own crate
I disagree. JitterRng
is quite self-contained and fits into a separate crate really nicely, someone may want to use it independently, e.g. for bare-metal targets. Also in my opinion having it as a optional dependency will be nicer and more explicit compared to a feature gated module.
What is a rationale for having EntropyRng assuming rand_os will incorporate feature-gated JitterRng fallback for windows? Why can't we seed RNGs directly from OsRng?
But why do we want to roll the fall-back into the same RNG? It's not simply a wrapper around the OS RNG any more. Same goes for embedded device-specific RNGs and RDRAND
— which implies we might want to change how the recent SGX implementation works.
As I said already, I'd prefer to keep JitterRng
generally-applicable but put it behind a feature-gate if not everyone wants it.
someone may want to use it independently
This is already possible. The entire reason EntropyRng
exists is to allow a flexible cross-platform entropy source, even where there is no OS (and OsRng
). We're not there yet, but it should be possible to achieve that by plugging in a high-resolution timer or an external RNG, or even with a local entropy collector/pool. But that is #579.
However, I guess it still works nicely as a separate crate, though with the number of crates we're collecting I'm wondering again about using multiple repos (core / entropy stuff / rngs / sampling).
I think the cleanest solution would be (1), but @tarcieri @naftulikay I understand there would be resistance to moving JitterRng into rand_os. Is this really justified? I guess in part this depends on whether the RFC proposed in #648 gets accepted, though this will be a while coming.
Failing at compile time (i.e. solution 1) is ideal IMHO. I think that the important thing to me is that it should always be very clear if a RNG is not a CSPRNG. The other issue and RFC into std
(and core
?) makes the only RNG exposed by the language be the system CSPRNG.
I don't know what the right balance is here, but I agree with many of the sentiments expressed above:
OsRng
should use the system CSPRNG.CryptoRng: Rng
or SecureRng: Rng
marker trait could be used to indicate at the type level that it's secure or insecure. APIs could thus fn gen_rsa<T: CryptoRng>(rng: T) -> Result<Vec<u8>>
.impl InsecureRng for T where T: !SecureRng
, maybe.OsRng
should be available anywhere that std
is available, including WASM via JavaScript's Crypto extensions to access the system CSPRNG via std::random::secure_random
or whatever the RFC finally decides on.As much as possible, fail at compile time and leverage the type system to make secure/insecure RNGs as obvious as can be. CryptoRng
/SecureRng
should probably be defined in rand
proper and implemented in rand_os
, etc.
@naftulikay:
CryptoRng
CryptoRng
is an independent trait, not an extension trait, hence you need T: CryptoRng + Rng
, although because Rust does not yet have multi-trait objects you cannot write &mut dyn CryptoRng + Rng
T: !SecureRng
is not possible; also there is a considerable grey area between "secure" and "known insecure"std
features, it just pretends to! Seriously, the hash-randomisation in std
just uses a fixed seed on WASM currently, and I don't believe "having a system random generator" is a big factor in whether the Rust team decide a target "supports std" or not. (And in practice, in this case, we require one of two dependencies to support OsRng
on WASM which are incompatible and thus we cannot force on the user.)BTW, do check out the rand_core
API.
The entire reason EntropyRng exists is to allow a flexible cross-platform entropy source, even where there is no OS (and OsRng). We're not there yet <..>
Ah, I was judging by the current state of things. I don't see a good way of enabling overwritable EntropyRng
except hacks with mutable global statics, so I have bigger hopes for getrandom
lang item, which I believe will cover most of the planned functionality for EntropyRng
, i.e. instead of redefining EntropyRng
you will redefine lang item with your source, this lang item will be used by OsRng
wrapper (it will not be strictly speaking "OS" anymore, but well...), which in turn will be used to seed local high-performance RNGs.
I'm wondering again about using multiple repos (core / entropy stuff / rngs / sampling).
I told ya. ;)
As for WASM and std
, I think it's an unfortunate limitation of how currently Rust std works. In my understanding wasm32-unknown-unknown
only can do allocations and not a single "OS stuff". I believe we need wasm32-web-unknown
and wasm32-node-unknown
targets (see the linked issue), and rand
should disable wasm32-unknown-unknown
support in future after we will get those targets.
CryptoRng is an independent trait
BTW can you please remind the rationale for it?
I donno. It's defined in rand_core
, and only rarely used with Rng
minus RngCore
, so if it were an extension trait then it'd be an extension trait of only RngCore
. We still see Rng + CryptoRng
occasionally when you need more advanced sampling form cryptographic distributions, mostly in lattice based cryptography, multi-party computations, and consensus algorithms.
I think readability dictates that OsRng
, JitterRng
, and EntropyRng
all belong together inside one crate. If this crate is not rand
itself, then rand_os
is a fine name. In this case, rand
might only export OsRng
so that rand_os
documentation gets read together.
There is a case that ThreadRng
belongs inside this crate too, but I think placing ReseedingRng
got painful, so maybe not.
We still have the question of whether JitterRng
will remain enabled as a fall-back normally (as it currently is), or only if explicitly enabled (or on certain platforms). In the latter case it makes more sense that it's an external crate.
We already mentioned that it may be used to implement OsRng
, and for this it's probably cleaner having it as a separate crate (though that isn't the only possibility — there could just be an option to specify an extern(C)
function with a high-resolution timer and a feature flag to enable it).
@dhardy I'm gonna shut up now, lol, and make sure that I'm familiar with the API before commenting further. Apologies, I should have done my homework before weighing in.
BTW can you please remind the rationale for it?
See the last line of rand_core::block
:
impl<R: BlockRngCore + CryptoRng> CryptoRng for BlockRng<R> {}
A BlockRngCore
is not in fact an Rng
/ RngCore
, yet is a CryptoRng
. Perhaps this is wrong; though I'm not sure if it's worth changing (it would mean breakage). Implementing the same logic would otherwise require yet another trait:
impl<R: CryptoBlockRngCore> CryptoRng for BlockRng<R> {}
... but it's probably better just to let crates like rand_chacha
implement CryptoRng
directly.
Well, I agree with @burdges that placing OsRng
and EntropyRng
in the same crate makes sense; this implies that crate must include or depend on JitterRng
.
On the other hand, we haven't resolved how EntropyRng
will allow user provision (#579), which implies breakage may occur, and if EntropyRng
is no longer in the main crate this would require bumping two version numbers in unison (not really a problem but annoying).
I would definitely not but ThreadRng
into the same crate however; it depends on much more code (could be its own crate but little motivation and another topic).
Conclusion: none of this really has an impact on whether we have a separate rand_jitter
crate or not.
Cool. Afaik, there is no real reason for the rand_os
crate to be separate from rand
, but likely no harm either so long as the documentation for "os-like csprngs" can be kept in one place. I'd keep jitter with them myself.
@burdges rand
presently pulls in a zoo of exotic "legacy crypto" CSPRNGs, e.g. ISAAC.
A rand_os
crate provides a clean and explicit separation for users who truly just do want a well-vetted platform-specific RNG.
Personally I would prefer not to have any "legacy crypto" crates in my project whatsoever. "It's the only way to be sure!"
I generally disagree with extremist POVs... maybe there's a more tactful way of expressing your intent? What do you mean by "legacy crypto", besides ISAAC?
ISAAC will no longer be included in Rand once we remove the deprecations (probably in 0.7).
I think poor documentation sounds like the biggest threat @tarcieri and micro-crates almost always make documentation worse for interlocking components, ala ReseedingRng
or EntropyRng
.
As a rule, I think CSPRNG algorithms like ISAAC or ChaCha mostly present documentation acceptably when done as individual crates, so not worried there. In more detail, there is a minor documentation improvement in placing the CSPRNG algorithms side-by-side, and a legacy_crypto
feature would be infinitely more effective at discouraging their use, but the audience for that improvement is protocol designers, not developers, and protocol designers should read many things besides the crate documentation. In short, I think algorithm crates work because I'm not extremist in my anti-legacy views. ;)
In this case, our distinction runs like:
OsRng
, EntropyRng
, and JitterRng
that belong inside a crate together because developers inherently choose among them, not protocol designers, and the developer documentation must present OS level randomness concerns cohesively, including warnings for jitter, windows, etc.ReseedingRng
and ThreadRng
that combine this OS level randomness discussion with the CSPRNG algorithm discussion. I think rand simply imposes some fairly conservative choice in ThreadRng
and via generic impl for CryptoRng
.I think poor documentation sounds like the biggest threat
I don't see any critical problems with documentation which can not be solved.
We've several OS-like randomness tools OsRng, EntropyRng, and JitterRng that belong inside a crate together
I strongly disagree here. JitterRng
is a perfectly stand-alone algorithm which can be used independently from OS.
As for EntropyRng
I believe in future it should be deprecated in favour of overwritable getrandom
lang-item, and currently rand_os
is already complex enough to burden it with an additional EntropyRng
code. So a conservative solution will be to leave it in rand
for the time being.
AFAIK the main reason for EntropyRng
introduction was OS RNG failures on Windows. Now we want to make it overwritable "default" randomness source, but it's still WIP and I am not sure if there is a good solution for it, and again I think it's better solved by the lang-item.
I generally disagree with extremist POVs... maybe there's a more tactful way of expressing your intent? What do you mean by "legacy crypto", besides ISAAC?
I brought this sort of thing up on #648 already, but when you pull in rand
today you get:
Okay, so we have one '90s cipher (ISAAC), a member of the venerable eSTREAM portfolio, a descendent of a member of the eSTREAM portfolio which is now widely deployed in IETF protocols, and two non-cryptographic RNGs.
The exact vintage of the cryptography, though, is a bit of a red herring, because really I don't want any userspace CSPRNGs in my project. So yes, while this is 3 stream ciphers, two of which are fairly obscure, and two non-cryptographic RNGs, all I want is rand_os
(thanks for the work on this, btw!)
@tarcieri rand_xorshift
, rand_chacha
and rand_isaac
are all deprecated as dependencies of Rand which will reduce that number significantly. All the same it might make sense to apply more modularisation, and for now I think it's worth keeping rand_os
as-is (at least until we've resolved #648).
@tarcieri and all: I wonder if an RNG (implementing RngCore
) is really want we want here, and if we shouldn't just have a simple "fill buffer" function in rand_os
? This is roughly what #648 is proposing except not within std
. The other parts of RNGs (next integer, seeding) are not applicable here (or in an extension providing a backup source).
In other words: perhaps we should build a simple "getrandom" crate, then discuss including that within std
(or making std
depend on it).
@newpavlov if we make a "getrandom" function (filling a buffer), then there are three possibilities:
std
platform (I've only seen that one report of problems)EntropyRng
; this is the simpler option and might use our JitterRng
as-is, but overall seems sub-optimalJitterRng
in its current formBecause of this I think moving JitterRng
to a new crate now is premature, and suggest we close that PR for now.
perhaps we should build a simple "getrandom" crate
Hm, it may be worth to do it. I don't have any objections to this idea. Also having an implementation may help with the RFC acceptance.
if we make a "getrandom" function (filling a buffer), then there are three possibilities:
Until we will get getrandom
into std I think we should have an optional Jitter fallback for OS RNG. IIRC the Windows issue came from Servo developers and solution for it is a must have for Firefox to work reliably. (though it certainly worth to check with them and ask their opinion on this issue) So I would prefer to incorporate Jitter fallback as a disabled by default feature-gated functionality directly into rand_os
.
I think that in the current form EntropyRng
is redundant and can be deprecated. (and the envisioned future form will be covered by the overwritable lang-item)
Good. I suggest we start with a new repository under https://github.com/rust-random since this will not be dependent on any part of rand
(besides the moved code). Any good ideas for the crate name? getrandom
, secure-random
, random-bytes
, system-random
, os-random
, ...
I was wondering if rather than try to get this functionality included in std
we could go the other way and make std
depend on it — but it I don't think that's possible because several OSes require std::io::Read
which is not available in core
. So it's either duplicate or getting merged into std
. Even so starting as an independent crate seems sensible, and no_std
support could remain in the external crate (rather than via core
and lang-items) — we should probably make this an option in our RFC.
I really think the jitter stuff belongs there if we want it, rather than as an RNG. Yes, that module is currently 882 lines, but a large portion of that is documentation and error handling. libstd
alone currently weighs in at over 100'000 lines so I don't think including the jitter code for std::random::secure_random
is a big deal if we decide we want it there.
The second point of this is to step back and look at what Rand is — it is about PRNGs, conversions of values to other Rust types, numeric distributions and random algorithms. Beyond OsRng
and JitterRng
, none of the rest of this code requires error handling, so potentially we can remove error types and try_fill_bytes
from rand_core
, and maybe even give rand_core
an optional dependency on getrandom
for seeding.
Thus we can have getrandom
for cryptographic libs and other low-level usage, and the rand
* crates for higher-level random number stuff.
(The one issue I see here is that CSPRNGs like ChaCha may be used both by crypto libs and as PRNGs within Rand. Perhaps we can move the core algorithms to a pure-crypto lib, then build rand_chacha
etc. as wrappers around this core, via the existing rand_core::block
code.)
I personally like getrandom
name. The crate will have to be mostly std
-dependable (except SGX rdrand
-based back-end and always erroring fallback). I am not sure how exactly it should be incorporated into std, so let's leave it for RFC discussion.
I really think the jitter stuff belongs there if we want it, rather than as an RNG.
No, I think it certainly shouldn't be a part of getrandom
(or whatever it will be named) crate. The idea is that in future users will be able to overwrite getrandom
function definition at application level if needed, e.g. by using function with Jitter fallback.
Overall I don't quite understand the reluctance toward splitting Jitter RNG into its own crate. It's a self-contained algorithm, and however we will use it in future, a separate crate will not result in any substantial amount of harm, while being easier to add, move or remove.
The second point of this is to step back and look at what Rand is
Thus we can have getrandom for cryptographic libs and other low-level usage, and the rand* crates for higher-level random number stuff.
I believe we will still need RngCore::try_fill_bytes
and CryptoRng
even after introduction of getrandom
(as a separate crate or in the std). Don't forget that crypto crates can be generic over RNGs. For example some may use ThreadRng
to speed-up key generation, or use a PRNG for deterministic testing. So I am mostly happy with the current rand_core
. (well, except the block part)
The one issue I see here is that CSPRNGs like ChaCha may be used both by crypto libs and as PRNGs
I hope in future we will use a single ChaCha
implementation for both PRNG and stream cipher. So rand_core::block
can be moved into RustCrypto/utils.
The idea is that in future users will be able to overwrite getrandom function definition at application level if needed, e.g. by using function with Jitter fallback.
You're now saying you don't think the jitter fallback should be used on Windows by default, but somehow applications which might need it should enable the fallback, and do so by overwriting the secure_random
function they want to use as their default random source?
My reluctance is that I am not convinced we will want to keep JitterRng
as an RNG; if it is used to implement secure_random
then only a byte-filling-function is required.
Additionally, I'm not sure whether we should make applications provide a timer to JitterRng
then provide that to implement secure_random
on certain no_std
platforms, or include the jitter code and simply make the application specify the timer.
Don't forget that crypto crates can be generic over RNGs.
You point me to an example using only fill_bytes
, which could use a simpler trait, and I wonder if this should example should panic on error? However, having only a single RngCore
trait to implement for RNGs certainly makes it easier to share CSPRNG code.
I'd be all for a getrandom
crate, particularly if it were free of JitterRng
fallback. Perhaps rand_os
could wrap getrandom
and handle the JitterRng
fallback?
Concretely I'd only want the existing OS random functions (getrandom
on Linux, RtlGenRandom
or BCryptGenRandom
on Windows, "safe" arc4random
etc), and RDRAND on SGX targets, with no fallbacks like JitterRng
.
Speaking of RDRAND, it seems like that would be preferable to falling back to JitterRng
if available, unless there are performance concerns.
Also am I the only one who finds the idea of JitterRng
scary in the age of microarchitectural covert channels?
falling back to JitterRng if available, unless there are performance concerns.
Have you any idea how slow JitterRng
is?
@tarcieri I am not well versed in side-channel attacks, and don't know where to start answering such a question, aside from the obvious: some type of local hardware or software bug needs to be present, and if that can already read your memory then everything is vulnerable. How practical it is to guess the output of a generator based on nano-second jitter I don't know, but you are right that we shouldn't fully trust it, and RDRAND is likely preferable (that may also not be fully trusted, but if you don't trust your CPU then secure entropy sources aren't your only problem).
We now have a slight architectural problem though because @nagisa's RDRAND implementation is dependent on rand_core
but we are now discussing using it from a lower-level getrandom
crate not dependent rand_core
.
@dhardy an example of a potential attack vector is attacker-controlled JavaScript running cotenant on the same CPU as a Rust program.
As we saw last year, covert channels are exploitable from web browsers.
So the question for JitterRng
to truly be a CryptoRng
, in my opinion, is: can an attacker-controlled cotenant program, such as an attacker-controlled JavaScript running in the same browser, either learn anything about or influence JitterRng
's output?
@tarcieri
I think that it's highly unlikely that such attack is practical, as there is just too much stuff happens on a machine constantly at the same time which influence timings in unpredictable ways, and if you'll add an additional load timings will just become less predictable. Though I have vague concerns regarding simplicity of the whitening scheme used in JitterRng
, to be safe I would prefer to see something like k12 to consume timings and emit entropy, it could even help with the performance issues a bit if we'll take a less conservative stance on the amount of required "true" entropy.
@dhardy
My reluctance is that I am not convinced we will want to keep JitterRng as an RNG;
We can make rand_core
an optional dependency for JitterRng
, i.e. RngCore
implementation will be feature gated (but probably enabled by default). The same goes for rdrand
.
You point me to an example using only fill_bytes, which could use a simpler trait, and I wonder if this should example should panic on error?
In the linked case it will panic, which seems is not a problem for dalek developers. But some of the crypto crate developers (e.g. @briansmith and @ctz IIUC) prefer to expose every potential error even if it's highly unlikely. And I don't think that try_fill_bytes
takes too much space, considering that it does not get exposed in higher-level code.
Have you any idea how slow JitterRng is?
I know next to nothing about the current JitterRng
implementation, apologies. I can learn, but my goal is to avoid it.
RDRAND implementation is dependent on
rand_core
but we are now discussing using it from a lower-level getrandom crate not dependentrand_core
.
Perhaps it should be moved to getrandom
as well?
I think that it's highly unlikely that such attack is practical
I'd prefer it be a guarantee as opposed to a best guess. A more concrete question to ask is: is the current TRNG algorithm designed to be sidechannel resistant?
A quick search for papers on this topic pulls up:
It seems provable sidechannel resistance for TRNGs is a thing.
@tarcieri JitterRng
uses the high-resolution part of nano-second timers. As far as I can tell, JavaScript cannot even access nanosecond timers in the browser. And as @newpavlov says, if it adds extra delays to "manipulate" the output, it will not make the output any easier to predict.
Your first article on GAROs sounds like it is observational rather than a definitive proof? I didn't read the whole article.
@newpavlov probably we should have an issue on JitterRng
improvements; this isn't the first suggestion I've seen (the other relating to sources of timing delta entropy).
Summary: JitterRng
is very likely secure vs JavaScript side-channel attacks. It could have some improvements (at least regarding performance) and ought to have a security review.
But as to what to do, it might still be best not to use a jitter-based-rng in our getrandom
crate, but instead use RDRAND as a backup option. Should this be enabled by default on all supported targets?
We can make rand_core an optional dependency for JitterRng, i.e. RngCore implementation will be feature gated (but probably enabled by default). The same goes for rdrand.
This prevents us from making rand_core
depend (optionally) on getrandom
, which would be nice: we could move the from_entropy
method into SeedableRng
.
I made a separate issue for JitterRng
if you'd like to continue the discussion there: https://github.com/rust-random/rand/issues/699
@newpavlov I think this means we should either delete JitterRng
or move it to a new repository, however we may as well migrate away from using it before removing the code from rand
. That means closing #685, though if you like I can make a new repo for that code (jitter_rng
or rand_jitter
).
Ideally I'd like another backup source in place before removing it however.
I don't mind moving rand_jitter
into a separate repository, but do you plan to publish rand v0.7
? Because JitterRng
is a part of public API. I highly doubt anyone has used it directly, but still strictly speaking removing it for v0.6 will be breakage of compatibility promise. So I think it will be better to merge #685 and decide its fate later in #699. I don't think we need two versions of JitterRng
, one in the separate repo, and one as part of rand
.
Agreed, we shouldn't remove it before 0.7, and even then we might want a deprecation warning.
Fair point, the crate name doesn't need to change, so there's no reason we can't merge #685 now.
I think the time has come to close this thread. It has several progeny:
rand_jitter
(#685)The continuation of the remainder of this discussion can move to #760.
Roughly, rand could be modularised as follows:
rand_core
rand_os
JitterRng
EntropyRng
ThreadRng
seq
distributions
Rng
Roughly 30% of the current code comes under non-linear distributions, which is its own story (#290). For the rest I don't think there's sufficient utility for more crates.
I regret accepting #643 as-is; it "promises" to support all
std
platforms yet fails on WASM with a compile error (#674, #678) and on any unsupported platforms. The reasons that is an issue are convoluted (probably involving users depending onrand
with default features yet not needing them all), but the conclusion of #678 is that Rand should always build forwasm32-unknown-unknown
, failing if necessary at run-time.We used to use run-time failure within
EntropyRng
but disableOsRng
at compile time where unneeded. Practical solutions are:rand_os
must compile but without theOsRng
struct on unsupported platforms.EntropyRng
is currently available on all platforms but with run-time failure when no source is available, however it requires a complexcfg
pattern in order to disable the missingOsRng
dependency when not available; it would therefore make sense to have this in the same crate.OsRng
on WASM, and use run-time failure on missing implementation.OsRng
on all platforms, and use run-time failure on missing implementation.I think the cleanest solution would be (1), but @tarcieri @naftulikay I understand there would be resistance to moving
JitterRng
intorand_os
. Is this really justified? I guess in part this depends on whether the RFC proposed in #648 gets accepted, though this will be a while coming.Otherwise we can do (2) or (3); the difference is that (2) would cause build failures on any platform where Rand is used with
std
/default features butOsRng
is unavailable. I'm not sure whether this is a good idea?I suppose (2) is most sensible now.
CC @newpavlov @burdges