mirror of
https://github.com/dani-garcia/vaultwarden.git
synced 2024-12-22 22:45:12 +01:00
Use constant size generic parameter for random bytes generation
All uses of `get_random()` were in the form of: `&get_random(vec![0u8; SIZE])` with `SIZE` being a constant. Building a `Vec` is unnecessary for two reasons. First, it uses a very short-lived dynamic memory allocation. Second, a `Vec` is a resizable object, which is useless in those context when random data have a fixed size and will only be read. `get_random_bytes()` takes a constant as a generic parameter and returns an array with the requested number of random bytes. Stack safety analysis: the random bytes will be allocated on the caller stack for a very short time (until the encoding function has been called on the data). In some cases, the random bytes take less room than the `Vec` did (a `Vec` is 24 bytes on a 64 bit computer). The maximum used size is 180 bytes, which makes it for 0.008% of the default stack size for a Rust thread (2MiB), so this is a non-issue. Also, most of the uses of those random bytes are to encode them using an `Encoding`. The function `crypto::encode_random_bytes()` generates random bytes and encode them with the provided `Encoding`, leading to code deduplication. `generate_id()` has also been converted to use a constant generic parameter as well since the length of the requested String is always a constant.
This commit is contained in:
parent
7a7673103f
commit
d0baa23f9a
5 changed files with 19 additions and 12 deletions
|
@ -34,7 +34,7 @@ async fn generate_authenticator(data: JsonUpcase<PasswordData>, headers: Headers
|
||||||
|
|
||||||
let (enabled, key) = match twofactor {
|
let (enabled, key) = match twofactor {
|
||||||
Some(tf) => (true, tf.data),
|
Some(tf) => (true, tf.data),
|
||||||
_ => (false, BASE32.encode(&crypto::get_random(vec![0u8; 20]))),
|
_ => (false, crypto::encode_random_bytes::<20>(BASE32)),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Json(json!({
|
Ok(Json(json!({
|
||||||
|
|
|
@ -105,7 +105,7 @@ async fn recover(data: JsonUpcase<RecoverTwoFactor>, mut conn: DbConn) -> JsonRe
|
||||||
|
|
||||||
async fn _generate_recover_code(user: &mut User, conn: &mut DbConn) {
|
async fn _generate_recover_code(user: &mut User, conn: &mut DbConn) {
|
||||||
if user.totp_recover.is_none() {
|
if user.totp_recover.is_none() {
|
||||||
let totp_recover = BASE32.encode(&crypto::get_random(vec![0u8; 20]));
|
let totp_recover = crypto::encode_random_bytes::<20>(BASE32);
|
||||||
user.totp_recover = Some(totp_recover);
|
user.totp_recover = Some(totp_recover);
|
||||||
user.save(conn).await.ok();
|
user.save(conn).await.ok();
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ fn negotiate(_headers: Headers) -> Json<JsonValue> {
|
||||||
use crate::crypto;
|
use crate::crypto;
|
||||||
use data_encoding::BASE64URL;
|
use data_encoding::BASE64URL;
|
||||||
|
|
||||||
let conn_id = BASE64URL.encode(&crypto::get_random(vec![0u8; 16]));
|
let conn_id = crypto::encode_random_bytes::<16>(BASE64URL);
|
||||||
let mut available_transports: Vec<JsonValue> = Vec::new();
|
let mut available_transports: Vec<JsonValue> = Vec::new();
|
||||||
|
|
||||||
if CONFIG.websocket_enabled() {
|
if CONFIG.websocket_enabled() {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
//
|
//
|
||||||
use std::num::NonZeroU32;
|
use std::num::NonZeroU32;
|
||||||
|
|
||||||
use data_encoding::HEXLOWER;
|
use data_encoding::{Encoding, HEXLOWER};
|
||||||
use ring::{digest, hmac, pbkdf2};
|
use ring::{digest, hmac, pbkdf2};
|
||||||
|
|
||||||
static DIGEST_ALG: pbkdf2::Algorithm = pbkdf2::PBKDF2_HMAC_SHA256;
|
static DIGEST_ALG: pbkdf2::Algorithm = pbkdf2::PBKDF2_HMAC_SHA256;
|
||||||
|
@ -38,17 +38,24 @@ pub fn hmac_sign(key: &str, data: &str) -> String {
|
||||||
//
|
//
|
||||||
|
|
||||||
pub fn get_random_64() -> Vec<u8> {
|
pub fn get_random_64() -> Vec<u8> {
|
||||||
get_random(vec![0u8; 64])
|
get_random_bytes::<64>().to_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_random(mut array: Vec<u8>) -> Vec<u8> {
|
/// Return an array holding `N` random bytes.
|
||||||
|
pub fn get_random_bytes<const N: usize>() -> [u8; N] {
|
||||||
use ring::rand::{SecureRandom, SystemRandom};
|
use ring::rand::{SecureRandom, SystemRandom};
|
||||||
|
|
||||||
|
let mut array = [0; N];
|
||||||
SystemRandom::new().fill(&mut array).expect("Error generating random values");
|
SystemRandom::new().fill(&mut array).expect("Error generating random values");
|
||||||
|
|
||||||
array
|
array
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Encode random bytes using the provided function.
|
||||||
|
pub fn encode_random_bytes<const N: usize>(e: Encoding) -> String {
|
||||||
|
e.encode(&get_random_bytes::<N>())
|
||||||
|
}
|
||||||
|
|
||||||
/// Generates a random string over a specified alphabet.
|
/// Generates a random string over a specified alphabet.
|
||||||
pub fn get_random_string(alphabet: &[u8], num_chars: usize) -> String {
|
pub fn get_random_string(alphabet: &[u8], num_chars: usize) -> String {
|
||||||
// Ref: https://rust-lang-nursery.github.io/rust-cookbook/algorithms/randomness.html
|
// Ref: https://rust-lang-nursery.github.io/rust-cookbook/algorithms/randomness.html
|
||||||
|
@ -77,18 +84,18 @@ pub fn get_random_string_alphanum(num_chars: usize) -> String {
|
||||||
get_random_string(ALPHABET, num_chars)
|
get_random_string(ALPHABET, num_chars)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_id(num_bytes: usize) -> String {
|
pub fn generate_id<const N: usize>() -> String {
|
||||||
HEXLOWER.encode(&get_random(vec![0; num_bytes]))
|
encode_random_bytes::<N>(HEXLOWER)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_send_id() -> String {
|
pub fn generate_send_id() -> String {
|
||||||
// Send IDs are globally scoped, so make them longer to avoid collisions.
|
// Send IDs are globally scoped, so make them longer to avoid collisions.
|
||||||
generate_id(32) // 256 bits
|
generate_id::<32>() // 256 bits
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_attachment_id() -> String {
|
pub fn generate_attachment_id() -> String {
|
||||||
// Attachment IDs are scoped to a cipher, so they can be smaller.
|
// Attachment IDs are scoped to a cipher, so they can be smaller.
|
||||||
generate_id(10) // 80 bits
|
generate_id::<10>() // 80 bits
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates a numeric token for email-based verifications.
|
/// Generates a numeric token for email-based verifications.
|
||||||
|
|
|
@ -48,7 +48,7 @@ impl Device {
|
||||||
use crate::crypto;
|
use crate::crypto;
|
||||||
use data_encoding::BASE64;
|
use data_encoding::BASE64;
|
||||||
|
|
||||||
let twofactor_remember = BASE64.encode(&crypto::get_random(vec![0u8; 180]));
|
let twofactor_remember = crypto::encode_random_bytes::<180>(BASE64);
|
||||||
self.twofactor_remember = Some(twofactor_remember.clone());
|
self.twofactor_remember = Some(twofactor_remember.clone());
|
||||||
|
|
||||||
twofactor_remember
|
twofactor_remember
|
||||||
|
@ -69,7 +69,7 @@ impl Device {
|
||||||
use crate::crypto;
|
use crate::crypto;
|
||||||
use data_encoding::BASE64URL;
|
use data_encoding::BASE64URL;
|
||||||
|
|
||||||
self.refresh_token = BASE64URL.encode(&crypto::get_random_64());
|
self.refresh_token = crypto::encode_random_bytes::<64>(BASE64URL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the expiration of the device and the last update date
|
// Update the expiration of the device and the last update date
|
||||||
|
|
Loading…
Reference in a new issue