diff --git a/crates/crypto/src/crypto/stream.rs b/crates/crypto/src/crypto/stream.rs index 109ecf2a1..8106f183f 100644 --- a/crates/crypto/src/crypto/stream.rs +++ b/crates/crypto/src/crypto/stream.rs @@ -4,7 +4,7 @@ use std::io::Cursor; use crate::{ - primitives::{AEAD_TAG_SIZE, BLOCK_SIZE, KEY_LEN}, + primitives::{Key, AEAD_TAG_SIZE, BLOCK_SIZE}, protected::ProtectedVec, Error, Protected, Result, }; @@ -55,7 +55,7 @@ impl StreamEncryption { /// /// The master key, a suitable nonce, and a specific algorithm should be provided. #[allow(clippy::needless_pass_by_value)] - pub fn new(key: Protected<[u8; KEY_LEN]>, nonce: &[u8], algorithm: Algorithm) -> Result { + pub fn new(key: Protected, nonce: &[u8], algorithm: Algorithm) -> Result { if nonce.len() != algorithm.nonce_len() { return Err(Error::NonceLengthMismatch); } @@ -153,7 +153,7 @@ impl StreamEncryption { /// It is just a thin wrapper around `encrypt_streams()`, but reduces the amount of code needed elsewhere. #[allow(unused_mut)] pub async fn encrypt_bytes( - key: Protected<[u8; KEY_LEN]>, + key: Protected, nonce: &[u8], algorithm: Algorithm, bytes: &[u8], @@ -174,7 +174,7 @@ impl StreamDecryption { /// /// The master key, nonce and algorithm that were used for encryption should be provided. #[allow(clippy::needless_pass_by_value)] - pub fn new(key: Protected<[u8; KEY_LEN]>, nonce: &[u8], algorithm: Algorithm) -> Result { + pub fn new(key: Protected, nonce: &[u8], algorithm: Algorithm) -> Result { if nonce.len() != algorithm.nonce_len() { return Err(Error::NonceLengthMismatch); } @@ -272,7 +272,7 @@ impl StreamDecryption { /// It is just a thin wrapper around `decrypt_streams()`, but reduces the amount of code needed elsewhere. #[allow(unused_mut)] pub async fn decrypt_bytes( - key: Protected<[u8; KEY_LEN]>, + key: Protected, nonce: &[u8], algorithm: Algorithm, bytes: &[u8], diff --git a/crates/crypto/src/header/file.rs b/crates/crypto/src/header/file.rs index acfb2aa59..60b3659ef 100644 --- a/crates/crypto/src/header/file.rs +++ b/crates/crypto/src/header/file.rs @@ -35,7 +35,7 @@ use tokio::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt}; use crate::{ crypto::stream::Algorithm, - primitives::{generate_nonce, to_array, KEY_LEN}, + primitives::{generate_nonce, to_array, Key, KEY_LEN}, protected::ProtectedVec, Error, Protected, Result, }; @@ -101,10 +101,7 @@ impl FileHeader { /// /// You receive an error if the password doesn't match or if there are no keyslots. #[allow(clippy::needless_pass_by_value)] - pub async fn decrypt_master_key( - &self, - password: ProtectedVec, - ) -> Result> { + pub async fn decrypt_master_key(&self, password: ProtectedVec) -> Result> { if self.keyslots.is_empty() { return Err(Error::NoKeyslots); } @@ -140,8 +137,8 @@ impl FileHeader { #[allow(clippy::needless_pass_by_value)] pub async fn decrypt_master_key_from_prehashed( &self, - hashed_keys: Vec>, - ) -> Result> { + hashed_keys: Vec>, + ) -> Result> { if self.keyslots.is_empty() { return Err(Error::NoKeyslots); } diff --git a/crates/crypto/src/header/keyslot.rs b/crates/crypto/src/header/keyslot.rs index 8d8cbd8b4..e15b1b7c4 100644 --- a/crates/crypto/src/header/keyslot.rs +++ b/crates/crypto/src/header/keyslot.rs @@ -27,8 +27,8 @@ use crate::{ crypto::stream::{Algorithm, StreamDecryption, StreamEncryption}, keys::hashing::HashingAlgorithm, primitives::{ - derive_key, generate_nonce, generate_salt, to_array, ENCRYPTED_KEY_LEN, FILE_KEY_CONTEXT, - KEY_LEN, SALT_LEN, + derive_key, generate_nonce, generate_salt, to_array, EncryptedKey, Key, Salt, + ENCRYPTED_KEY_LEN, FILE_KEY_CONTEXT, SALT_LEN, }, protected::ProtectedVec, Error, Protected, Result, @@ -42,9 +42,9 @@ pub struct Keyslot { pub version: KeyslotVersion, pub algorithm: Algorithm, // encryption algorithm pub hashing_algorithm: HashingAlgorithm, // password hashing algorithm - pub salt: [u8; SALT_LEN], // the salt used for deriving a KEK from a (key/content salt) hash - pub content_salt: [u8; SALT_LEN], - pub master_key: [u8; ENCRYPTED_KEY_LEN], // this is encrypted so we can store it + pub salt: Salt, // the salt used for deriving a KEK from a (key/content salt) hash + pub content_salt: Salt, + pub master_key: EncryptedKey, // this is encrypted so we can store it pub nonce: Vec, } @@ -69,9 +69,9 @@ impl Keyslot { version: KeyslotVersion, algorithm: Algorithm, hashing_algorithm: HashingAlgorithm, - content_salt: [u8; SALT_LEN], - hashed_key: Protected<[u8; KEY_LEN]>, - master_key: Protected<[u8; KEY_LEN]>, + content_salt: Salt, + hashed_key: Protected, + master_key: Protected, ) -> Result { let nonce = generate_nonce(algorithm); @@ -130,7 +130,7 @@ impl Keyslot { /// An error will be returned on failure. pub async fn decrypt_master_key_from_prehashed( &self, - key: Protected<[u8; KEY_LEN]>, + key: Protected, ) -> Result> { StreamDecryption::decrypt_bytes( derive_key(key, self.salt, FILE_KEY_CONTEXT), diff --git a/crates/crypto/src/header/metadata.rs b/crates/crypto/src/header/metadata.rs index 1c9dae758..f0138aba8 100644 --- a/crates/crypto/src/header/metadata.rs +++ b/crates/crypto/src/header/metadata.rs @@ -30,10 +30,13 @@ #[cfg(feature = "serde")] use crate::protected::ProtectedVec; +#[cfg(feature = "serde")] +use crate::primitives::Key; + #[cfg(feature = "serde")] use crate::{ crypto::stream::{StreamDecryption, StreamEncryption}, - primitives::{generate_nonce, KEY_LEN}, + primitives::generate_nonce, Protected, }; @@ -75,7 +78,7 @@ impl FileHeader { &mut self, version: MetadataVersion, algorithm: Algorithm, - master_key: Protected<[u8; KEY_LEN]>, + master_key: Protected, metadata: &T, ) -> Result<()> where @@ -110,7 +113,7 @@ impl FileHeader { #[cfg(feature = "serde")] pub async fn decrypt_metadata_from_prehashed( &self, - hashed_keys: Vec>, + hashed_keys: Vec>, ) -> Result where T: serde::de::DeserializeOwned, diff --git a/crates/crypto/src/header/preview_media.rs b/crates/crypto/src/header/preview_media.rs index 79e0849e5..101d02669 100644 --- a/crates/crypto/src/header/preview_media.rs +++ b/crates/crypto/src/header/preview_media.rs @@ -24,7 +24,7 @@ use tokio::io::AsyncReadExt; use crate::{ crypto::stream::{Algorithm, StreamDecryption, StreamEncryption}, - primitives::{generate_nonce, KEY_LEN}, + primitives::{generate_nonce, Key}, protected::ProtectedVec, Error, Protected, Result, }; @@ -62,7 +62,7 @@ impl FileHeader { &mut self, version: PreviewMediaVersion, algorithm: Algorithm, - master_key: Protected<[u8; KEY_LEN]>, + master_key: Protected, media: &[u8], ) -> Result<()> { let media_nonce = generate_nonce(algorithm); @@ -88,7 +88,7 @@ impl FileHeader { /// Once provided, a `Vec` is returned that contains the preview media pub async fn decrypt_preview_media_from_prehashed( &self, - hashed_keys: Vec>, + hashed_keys: Vec>, ) -> Result> { let master_key = self.decrypt_master_key_from_prehashed(hashed_keys).await?; diff --git a/crates/crypto/src/keys/hashing.rs b/crates/crypto/src/keys/hashing.rs index ab1d791d2..73756afbf 100644 --- a/crates/crypto/src/keys/hashing.rs +++ b/crates/crypto/src/keys/hashing.rs @@ -11,10 +11,10 @@ //! let hashed_password = hashing_algorithm.hash(password, salt).unwrap(); //! ``` -use crate::primitives::KEY_LEN; +use crate::primitives::{Key, Salt, KEY_LEN}; use crate::protected::ProtectedVec; use crate::Protected; -use crate::{primitives::SALT_LEN, Error, Result}; +use crate::{Error, Result}; use argon2::Argon2; use balloon_hash::Balloon; @@ -54,9 +54,9 @@ impl HashingAlgorithm { pub fn hash( &self, password: ProtectedVec, - salt: [u8; SALT_LEN], + salt: Salt, secret: Option>, - ) -> Result> { + ) -> Result> { match self { Self::Argon2id(params) => PasswordHasher::argon2id(password, salt, secret, *params), Self::BalloonBlake3(params) => { @@ -108,10 +108,10 @@ impl PasswordHasher { #[allow(clippy::needless_pass_by_value)] fn argon2id( password: ProtectedVec, - salt: [u8; SALT_LEN], + salt: Salt, secret: Option>, params: Params, - ) -> Result> { + ) -> Result> { let secret = secret.map_or(Protected::new(vec![]), |k| k); let mut key = [0u8; KEY_LEN]; @@ -131,10 +131,10 @@ impl PasswordHasher { #[allow(clippy::needless_pass_by_value)] fn balloon_blake3( password: ProtectedVec, - salt: [u8; SALT_LEN], + salt: Salt, secret: Option>, params: Params, - ) -> Result> { + ) -> Result> { let secret = secret.map_or(Protected::new(vec![]), |k| k); let mut key = [0u8; KEY_LEN]; diff --git a/crates/crypto/src/keys/keymanager.rs b/crates/crypto/src/keys/keymanager.rs index b0be50ebe..2396e3cd2 100644 --- a/crates/crypto/src/keys/keymanager.rs +++ b/crates/crypto/src/keys/keymanager.rs @@ -39,15 +39,11 @@ use std::sync::Mutex; use crate::crypto::stream::{StreamDecryption, StreamEncryption}; use crate::primitives::{ - derive_key, generate_master_key, generate_nonce, generate_salt, to_array, OnboardingConfig, - KEY_LEN, LATEST_STORED_KEY, MASTER_PASSWORD_CONTEXT, ROOT_KEY_CONTEXT, + derive_key, generate_master_key, generate_nonce, generate_salt, to_array, EncryptedKey, Key, + OnboardingConfig, Salt, KEY_LEN, LATEST_STORED_KEY, MASTER_PASSWORD_CONTEXT, ROOT_KEY_CONTEXT, }; use crate::protected::ProtectedVec; -use crate::{ - crypto::stream::Algorithm, - primitives::{ENCRYPTED_KEY_LEN, SALT_LEN}, - Protected, -}; +use crate::{crypto::stream::Algorithm, primitives::ENCRYPTED_KEY_LEN, Protected}; use crate::{Error, Result}; use dashmap::{DashMap, DashSet}; @@ -67,13 +63,13 @@ pub struct StoredKey { pub version: StoredKeyVersion, pub algorithm: Algorithm, // encryption algorithm for encrypting the master key. can be changed (requires a re-encryption though) pub hashing_algorithm: HashingAlgorithm, // hashing algorithm used for hashing the key with the content salt - pub content_salt: [u8; SALT_LEN], + pub content_salt: Salt, #[cfg_attr(feature = "serde", serde(with = "BigArray"))] // salt used for file data - pub master_key: [u8; ENCRYPTED_KEY_LEN], // this is for encrypting the `key` + pub master_key: EncryptedKey, // this is for encrypting the `key` pub master_key_nonce: Vec, // nonce for encrypting the master key pub key_nonce: Vec, // nonce used for encrypting the main key pub key: Vec, // encrypted. the key stored in spacedrive (e.g. generated 64 char key) - pub salt: [u8; SALT_LEN], + pub salt: Salt, pub memory_only: bool, pub automount: bool, } @@ -90,8 +86,8 @@ pub enum StoredKeyVersion { /// This contains the plaintext key, and the same key hashed with the content salt. #[derive(Clone)] pub struct MountedKey { - pub uuid: Uuid, // used for identification. shared with stored keys - pub hashed_key: Protected<[u8; KEY_LEN]>, // this is hashed with the content salt, for instant access + pub uuid: Uuid, // used for identification. shared with stored keys + pub hashed_key: Protected, // this is hashed with the content salt, for instant access } /// This is the key manager itself. @@ -100,7 +96,7 @@ pub struct MountedKey { /// /// Use the associated functions to interact with it. pub struct KeyManager { - root_key: Mutex>>, // the root key for the vault + root_key: Mutex>>, // the root key for the vault verification_key: Mutex>, keystore: DashMap, keymount: DashMap, @@ -651,7 +647,7 @@ impl KeyManager { hashing_algorithm: HashingAlgorithm, memory_only: bool, automount: bool, - content_salt: Option<[u8; SALT_LEN]>, + content_salt: Option, ) -> Result { let uuid = uuid::Uuid::new_v4(); @@ -741,7 +737,7 @@ impl KeyManager { } /// This should ONLY be used internally. - fn get_root_key(&self) -> Result> { + fn get_root_key(&self) -> Result> { self.root_key.lock()?.clone().ok_or(Error::NoMasterPassword) } @@ -779,11 +775,11 @@ impl KeyManager { /// /// This means we don't need to keep super specific track of which key goes to which file, and we can just throw all of them at it. #[must_use] - pub fn enumerate_hashed_keys(&self) -> Vec> { + pub fn enumerate_hashed_keys(&self) -> Vec> { self.keymount .iter() .map(|mounted_key| mounted_key.hashed_key.clone()) - .collect::>>() + .collect::>>() } /// This function is for converting a memory-only key to a saved key which syncs to the library. diff --git a/crates/crypto/src/primitives.rs b/crates/crypto/src/primitives.rs index 982e7deb0..e15d2cf8f 100644 --- a/crates/crypto/src/primitives.rs +++ b/crates/crypto/src/primitives.rs @@ -44,6 +44,10 @@ pub const MASTER_PASSWORD_CONTEXT: &str = "spacedrive 2022-12-14 15:35:41 master password hash derivation"; // used for deriving keys from the master password hash pub const FILE_KEY_CONTEXT: &str = "spacedrive 2022-12-14 12:54:12 file key derivation"; // used for deriving keys from user key/content salt hashes (for file encryption) +pub type Key = [u8; KEY_LEN]; +pub type EncryptedKey = [u8; ENCRYPTED_KEY_LEN]; +pub type Salt = [u8; SALT_LEN]; + #[derive(Clone)] #[cfg_attr(feature = "serde", derive(serde::Deserialize))] #[cfg_attr(feature = "rspc", derive(specta::Type))] @@ -70,7 +74,7 @@ pub fn generate_nonce(algorithm: Algorithm) -> Vec { /// /// This function uses `ChaCha20Rng` for generating cryptographically-secure random data #[must_use] -pub fn generate_salt() -> [u8; SALT_LEN] { +pub fn generate_salt() -> Salt { let mut salt = [0u8; SALT_LEN]; rand_chacha::ChaCha20Rng::from_entropy().fill_bytes(&mut salt); salt @@ -82,7 +86,7 @@ pub fn generate_salt() -> [u8; SALT_LEN] { /// /// This function uses `ChaCha20Rng` for generating cryptographically-secure random data #[must_use] -pub fn generate_master_key() -> Protected<[u8; KEY_LEN]> { +pub fn generate_master_key() -> Protected { let mut master_key = [0u8; KEY_LEN]; rand_chacha::ChaCha20Rng::from_entropy().fill_bytes(&mut master_key); Protected::new(master_key) @@ -90,11 +94,7 @@ pub fn generate_master_key() -> Protected<[u8; KEY_LEN]> { #[must_use] #[allow(clippy::needless_pass_by_value)] -pub fn derive_key( - key: Protected<[u8; KEY_LEN]>, - salt: [u8; SALT_LEN], - context: &str, -) -> Protected<[u8; KEY_LEN]> { +pub fn derive_key(key: Protected, salt: Salt, context: &str) -> Protected { let mut input = key.expose().to_vec(); input.extend_from_slice(&salt); @@ -107,7 +107,7 @@ pub fn derive_key( /// This is used for converting a `Vec` to an array of bytes /// -/// It's main usage is for converting an encrypted master key from a `Vec` to `[u8; ENCRYPTED_KEY_LEN]` +/// It's main usage is for converting an encrypted master key from a `Vec` to `EncryptedKey` /// /// As the master key is encrypted at this point, it does not need to be `Protected<>` /// diff --git a/crates/crypto/src/protected.rs b/crates/crypto/src/protected.rs index 27a3629e0..747f1a1bc 100644 --- a/crates/crypto/src/protected.rs +++ b/crates/crypto/src/protected.rs @@ -32,7 +32,6 @@ use std::{fmt::Debug, mem::swap}; use zeroize::Zeroize; pub type ProtectedVec = Protected>; - #[derive(Clone)] pub struct Protected where