-
Notifications
You must be signed in to change notification settings - Fork 13.3k
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
Tracking Issue for secure random data generation in std
#130703
Comments
Disclaimer: I am one of the I think it's important for It may be worth to add the following methods to
It's also not clear whether it's allowed to overwrite the default |
Would you consider rust-lang/libs-team#159 to be a better solution? That one used the |
No, I don't think it's an appropriate solution. Firstly, it relies on For the last point I guess we could define a separate |
I don't think this needs to be a blocker. IMO a lot of |
Would it be better to make this explicit with generics? Like |
I (mostly) disagree. CSPRNGs should almost never fail. When they do, users are almost never qualified to diagnose the problem. For example: golang/go#66821 A compromise is something like this: trait RandomSource {
type Error;
fn fill_bytes(...) {
self.try_fill_bytes(...).unwrap();
}
fn try_fill_bytes(...) -> Result<..., Self::Error>
} This allows most CSPRNGs to use |
@ericlagergren As for design of fallible RNG traits, see the new |
This trait (and the topic of random value generation) should be removed from this discussion entirely in my opinion, focussing only on "secure random data generation" as in the title. Why: because (1) provision of secure random data is an important topic by itself (with many users only wanting a byte slice and with methods like Disclaimer: I am one of the |
Overriding the default source in an application that already has one from linking If overriding the
This wouldn't be a problem if the entire ecosystem could agree to always delegate this problem to on one specific crate (version) with appropriate hooks, like Edit: almost forgot that even |
There is a number of reasons to allow overriding:
Yes. How about following the Either way, overriding is probably can be left for later. I think we both agree that we need a way to expose "system" entropy source in
I agree that ideally we need a unified approach for this kind of problem. I made a similar proposal once upon a time. But I think it fits fine? Targets with
I believe that having
Well, it has happened, sort of. The problem is that
Can we add yet another sysroot crate for |
The RFC (and the competing ones I've looked at) only supports a default implementation in the crate that "declares" the externally-implementable thing. If that crate isn't
I was specifically talking about
Not to point any fingers but a counter example that's fresh on my mind because I looked at its code recently is foldhash. As another example,
Possibly, but people may object to a proliferation of sysroot crates so let's hope there's a better solution. |
Yes, it's not as if RFC is a technical specification which must be followed word-by-word. There is a number of cases where the original RFC vision has somewhat changed during implementation stages. If anything, I would say it's an oversight/deficiency of the RFC to not cover cases like this.
If a crate aims to minimize its number of dependencies as far as possible even at the cost of code quality and security, it obviously will not depend on |
As I said, I have no intention of pointing fingers at any crates. They have to navigate tricky trade-offs and complexities due to Rust's standard library (as a whole, not just |
The Random trait seems weakly motivated in terms of coupling it to RandomSource, as its design seems like it will be a much more hotly contested space, and it is (mostly) unrelated to RandomSource. |
Note that @dhardy (maintainer of rand) wrote some criticism of this at rust-lang/libs-team#393 (comment) |
Could let random_array: [u64; 100] = random(); which is a lot more convenient than using the |
I think it would be useful to have a data type like |
I disagree that it is useful in testing implementations of traits like |
As far as I know there’s no plan to make the |
It seems like one might regret adding For more complicated types (e.g., It seems better to leave this out rather than leave it in this poorly specified state. Just stabilize Although... even |
I really don't think so. The current interface works perfectly fine, it's just slightly suboptimal in some use cases (fewer than in the context of general byte-centric I/O). Providing only a So I think it's pretty clear that the method for filling a |
Perhaps something like this would work: // Users don't need to concern themselves with this type.
pub strut OutBuf([MaybeUninit<u8>]);
impl OutBuf {
// various methods to construct it and write to it, no method to read from it
}
// Users don't need to worry about implementing this, just use it
pub unsafe trait AsOutBuf {
type Init: ?Sized;
fn as_out_buf(&mut self) -> &mut OutBuf;
// Only allowed if the entire buffer was overwritten.
unsafe fn assume_init(&mut self) -> &mut Self::Init;
}
impl AsOutBuf for [u8] { type Init = [u8]; ... }
impl AsOutBuf for [MaybeUninit<u8>] { type Init = [u8]; ... }
impl<const N: usize> AsOutBuf for [u8; N] { type Init = [u8; N]; ... }
impl<const N: usize> AsOutBuf for [MaybeUninit<u8>; N] { type Init = [u8; N]; ... }
// Users can pass in any byte slice, byte array or their uninitialized counterparts
// The entire value is guaranteed to get overwritten, so if using the returned value is undesirable due to borrowing issues the users can simply use the original value safely, if it was an initialized type to begin with or they may just soundly call `assume_init` on it.
pub fn fill_random_bytes<T: AsOutBuf>(buf: &mut T) -> &mut T::Init { ... } This way it already supports all reasonable cases and people are not forced into using uninitialized API. They can write |
That helps the simple call sites remain simple, but it has several downsides:
|
Yes, this is why it's important to decide whether we plan to add
Note that I intentionally used |
The different traits work great for APIs that take an RNG as an argument. But there's also plenty of usecases for things like "I would like 16 random bytes please", and for those it can be relatively easy to mix up a CSPRNG vs. a non-CSPRNG. |
Keep it simple, leave out You can always add it later if it really becomes important (i.e., to make it easier for non- |
The scope is what I would like to see: an interface suitable for initializing a CSPRNG, rendering the I agree with @newpavlov: |
No one says it should be stabilized together with And it's pretty easy to specify in my opinion: "reasonable" effort randomness source which may emit predictable random numbers in the worst case scenario, to the point of using PRNG seeded with a fixed seed (e.g. on WASM targets). I would say we have a bigger issue with |
This was discussed before, see #130703 (comment) and surrounding comments -- it affects many other std APIs on various targets besides wasm and is generally handled by panicking or returning an error. This tracking issue is really getting far too long, even the people who have been involved in it the entire time are going in circles because it's become so unwieldy 🙃 |
I might be biased but @newpavlov I don't get what's the deal with WASM. It's not OS/hardware, so it shouldn't even have |
This issue is for secure random data generation: reading bytes directly from the system's CSPRNG. Everything else should happen in a separate issue. |
I agree, but the unfortunate reality is that Rust does provide Imagine a function/method like |
Libraries that don’t require |
I think that is the best thing to do. The real issue is that we haven't deprecated the wasm32-unknown-unknown target yet; it is inevitable, but not everybody sees it yet. wasm32-unknown-unknown stuff shouldn't block progress on this. |
I don't see any reason to not deprecate it at least and provide more sensible alternative. "does not work on Being unavailable on
Well, minimizing WASM module size by getting rid of |
Seconded. All I want is something like io::read_entropy as an alternative to the getrandom crate. Does the libs team need to accept an ACP first or should someone presumptuously make an issue so we can move discussion there? |
We discussed this at length in today's @rust-lang/libs-api meeting. We didn't come to any final conclusions, but here's a summary of the discussion: We were generally amenable to the idea of exposing low-level randomness in the style of We felt that that was an independent decision, separate from the higher-level interfaces in the style of We discussed whether the low-level method being requested here is effectively the existing In discussing the possible differences, we talked about whether We did agree that, if we want to expose the IO error, we should do so by having Everyone present in the meeting was generally in favor of exposing the IO error, and doing so by having Summary:
|
@joshtriplett Implementing
Also: is |
This looks really bad for the potential future move of this trait to |
Another (smaller) issue with reusing
Any effort spent flagging this and either rewriting it with |
Chiming in to note that
I guess the question is whether the standard library should try to account for this, or just count it as a failure. |
@abgros I don't see a practical reason to expose a |
I certainly hope not. I would expect the handling of any such error to be a graceful exit, and the only reason to expose it rather than panicking is the ability to handle it gracefully.
I would not in general expect such errors to be recoverable.
|
If we're going to expose errors from the OS, the obvious type for that would be If we decide to panic, or use a different error type, then I agree that we can't use
We could absolutely do that, but the question is what we should do about error handling, if anything. If we use |
That's a valid point. |
The obvious approach is to use the Somewhat tangential rant: I believe that It covers two very distinct cases: "error code from OS" and "any error under the sun abstracted by Yes, we need some limited extendability for things like Making |
I don't think that's obvious, and it has disadvantages: code that's generic over
I agree with you completely, and that's a substantial problem. In the absence of that boxed variant, |
Judging by the Cryptographic code is a bit different in this regard since it's more common to use |
Is that really true? I had assumed, perhaps incorrectly, that But Is there anything else in Related, when people talk about having Because if it's the former then, again, I don't understand what |
Unfortunately, users do fall back to insecure sources of randomness. :/
If there is going to be a My goal here is just to make sure these new APIs are misuse resistant. |
(Note: further discussion on this would be off topic for this tracking issue; for that, I'd suggest
Teasing apart the parts of
I would not expect |
@jstarks
The idea is to start with the former and maybe move to the latter in future (in a separate sysroot crate). IIUC the main blocker for the latter is lack of a unified way to handle Having the randomness trait defined in |
Feature gate:
#![feature(random)]
This is a tracking issue for secure random data generation support in
std
.Central to this feature are the
Random
andRandomSource
traits insidecore::random
. TheRandom
trait defines a method to create a new random value of the implementing type from random bytes generated by aRandomSource
.std
also exposes the platform's secure random number generator via theDefaultRandomSource
type which can be conveniently access via therandom::random
function.Public API
Steps / History
random
feature (alternative version) #129201Unresolved Questions
gen_bytes
andDefaultRng
, the implementation PR usesfill_bytes
andDefaultRandomSource
(see arguments progen_bytes
and profill_bytes
)Footnotes
https://std-dev-guide.rust-lang.org/feature-lifecycle/stabilization.html ↩
The text was updated successfully, but these errors were encountered: