From 0d1240255af0ffc69e8859a6fbfd512ccb86508b Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Mon, 25 May 2026 21:13:51 -0600 Subject: [PATCH] ssh-key: fix `getrandom` It was temporarily disabled in #417 to simplify the `rand_core` v0.10 upgrade. --- Cargo.lock | 1 + ssh-key/Cargo.toml | 3 ++ ssh-key/src/certificate/builder.rs | 9 +++--- ssh-key/src/lib.rs | 18 +++++------ ssh-key/src/private.rs | 12 ++++--- ssh-key/tests/encrypted_private_key.rs | 43 +++++++++++++------------- 6 files changed, 45 insertions(+), 41 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index eb0b5e4..ee03a73 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -924,6 +924,7 @@ dependencies = [ "ctutils", "dsa", "ed25519-dalek", + "getrandom", "hex", "hex-literal", "hmac", diff --git a/ssh-key/Cargo.toml b/ssh-key/Cargo.toml index 627cdbd..0b9afe1 100644 --- a/ssh-key/Cargo.toml +++ b/ssh-key/Cargo.toml @@ -54,6 +54,7 @@ sha1 = { version = "0.11", optional = true, default-features = false, features = [dev-dependencies] hex-literal = "1" chacha20 = { version = "0.10", features = ["rng"] } +getrandom = { version = "0.4", features = ["sys_rng"] } [features] default = ["ecdsa", "rand_core", "std"] @@ -71,10 +72,12 @@ encryption = [ "cipher/chacha20poly1305", "rand_core" ] +getrandom = ["cipher/getrandom", "rand_core"] p256 = ["dep:p256", "ecdsa"] p384 = ["dep:p384", "ecdsa"] p521 = ["dep:p521", "ecdsa"] ppk = ["dep:hex", "alloc", "cipher/aes", "dep:hmac", "dep:argon2", "dep:sha1"] +rand_core = ["dep:rand_core", "cipher/rand_core"] rsa = ["dep:rsa", "alloc", "encoding/bigint", "rand_core"] sha1 = ["dep:sha1"] tdes = ["cipher/tdes", "encryption"] diff --git a/ssh-key/src/certificate/builder.rs b/ssh-key/src/certificate/builder.rs index fcd498c..84bb9e4 100644 --- a/ssh-key/src/certificate/builder.rs +++ b/ssh-key/src/certificate/builder.rs @@ -40,16 +40,17 @@ use crate::{Error, PrivateKey}; doc = " ```ignore" )] /// # fn main() -> Result<(), ssh_key::Error> { -/// use ssh_key::{Algorithm, PrivateKey, certificate, rand_core::{TryRngCore, OsRng}}; +/// use ssh_key::{Algorithm, PrivateKey, certificate, getrandom::SysRng, rand_core::UnwrapErr}; /// use std::time::{SystemTime, UNIX_EPOCH}; /// /// // Generate the certificate authority's private key -/// let ca_key = PrivateKey::random(&mut OsRng.unwrap_err(), Algorithm::Ed25519)?; +/// let mut rng = UnwrapErr(SysRng); +/// let ca_key = PrivateKey::random(&mut rng, Algorithm::Ed25519)?; /// /// // Generate a "subject" key to be signed by the certificate authority. /// // Normally a user or host would do this locally and give the certificate /// // authority the public key. -/// let subject_private_key = PrivateKey::random(&mut OsRng.unwrap_err(), Algorithm::Ed25519)?; +/// let subject_private_key = PrivateKey::random(&mut rng, Algorithm::Ed25519)?; /// let subject_public_key = subject_private_key.public_key(); /// /// // Create certificate validity window @@ -58,7 +59,7 @@ use crate::{Error, PrivateKey}; /// /// // Initialize certificate builder /// let mut cert_builder = certificate::Builder::new_with_random_nonce( -/// &mut OsRng.unwrap_err(), +/// &mut rng, /// subject_public_key, /// valid_after, /// valid_before, diff --git a/ssh-key/src/lib.rs b/ssh-key/src/lib.rs index 00f9c0b..820e701 100644 --- a/ssh-key/src/lib.rs +++ b/ssh-key/src/lib.rs @@ -5,7 +5,6 @@ html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg" )] -#![allow(unexpected_cfgs, reason = "TODO fix getrandom feature")] //! ## Usage //! @@ -160,6 +159,14 @@ pub use cipher::{self, Cipher}; pub use encoding::{self, pem::LineEnding}; pub use sha2; +#[cfg(feature = "std")] +pub use crate::dot_ssh::DotSsh; +#[cfg(feature = "getrandom")] +pub use cipher::cipher::common::getrandom; +#[cfg(feature = "rand_core")] +pub use rand_core; +#[cfg(feature = "ecdsa")] +pub use sec1; #[cfg(feature = "alloc")] pub use { crate::{ @@ -172,12 +179,3 @@ pub use { }, encoding::Mpint, }; - -#[cfg(feature = "ecdsa")] -pub use sec1; - -#[cfg(feature = "rand_core")] -pub use rand_core; - -#[cfg(feature = "std")] -pub use crate::dot_ssh::DotSsh; diff --git a/ssh-key/src/private.rs b/ssh-key/src/private.rs index f0ce4eb..a7bf4a2 100644 --- a/ssh-key/src/private.rs +++ b/ssh-key/src/private.rs @@ -55,15 +55,16 @@ doc = " ```ignore" )] //! # fn main() -> Result<(), ssh_key::Error> { -//! use ssh_key::{Algorithm, PrivateKey, rand_core::{OsRng, TryRngCore}}; +//! use ssh_key::{Algorithm, PrivateKey, getrandom::SysRng, rand_core::UnwrapErr}; //! //! // Generate a random key -//! let unencrypted_key = PrivateKey::random(&mut OsRng.unwrap_err(), Algorithm::Ed25519)?; +//! let mut rng = UnwrapErr(SysRng); +//! let unencrypted_key = PrivateKey::random(&mut rng, Algorithm::Ed25519)?; //! //! // WARNING: don't hardcode passwords, and this one's bad anyway //! let password = "hunter42"; //! -//! let encrypted_key = unencrypted_key.encrypt(&mut OsRng, password)?; +//! let encrypted_key = unencrypted_key.encrypt(&mut SysRng, password)?; //! assert!(encrypted_key.is_encrypted()); //! # Ok(()) //! # } @@ -84,9 +85,10 @@ doc = " ```ignore" )] //! # fn main() -> Result<(), ssh_key::Error> { -//! use ssh_key::{Algorithm, PrivateKey, rand_core::{OsRng, TryRngCore}}; +//! use ssh_key::{Algorithm, PrivateKey, getrandom::SysRng, rand_core::UnwrapErr}; //! -//! let private_key = PrivateKey::random(&mut OsRng.unwrap_err(), Algorithm::Ed25519)?; +//! let mut rng = UnwrapErr(SysRng); +//! let private_key = PrivateKey::random(&mut rng, Algorithm::Ed25519)?; //! # Ok(()) //! # } //! ``` diff --git a/ssh-key/tests/encrypted_private_key.rs b/ssh-key/tests/encrypted_private_key.rs index 3e61508..c048df7 100644 --- a/ssh-key/tests/encrypted_private_key.rs +++ b/ssh-key/tests/encrypted_private_key.rs @@ -1,8 +1,6 @@ //! Encrypted SSH private key tests. #![cfg(feature = "alloc")] -// TODO(tarcieri): fix `getrandom` feature -#![allow(unexpected_cfgs)] use hex_literal::hex; use ssh_key::{Algorithm, Cipher, Kdf, KdfAlg, PrivateKey}; @@ -297,11 +295,12 @@ fn encode_openssh_aes256_gcm() { #[cfg(all(feature = "encryption", feature = "getrandom"))] #[test] fn encrypt_openssh_aes128_cbc() { - use rand_core::{OsRng, TryRngCore}; + use getrandom::{SysRng, rand_core::UnwrapErr}; + let mut rng = UnwrapErr(SysRng); let key_dec = PrivateKey::from_openssh(OPENSSH_ED25519_EXAMPLE).unwrap(); let key_enc = key_dec - .encrypt_with_cipher(&mut OsRng.unwrap_err(), Cipher::Aes128Cbc, PASSWORD) + .encrypt_with_cipher(&mut rng, Cipher::Aes128Cbc, PASSWORD) .unwrap(); // Ensure encrypted key round trips through encoder/decoder @@ -317,11 +316,11 @@ fn encrypt_openssh_aes128_cbc() { #[cfg(all(feature = "encryption", feature = "getrandom"))] #[test] fn encrypt_openssh_aes192_cbc() { - use rand_core::OsRng; + use getrandom::SysRng; let key_dec = PrivateKey::from_openssh(OPENSSH_ED25519_EXAMPLE).unwrap(); let key_enc = key_dec - .encrypt_with_cipher(&mut OsRng, Cipher::Aes192Cbc, PASSWORD) + .encrypt_with_cipher(&mut SysRng, Cipher::Aes192Cbc, PASSWORD) .unwrap(); // Ensure encrypted key round trips through encoder/decoder @@ -337,11 +336,11 @@ fn encrypt_openssh_aes192_cbc() { #[cfg(all(feature = "encryption", feature = "getrandom"))] #[test] fn encrypt_openssh_aes256_cbc() { - use rand_core::OsRng; + use getrandom::SysRng; let key_dec = PrivateKey::from_openssh(OPENSSH_ED25519_EXAMPLE).unwrap(); let key_enc = key_dec - .encrypt_with_cipher(&mut OsRng, Cipher::Aes256Cbc, PASSWORD) + .encrypt_with_cipher(&mut SysRng, Cipher::Aes256Cbc, PASSWORD) .unwrap(); // Ensure encrypted key round trips through encoder/decoder @@ -357,11 +356,11 @@ fn encrypt_openssh_aes256_cbc() { #[cfg(all(feature = "encryption", feature = "getrandom"))] #[test] fn encrypt_openssh_aes128_ctr() { - use rand_core::OsRng; + use getrandom::SysRng; let key_dec = PrivateKey::from_openssh(OPENSSH_ED25519_EXAMPLE).unwrap(); let key_enc = key_dec - .encrypt_with_cipher(&mut OsRng, Cipher::Aes128Ctr, PASSWORD) + .encrypt_with_cipher(&mut SysRng, Cipher::Aes128Ctr, PASSWORD) .unwrap(); // Ensure encrypted key round trips through encoder/decoder @@ -377,11 +376,11 @@ fn encrypt_openssh_aes128_ctr() { #[cfg(all(feature = "encryption", feature = "getrandom"))] #[test] fn encrypt_openssh_aes192_ctr() { - use rand_core::OsRng; + use getrandom::SysRng; let key_dec = PrivateKey::from_openssh(OPENSSH_ED25519_EXAMPLE).unwrap(); let key_enc = key_dec - .encrypt_with_cipher(&mut OsRng, Cipher::Aes192Ctr, PASSWORD) + .encrypt_with_cipher(&mut SysRng, Cipher::Aes192Ctr, PASSWORD) .unwrap(); // Ensure encrypted key round trips through encoder/decoder @@ -397,10 +396,10 @@ fn encrypt_openssh_aes192_ctr() { #[cfg(all(feature = "encryption", feature = "getrandom"))] #[test] fn encrypt_openssh_aes256_ctr() { - use rand_core::OsRng; + use getrandom::SysRng; let key_dec = PrivateKey::from_openssh(OPENSSH_ED25519_EXAMPLE).unwrap(); - let key_enc = key_dec.encrypt(&mut OsRng, PASSWORD).unwrap(); + let key_enc = key_dec.encrypt(&mut SysRng, PASSWORD).unwrap(); // Ensure encrypted key round trips through encoder/decoder let key_enc_str = key_enc.to_openssh(Default::default()).unwrap(); @@ -415,12 +414,12 @@ fn encrypt_openssh_aes256_ctr() { #[cfg(all(feature = "encryption", feature = "getrandom"))] #[test] fn encrypt_openssh_aes128_gcm() { - use rand_core::OsRng; + use getrandom::SysRng; let key_dec = PrivateKey::from_openssh(OPENSSH_ED25519_EXAMPLE).unwrap(); let key_enc = key_dec - .encrypt_with_cipher(&mut OsRng, Cipher::Aes128Gcm, PASSWORD) + .encrypt_with_cipher(&mut SysRng, Cipher::Aes128Gcm, PASSWORD) .unwrap(); // Ensure encrypted key round trips through encoder/decoder @@ -436,12 +435,12 @@ fn encrypt_openssh_aes128_gcm() { #[cfg(all(feature = "encryption", feature = "getrandom"))] #[test] fn encrypt_openssh_aes256_gcm() { - use rand_core::OsRng; + use getrandom::SysRng; let key_dec = PrivateKey::from_openssh(OPENSSH_ED25519_EXAMPLE).unwrap(); let key_enc = key_dec - .encrypt_with_cipher(&mut OsRng, Cipher::Aes256Gcm, PASSWORD) + .encrypt_with_cipher(&mut SysRng, Cipher::Aes256Gcm, PASSWORD) .unwrap(); // Ensure encrypted key round trips through encoder/decoder @@ -457,12 +456,12 @@ fn encrypt_openssh_aes256_gcm() { #[cfg(all(feature = "encryption", feature = "getrandom"))] #[test] fn encrypt_openssh_chacha20_poly1305() { - use rand_core::OsRng; + use getrandom::SysRng; let key_dec = PrivateKey::from_openssh(OPENSSH_ED25519_EXAMPLE).unwrap(); let key_enc = key_dec - .encrypt_with_cipher(&mut OsRng, Cipher::ChaCha20Poly1305, PASSWORD) + .encrypt_with_cipher(&mut SysRng, Cipher::ChaCha20Poly1305, PASSWORD) .unwrap(); // Ensure encrypted key round trips through encoder/decoder @@ -478,12 +477,12 @@ fn encrypt_openssh_chacha20_poly1305() { #[cfg(all(feature = "tdes", feature = "getrandom"))] #[test] fn encrypt_openssh_3des() { - use rand_core::OsRng; + use getrandom::SysRng; let key_dec = PrivateKey::from_openssh(OPENSSH_ED25519_EXAMPLE).unwrap(); let key_enc = key_dec - .encrypt_with_cipher(&mut OsRng, Cipher::TdesCbc, PASSWORD) + .encrypt_with_cipher(&mut SysRng, Cipher::TdesCbc, PASSWORD) .unwrap(); // Ensure encrypted key round trips through encoder/decoder