From 0a38fcd8123a4d78ef00bde54bdcc96b77878deb Mon Sep 17 00:00:00 2001
From: James Hodgkinson <james@terminaloutcomes.com>
Date: Tue, 22 Apr 2025 14:35:44 +1000
Subject: [PATCH] maint: updating rand and rand_chacha

---
 Cargo.lock                                | 15 +++++++-------
 Cargo.toml                                |  4 ++--
 libs/crypto/src/lib.rs                    | 24 +++++++++++------------
 server/lib/src/credential/totp.rs         |  4 ++--
 server/lib/src/idm/oauth2.rs              | 11 ++++++-----
 server/lib/src/idm/server.rs              |  4 ++--
 server/lib/src/utils.rs                   | 10 +++++-----
 tools/orca/src/error.rs                   |  2 ++
 tools/orca/src/generate.rs                |  8 +++++---
 tools/orca/src/models/basic.rs            |  2 +-
 tools/orca/src/models/latency_measurer.rs |  2 +-
 tools/orca/src/models/read.rs             |  2 +-
 tools/orca/src/models/write.rs            |  2 +-
 tools/orca/src/profile.rs                 |  6 +++---
 tools/orca/src/run.rs                     |  2 +-
 15 files changed, 51 insertions(+), 47 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index c3e9b5b92..a85022924 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3072,7 +3072,7 @@ dependencies = [
  "md-5",
  "openssl",
  "openssl-sys",
- "rand 0.8.5",
+ "rand 0.9.1",
  "serde",
  "sha-crypt",
  "sha2",
@@ -3302,7 +3302,7 @@ dependencies = [
  "num_enum",
  "openssl",
  "openssl-sys",
- "rand 0.8.5",
+ "rand 0.9.1",
  "regex",
  "rusqlite",
  "serde",
@@ -4216,8 +4216,8 @@ dependencies = [
  "kanidm_client",
  "mathru",
  "mimalloc",
- "rand 0.8.5",
- "rand_chacha 0.3.1",
+ "rand 0.9.1",
+ "rand_chacha 0.9.0",
  "serde",
  "serde_json",
  "tokio",
@@ -4602,7 +4602,7 @@ checksum = "b820744eb4dc9b57a3398183639c511b5a26d2ed702cedd3febaa1393caa22cc"
 dependencies = [
  "bytes",
  "getrandom 0.3.2",
- "rand 0.9.0",
+ "rand 0.9.1",
  "ring",
  "rustc-hash 2.1.1",
  "rustls",
@@ -4656,13 +4656,12 @@ dependencies = [
 
 [[package]]
 name = "rand"
-version = "0.9.0"
+version = "0.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
+checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
 dependencies = [
  "rand_chacha 0.9.0",
  "rand_core 0.9.3",
- "zerocopy 0.8.24",
 ]
 
 [[package]]
diff --git a/Cargo.toml b/Cargo.toml
index 9dbaa47c1..6761d8275 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -237,8 +237,8 @@ prctl = "1.0.0"
 proc-macro2 = "1.0.93"
 qrcode = "^0.12.0"
 quote = "1"
-rand = "^0.8.5"
-rand_chacha = "0.3.1"
+rand = "0.9.1"
+rand_chacha = "0.9.0"
 regex = "1.11.0"
 reqwest = { version = "0.12.12", default-features = false, features = [
     "cookies",
diff --git a/libs/crypto/src/lib.rs b/libs/crypto/src/lib.rs
index f95b2ae73..c1417d35b 100644
--- a/libs/crypto/src/lib.rs
+++ b/libs/crypto/src/lib.rs
@@ -834,9 +834,9 @@ impl TryFrom<&str> for Password {
 
 impl Password {
     fn bench_pbkdf2(pbkdf2_cost: usize) -> Option<Duration> {
-        let mut rng = rand::thread_rng();
-        let salt: Vec<u8> = (0..PBKDF2_SALT_LEN).map(|_| rng.gen()).collect();
-        let input: Vec<u8> = (0..PBKDF2_SALT_LEN).map(|_| rng.gen()).collect();
+        let mut rng = rand::rng();
+        let salt: Vec<u8> = (0..PBKDF2_SALT_LEN).map(|_| rng.random()).collect();
+        let input: Vec<u8> = (0..PBKDF2_SALT_LEN).map(|_| rng.random()).collect();
         // This is 512 bits of output
         let mut key: Vec<u8> = (0..PBKDF2_KEY_LEN).map(|_| 0).collect();
 
@@ -855,9 +855,9 @@ impl Password {
     }
 
     fn bench_argon2id(params: Params) -> Option<Duration> {
-        let mut rng = rand::thread_rng();
-        let salt: Vec<u8> = (0..ARGON2_SALT_LEN).map(|_| rng.gen()).collect();
-        let input: Vec<u8> = (0..ARGON2_SALT_LEN).map(|_| rng.gen()).collect();
+        let mut rng = rand::rng();
+        let salt: Vec<u8> = (0..ARGON2_SALT_LEN).map(|_| rng.random()).collect();
+        let input: Vec<u8> = (0..ARGON2_SALT_LEN).map(|_| rng.random()).collect();
         let mut key: Vec<u8> = (0..ARGON2_KEY_LEN).map(|_| 0).collect();
 
         let argon = Argon2::new(Algorithm::Argon2id, Version::V0x13, params);
@@ -873,8 +873,8 @@ impl Password {
 
     pub fn new_pbkdf2(policy: &CryptoPolicy, cleartext: &str) -> Result<Self, CryptoError> {
         let pbkdf2_cost = policy.pbkdf2_cost;
-        let mut rng = rand::thread_rng();
-        let salt: Vec<u8> = (0..PBKDF2_SALT_LEN).map(|_| rng.gen()).collect();
+        let mut rng = rand::rng();
+        let salt: Vec<u8> = (0..PBKDF2_SALT_LEN).map(|_| rng.random()).collect();
         let mut key: Vec<u8> = (0..PBKDF2_KEY_LEN).map(|_| 0).collect();
 
         pbkdf2_hmac(
@@ -897,8 +897,8 @@ impl Password {
 
         let argon = Argon2::new(Algorithm::Argon2id, version, policy.argon2id_params.clone());
 
-        let mut rng = rand::thread_rng();
-        let salt: Vec<u8> = (0..ARGON2_SALT_LEN).map(|_| rng.gen()).collect();
+        let mut rng = rand::rng();
+        let salt: Vec<u8> = (0..ARGON2_SALT_LEN).map(|_| rng.random()).collect();
         let mut key: Vec<u8> = (0..ARGON2_KEY_LEN).map(|_| 0).collect();
 
         argon
@@ -925,8 +925,8 @@ impl Password {
 
         let argon = Argon2::new(Algorithm::Argon2id, version, policy.argon2id_params.clone());
 
-        let mut rng = rand::thread_rng();
-        let salt: Vec<u8> = (0..ARGON2_SALT_LEN).map(|_| rng.gen()).collect();
+        let mut rng = rand::rng();
+        let salt: Vec<u8> = (0..ARGON2_SALT_LEN).map(|_| rng.random()).collect();
         let mut check_key: Vec<u8> = (0..ARGON2_KEY_LEN).map(|_| 0).collect();
 
         argon
diff --git a/server/lib/src/credential/totp.rs b/server/lib/src/credential/totp.rs
index f6ae0fd1e..e887f90e9 100644
--- a/server/lib/src/credential/totp.rs
+++ b/server/lib/src/credential/totp.rs
@@ -145,8 +145,8 @@ impl Totp {
 
     // Create a new token with secure key and algo.
     pub fn generate_secure(step: u64) -> Self {
-        let mut rng = rand::thread_rng();
-        let secret: Vec<u8> = (0..SECRET_SIZE_BYTES).map(|_| rng.gen()).collect();
+        let mut rng = rand::rng();
+        let secret: Vec<u8> = (0..SECRET_SIZE_BYTES).map(|_| rng.random()).collect();
         let algo = TotpAlgo::Sha256;
         let digits = TotpDigits::Six;
         Totp {
diff --git a/server/lib/src/idm/oauth2.rs b/server/lib/src/idm/oauth2.rs
index 9628e1ea4..dc9d8a73f 100644
--- a/server/lib/src/idm/oauth2.rs
+++ b/server/lib/src/idm/oauth2.rs
@@ -2992,11 +2992,12 @@ fn validate_scopes(req_scopes: &BTreeSet<String>) -> Result<(), Oauth2Error> {
 #[cfg(any(feature = "dev-oauth2-device-flow", test))]
 #[allow(dead_code)]
 fn gen_device_code() -> Result<[u8; 16], Oauth2Error> {
-    let mut rng = rand::thread_rng();
+    use rand::TryRngCore;
+
+    let mut rng = rand::rng();
     let mut result = [0u8; 16];
     // doing it here because of feature-shenanigans.
-    use rand::Rng;
-    if let Err(err) = rng.try_fill(&mut result) {
+    if let Err(err) = rng.try_fill_bytes(&mut result) {
         error!("Failed to generate device code! {:?}", err);
         return Err(Oauth2Error::ServerError(OperationError::Backend));
     }
@@ -3009,8 +3010,8 @@ fn gen_device_code() -> Result<[u8; 16], Oauth2Error> {
 /// Returns (xxx-yyy-zzz, digits) where one's the human-facing code, the other is what we store in the DB.
 fn gen_user_code() -> (String, u32) {
     use rand::Rng;
-    let mut rng = rand::thread_rng();
-    let num: u32 = rng.gen_range(0..=999999999);
+    let mut rng = rand::rng();
+    let num: u32 = rng.random_range(0..=999999999);
     let result = format!("{:09}", num);
     (
         format!("{}-{}-{}", &result[0..3], &result[3..6], &result[6..9]),
diff --git a/server/lib/src/idm/server.rs b/server/lib/src/idm/server.rs
index d6fc173ea..d047bb319 100644
--- a/server/lib/src/idm/server.rs
+++ b/server/lib/src/idm/server.rs
@@ -236,7 +236,7 @@ impl IdmServer {
         let qs_read = self.qs.read().await?;
 
         let mut sid = [0; 4];
-        let mut rng = StdRng::from_entropy();
+        let mut rng = StdRng::from_os_rng();
         rng.fill(&mut sid);
 
         Ok(IdmServerAuthTransaction {
@@ -279,7 +279,7 @@ impl IdmServer {
         let qs_write = self.qs.write(ts).await?;
 
         let mut sid = [0; 4];
-        let mut rng = StdRng::from_entropy();
+        let mut rng = StdRng::from_os_rng();
         rng.fill(&mut sid);
 
         Ok(IdmServerProxyWriteTransaction {
diff --git a/server/lib/src/utils.rs b/server/lib/src/utils.rs
index 1c762b027..2179f45b7 100644
--- a/server/lib/src/utils.rs
+++ b/server/lib/src/utils.rs
@@ -2,8 +2,8 @@
 
 use crate::prelude::*;
 use hashbrown::HashSet;
-use rand::distributions::{Distribution, Uniform};
-use rand::{thread_rng, Rng};
+use rand::distr::{Distribution, Uniform};
+use rand::{rng, Rng};
 use std::ops::Range;
 
 #[derive(Debug)]
@@ -35,7 +35,7 @@ pub fn uuid_from_duration(d: Duration, sid: Sid) -> Uuid {
 }
 
 pub(crate) fn password_from_random_len(len: u32) -> String {
-    thread_rng()
+    rng()
         .sample_iter(&DistinctAlpha)
         .take(len as usize)
         .collect::<String>()
@@ -52,7 +52,7 @@ pub fn backup_code_from_random() -> HashSet<String> {
 pub fn readable_password_from_random() -> String {
     // 2^112 bits, means we need at least 55^20 to have as many bits of entropy.
     // this leads us to 4 groups of 5 to create 55^20
-    let mut trng = thread_rng();
+    let mut trng = rng();
     format!(
         "{}-{}-{}-{}",
         (&mut trng)
@@ -81,7 +81,7 @@ impl Distribution<char> for DistinctAlpha {
                 abcdefghjkpqrstuvwxyz\
                 0123456789";
 
-        let range = Uniform::new(0, RANGE);
+        let range = Uniform::new(0, RANGE).expect("Failed to get a uniform range");
 
         let n = range.sample(rng);
         GEN_ASCII_STR_CHARSET[n as usize] as char
diff --git a/tools/orca/src/error.rs b/tools/orca/src/error.rs
index a2cc9697d..f73d3913b 100644
--- a/tools/orca/src/error.rs
+++ b/tools/orca/src/error.rs
@@ -8,4 +8,6 @@ pub enum Error {
     Interrupt,
     Crossbeam,
     InvalidState,
+    #[allow(dead_code)]
+    RandomNumber(String),
 }
diff --git a/tools/orca/src/generate.rs b/tools/orca/src/generate.rs
index afd779ff2..b34bf5fd8 100644
--- a/tools/orca/src/generate.rs
+++ b/tools/orca/src/generate.rs
@@ -4,8 +4,9 @@ use crate::model::ActorRole;
 use crate::profile::Profile;
 use crate::state::{Credential, Flag, Group, GroupName, Person, PreflightState, State};
 use hashbrown::HashMap;
-use rand::distributions::{Alphanumeric, DistString, Uniform};
-use rand::seq::{index, SliceRandom};
+use rand::distr::{Alphanumeric, SampleString, Uniform};
+use rand::seq::{index, IndexedRandom};
+
 use rand::{Rng, SeedableRng};
 use rand_chacha::ChaCha8Rng;
 
@@ -171,7 +172,8 @@ pub async fn populate(_client: &KanidmOrcaClient, profile: Profile) -> Result<St
                 let baseline = persons.len() / 3;
                 let inverse = persons.len() - baseline;
                 // Randomly add extra from the inverse
-                let extra = Uniform::new(0, inverse);
+                let extra =
+                    Uniform::new(0, inverse).map_err(|err| Error::RandomNumber(err.to_string()))?;
                 baseline + seeded_rng.sample(extra)
             }
         };
diff --git a/tools/orca/src/models/basic.rs b/tools/orca/src/models/basic.rs
index c362906a4..23f4c3142 100644
--- a/tools/orca/src/models/basic.rs
+++ b/tools/orca/src/models/basic.rs
@@ -27,7 +27,7 @@ impl ActorBasic {
     pub fn new(mut cha_rng: ChaCha8Rng, warmup_time_ms: u64) -> Self {
         let max_backoff_time_in_ms = 2 * warmup_time_ms / 3;
         let randomised_backoff_time =
-            Duration::from_millis(cha_rng.gen_range(0..max_backoff_time_in_ms));
+            Duration::from_millis(cha_rng.random_range(0..max_backoff_time_in_ms));
         ActorBasic {
             state: State::Unauthenticated,
             randomised_backoff_time,
diff --git a/tools/orca/src/models/latency_measurer.rs b/tools/orca/src/models/latency_measurer.rs
index 6601fac09..d681186a3 100644
--- a/tools/orca/src/models/latency_measurer.rs
+++ b/tools/orca/src/models/latency_measurer.rs
@@ -76,7 +76,7 @@ impl ActorLatencyMeasurer {
 
         let max_backoff_time_in_ms = 2 * warmup_time_ms / 3;
         let randomised_backoff_time =
-            Duration::from_millis(cha_rng.gen_range(0..max_backoff_time_in_ms));
+            Duration::from_millis(cha_rng.random_range(0..max_backoff_time_in_ms));
         Ok(ActorLatencyMeasurer {
             state: State::Unauthenticated,
             randomised_backoff_time,
diff --git a/tools/orca/src/models/read.rs b/tools/orca/src/models/read.rs
index f11eb9984..b280f0b5d 100644
--- a/tools/orca/src/models/read.rs
+++ b/tools/orca/src/models/read.rs
@@ -25,7 +25,7 @@ impl ActorReader {
     pub fn new(mut cha_rng: ChaCha8Rng, warmup_time_ms: u64) -> Self {
         let max_backoff_time_in_ms = warmup_time_ms - 1000;
         let randomised_backoff_time =
-            Duration::from_millis(cha_rng.gen_range(0..max_backoff_time_in_ms));
+            Duration::from_millis(cha_rng.random_range(0..max_backoff_time_in_ms));
         ActorReader {
             state: State::Unauthenticated,
             randomised_backoff_time,
diff --git a/tools/orca/src/models/write.rs b/tools/orca/src/models/write.rs
index 969f153ff..09da27c1a 100644
--- a/tools/orca/src/models/write.rs
+++ b/tools/orca/src/models/write.rs
@@ -26,7 +26,7 @@ impl ActorWriter {
     pub fn new(mut cha_rng: ChaCha8Rng, warmup_time_ms: u64) -> Self {
         let max_backoff_time_in_ms = 2 * warmup_time_ms / 3;
         let randomised_backoff_time =
-            Duration::from_millis(cha_rng.gen_range(0..max_backoff_time_in_ms));
+            Duration::from_millis(cha_rng.random_range(0..max_backoff_time_in_ms));
         ActorWriter {
             state: State::Unauthenticated,
             randomised_backoff_time,
diff --git a/tools/orca/src/profile.rs b/tools/orca/src/profile.rs
index 9b080d81d..d39a4c77b 100644
--- a/tools/orca/src/profile.rs
+++ b/tools/orca/src/profile.rs
@@ -1,6 +1,6 @@
 use crate::error::Error;
 use crate::state::{GroupName, Model};
-use rand::{thread_rng, Rng};
+use rand::{rng, Rng};
 use serde::de::{value, IntoDeserializer};
 use serde::{Deserialize, Serialize};
 use std::collections::BTreeMap;
@@ -200,8 +200,8 @@ impl ProfileBuilder {
         } = self;
 
         let seed: u64 = seed.unwrap_or_else(|| {
-            let mut rng = thread_rng();
-            rng.gen()
+            let mut rng = rng();
+            rng.random()
         });
 
         //TODO: Allow to specify group properties from the CLI
diff --git a/tools/orca/src/run.rs b/tools/orca/src/run.rs
index 393e6981f..c95187828 100644
--- a/tools/orca/src/run.rs
+++ b/tools/orca/src/run.rs
@@ -187,7 +187,7 @@ pub async fn execute(state: State, control_rx: broadcast::Receiver<Signal>) -> R
                 })
             })
             .collect::<Result<Vec<_>, _>>()?;
-        let main_client_index = seeded_rng.gen_range(0..cloned_clients.len());
+        let main_client_index = seeded_rng.random_range(0..cloned_clients.len());
         let main_client = cloned_clients.remove(main_client_index);
         //note that cloned_clients now contains all other clients except the first one