From 2cdefbe45c2b298529924092b492e2bea0e7b242 Mon Sep 17 00:00:00 2001 From: Jason Ross Date: Wed, 24 Jun 2026 20:44:22 -0500 Subject: [PATCH] Update rand to 0.10 with a rand_core 0.6 compatibility shim MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bump the `rand` dev-dependency to the latest (0.10), which exposes rand_core 0.10, while the latest `rsa` (0.9) still requires an rand_core 0.6 RNG for key generation. Bridge the skew with a small, test-only adapter instead of pinning rand back. * Add `rand_core_06 = { package = "rand_core", version = "0.6" }` so the shim can implement the old traits (cargo unifies it with the rand_core 0.6 that rsa already uses). * `RandCompat` wraps a modern RNG and re-implements rand_core 0.6's RngCore + CryptoRng over it, delegating to rand_core 0.10's infallible methods. Implementing both satisfies rand_core 0.6's blanket CryptoRngCore impl, which is exactly the bound rsa keygen requires. * The CryptoRng bound is preserved (only wraps RNGs still marked cryptographically secure), so the randomness is not weakened — it is purely a trait-version shim. Tests now use `RandCompat(rand::rng())`. 46 tests pass (incl. the RSA-based EPUB roundtrips that exercise the shim); clippy + rustfmt clean. Co-Authored-By: Claude Opus 4.8 --- Cargo.lock | 43 +++++++++++++++++++++----- crates/drmlibre-core/Cargo.toml | 9 ++++-- crates/drmlibre-core/src/adept/epub.rs | 40 ++++++++++++++++++++++-- 3 files changed, 79 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8ed00dc..25bd2a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -141,6 +141,17 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "chacha20" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" +dependencies = [ + "cfg-if", + "cpufeatures", + "rand_core 0.10.1", +] + [[package]] name = "cipher" version = "0.5.2" @@ -305,7 +316,8 @@ dependencies = [ "hex", "md-5", "quick-xml", - "rand", + "rand 0.10.1", + "rand_core 0.6.4", "rsa", "serde", "sha1", @@ -382,6 +394,7 @@ dependencies = [ "cfg-if", "libc", "r-efi", + "rand_core 0.10.1", ] [[package]] @@ -525,7 +538,7 @@ dependencies = [ "num-integer", "num-iter", "num-traits", - "rand", + "rand 0.8.6", "smallvec", "zeroize", ] @@ -656,9 +669,19 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" dependencies = [ - "libc", "rand_chacha", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" +dependencies = [ + "chacha20", + "getrandom 0.4.3", + "rand_core 0.10.1", ] [[package]] @@ -668,7 +691,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -680,6 +703,12 @@ dependencies = [ "getrandom 0.2.17", ] +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + [[package]] name = "regex-automata" version = "0.4.14" @@ -710,7 +739,7 @@ dependencies = [ "num-traits", "pkcs1", "pkcs8", - "rand_core", + "rand_core 0.6.4", "signature", "spki", "subtle", @@ -807,7 +836,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest 0.10.7", - "rand_core", + "rand_core 0.6.4", ] [[package]] diff --git a/crates/drmlibre-core/Cargo.toml b/crates/drmlibre-core/Cargo.toml index 50d6afa..35373a3 100644 --- a/crates/drmlibre-core/Cargo.toml +++ b/crates/drmlibre-core/Cargo.toml @@ -39,6 +39,9 @@ winreg = "0.56" [dev-dependencies] tempfile = "3" -# Held at 0.8: the latest `rsa` (0.9) requires an `rand_core` 0.6 RNG for keygen, -# which rand 0.9+ no longer provides; bumping breaks the RSA-based EPUB tests. -rand = "0.8" +rand = "0.10" +# Escape hatch: the latest `rsa` (0.9) still requires an `rand_core` 0.6 RNG for +# key generation, while `rand` 0.10 provides `rand_core` 0.10. We depend on +# `rand_core` 0.6 directly (package-renamed to avoid the name clash) so the +# test-only `RandCompat` shim can re-implement its traits over a modern RNG. +rand_core_06 = { package = "rand_core", version = "0.6" } diff --git a/crates/drmlibre-core/src/adept/epub.rs b/crates/drmlibre-core/src/adept/epub.rs index 493aa8b..1d90a93 100644 --- a/crates/drmlibre-core/src/adept/epub.rs +++ b/crates/drmlibre-core/src/adept/epub.rs @@ -269,9 +269,43 @@ mod tests { Some(buf) } + /// Test-only escape hatch for the `rand_core` version skew: `rsa` 0.9 still + /// requires an `rand_core` 0.6 RNG for key generation, while `rand` 0.10 + /// exposes `rand_core` 0.10. `RandCompat` wraps a modern RNG and + /// re-implements `rand_core` 0.6's `RngCore`/`CryptoRng` over it, delegating + /// to the new (infallible) methods. Implementing both satisfies `rand_core` + /// 0.6's blanket `CryptoRngCore` impl — exactly what `rsa` keygen wants. + /// + /// The `CryptoRng` bound is preserved (we only wrap RNGs the new crate still + /// marks cryptographically secure), so this is a pure trait-version shim that + /// does not weaken the randomness. + struct RandCompat(R); + + impl rand_core_06::RngCore for RandCompat { + fn next_u32(&mut self) -> u32 { + rand::Rng::next_u32(&mut self.0) + } + fn next_u64(&mut self) -> u64 { + rand::Rng::next_u64(&mut self.0) + } + fn fill_bytes(&mut self, dest: &mut [u8]) { + rand::Rng::fill_bytes(&mut self.0, dest) + } + fn try_fill_bytes( + &mut self, + dest: &mut [u8], + ) -> std::result::Result<(), rand_core_06::Error> { + // `fill_bytes` is infallible in rand_core 0.10. + rand::Rng::fill_bytes(&mut self.0, dest); + Ok(()) + } + } + + impl rand_core_06::CryptoRng for RandCompat {} + fn make_rsa() -> (Vec, rsa::RsaPublicKey) { use rsa::pkcs8::EncodePrivateKey; - let mut rng = rand::thread_rng(); + let mut rng = RandCompat(rand::rng()); let priv_key = rsa::RsaPrivateKey::new(&mut rng, 1024).unwrap(); let der = priv_key.to_pkcs8_der().unwrap().as_bytes().to_vec(); let pub_key = rsa::RsaPublicKey::from(&priv_key); @@ -286,7 +320,7 @@ mod tests { let (der, pub_key) = make_rsa(); let bookkey = [0x5Au8; 16]; - let mut rng = rand::thread_rng(); + let mut rng = RandCompat(rand::rng()); let enc_key = pub_key .encrypt(&mut rng, rsa::Pkcs1v15Encrypt, &bookkey) .unwrap(); @@ -323,7 +357,7 @@ mod tests { let (_der, pub_key) = make_rsa(); let (other_der, _other_pub) = make_rsa(); let bookkey = [0x5Au8; 16]; - let mut rng = rand::thread_rng(); + let mut rng = RandCompat(rand::rng()); let enc_key = pub_key .encrypt(&mut rng, rsa::Pkcs1v15Encrypt, &bookkey) .unwrap();