-
Notifications
You must be signed in to change notification settings - Fork 13.2k
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 not 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:
|
As noted above, panicking or returning an error on unsupported functionality in The WASI/WASM case is yet another argument why we need to introduce an "insecure" randomness source. We can mandate that this source may use PRNG seeded with a fixed seed on platforms which do not provide proper system randomness. |
This seems okay for general use but I think it could actually be very dangerous. If I'm given an uninitialized buffer: let mut buf = [MaybeUninit::<u8>::uninit(); 100]; I might be tempted to convert it to a let slice = unsafe {
std::slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u8, buf.len())
};
read_random(slice); Unfortunately, calling I would recommend changing the signature to: fn read_random(bytes: &mut [MaybeUninit<u8>]); and also adding a guarantee that if this function succeeds, all the bytes in the slice will have been initialized (i.e. calling EDIT: upon further discussion this might be a good use case for BorrowedBuf? |
Requiring every caller to write a bit of I don’t find your new argument very convincing: casting an uninitialized slice to |
What if we make the
// core::marker
// Possibly as a language item:
pub /* unsafe */ trait FromBytes { } // Or with some other name...
// std::io
pub fn read_random<T: FromBytes>(buf: &mut T); We could then add an extra promise that the buffer referenced by (edit: I would personally prefer the name |
To be fair, it seems like many people here are overtly hostile to the "common uses", e.g. see above
But since every low-level OS API that I'm familiar with takes in a pointer and a length, it might be wise to have a lower-level function giving you direct access to it and avoiding any overhead or abstraction like: pub unsafe fn read_bytes_raw(dst: *mut u8, len: usize); and then also have higher-level APIs covering plenty of common stuff like generating numbers or vectors which don't require using
It seems like your proposed |
I would argue that it is different in that my proposal would randomise the raw representation of the buffer – regardless of how this effects its effective value (whereas the current |
Well, |
Hey, T-libs-api! How do you feel about reducing the scope of this feature to the following API:
@rustbot label +I-libs-api-nominated |
In my opinion, this function should not be defined in the UPD: It seems we already have the |
Many people were not happy with the idea of a strong entropy source sharing a module with high level random traits and (potentially) weaker random functions. The first may be used for cryptographic purposes but the later must not. |
It's a weird argument in my opinion. Where else should items related to RNG live if not in a module named Applicability for cryptographic applications should be resolved by a |
The exact path (module, name) seems less important than the question raised about scope of the feature. |
I agree with the limited scope, i.e. starting with a relatively simple potentially panicking function with |
I think that makes sense, but only if we want to add other randomness functions in the future (otherwise it'd be a module with just one function). As I'm arguing that |
I'm not at all opposed, but I'd prefer to defer that discussion. |
(👋, I maintain the Python cryptography library, in addition to the Rust stuff I do) I think the specific anti-pattern that we want to avoid is something like |
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? |
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: