Skip to content

Commit 272a125

Browse files
authored
sha-crypt: switch from rand to rand_core (#720)
Replaces the use of `Distribution` by first filling a buffer with random bytes, then encoding it as Base64. It seems the Base64 encoding is directly consumed by the algorithm, or otherwise it would probably make sense to convert all usages of `salt` to be raw bytes. That warrants further investigation.
1 parent 8381055 commit 272a125

File tree

4 files changed

+15
-90
lines changed

4 files changed

+15
-90
lines changed

Cargo.lock

Lines changed: 1 addition & 50 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sha-crypt/Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,15 @@ rust-version = "1.85"
1818

1919
[dependencies]
2020
sha2 = { version = "0.11.0-rc.2", default-features = false }
21+
base64ct = { version = "1.7.1", default-features = false }
2122

2223
# optional dependencies
23-
rand = { version = "0.9", optional = true }
24+
rand_core = { version = "0.9", optional = true, default-features = false, features = ["os_rng"] }
2425
subtle = { version = "2", optional = true, default-features = false }
25-
base64ct = "1.7.1"
2626

2727
[features]
2828
default = ["simple"]
29-
simple = ["rand", "subtle"]
29+
simple = ["base64ct/alloc", "dep:rand_core", "dep:subtle"]
3030

3131
[package.metadata.docs.rs]
3232
all-features = true

sha-crypt/src/defs.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,6 @@ pub const PW_SIZE_SHA512: usize = 86;
1414
#[cfg(feature = "simple")]
1515
pub const SALT_MAX_LEN: usize = 16;
1616

17-
/// Encoding table.
18-
#[cfg(feature = "simple")]
19-
pub static TAB: &[u8] = b"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
20-
2117
/// Inverse encoding map for SHA512.
2218
#[rustfmt::skip]
2319
pub const MAP_SHA512: [u8; 64] = [

sha-crypt/src/lib.rs

Lines changed: 11 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,10 @@ use sha2::{Digest, Sha256, Sha512};
5656

5757
#[cfg(feature = "simple")]
5858
use {
59-
crate::{
60-
defs::{SALT_MAX_LEN, TAB},
61-
errors::CheckError,
62-
},
59+
crate::{defs::SALT_MAX_LEN, errors::CheckError},
6360
alloc::string::ToString,
64-
rand::{Rng, distr::Distribution},
61+
base64ct::{Base64ShaCrypt, Encoding},
62+
rand_core::{OsRng, RngCore, TryRngCore},
6563
};
6664

6765
#[cfg(feature = "simple")]
@@ -317,13 +315,7 @@ pub fn sha256_crypt_b64(password: &[u8], salt: &[u8], params: &Sha256Params) ->
317315
/// [1]: https://www.akkadia.org/drepper/SHA-crypt.txt
318316
#[cfg(feature = "simple")]
319317
pub fn sha512_simple(password: &str, params: &Sha512Params) -> String {
320-
let rng = rand::rng();
321-
322-
let salt: String = rng
323-
.sample_iter(&ShaCryptDistribution)
324-
.take(SALT_MAX_LEN)
325-
.collect();
326-
318+
let salt = random_salt();
327319
let out = sha512_crypt(password.as_bytes(), salt.as_bytes(), params);
328320

329321
let mut result = String::new();
@@ -352,13 +344,7 @@ pub fn sha512_simple(password: &str, params: &Sha512Params) -> String {
352344
/// [1]: https://www.akkadia.org/drepper/SHA-crypt.txt
353345
#[cfg(feature = "simple")]
354346
pub fn sha256_simple(password: &str, params: &Sha256Params) -> String {
355-
let rng = rand::rng();
356-
357-
let salt: String = rng
358-
.sample_iter(&ShaCryptDistribution)
359-
.take(SALT_MAX_LEN)
360-
.collect();
361-
347+
let salt = random_salt();
362348
let out = sha256_crypt(password.as_bytes(), salt.as_bytes(), params);
363349

364350
let mut result = String::new();
@@ -528,21 +514,13 @@ pub fn sha256_check(password: &str, hashed_value: &str) -> Result<(), CheckError
528514
}
529515
}
530516

517+
/// Generate a random salt that is 16-bytes long.
531518
#[cfg(feature = "simple")]
532-
#[derive(Debug)]
533-
struct ShaCryptDistribution;
534-
535-
#[cfg(feature = "simple")]
536-
impl Distribution<char> for ShaCryptDistribution {
537-
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> char {
538-
const RANGE: u32 = 26 + 26 + 10 + 2; // 2 == "./"
539-
loop {
540-
let var = rng.next_u32() >> (32 - 6);
541-
if var < RANGE {
542-
return TAB[var as usize] as char;
543-
}
544-
}
545-
}
519+
fn random_salt() -> String {
520+
// Create buffer containing raw bytes to encode as Base64
521+
let mut buf = [0u8; (SALT_MAX_LEN * 3).div_ceil(4)];
522+
OsRng.unwrap_err().fill_bytes(&mut buf);
523+
Base64ShaCrypt::encode_string(&buf)
546524
}
547525

548526
fn produce_byte_seq(len: usize, fill_from: &[u8]) -> Vec<u8> {

0 commit comments

Comments
 (0)