diff options
author | Roland Vet <RlndVt@protonmail.com> | 2024-02-18 09:32:19 +0100 |
---|---|---|
committer | Roland Vet <RlndVt@protonmail.com> | 2024-02-22 21:12:49 +0100 |
commit | d67643f24cf3b47d89ddf889a87de656e50be8bb (patch) | |
tree | 813b63b1c046469b0f4594f1d81283974d80439f | |
parent | 0ff96b2a0fda48df57bbb47573aabeb493995a94 (diff) |
Add decryption by key_file
- Add key_file option to Cli
- Rework decryption flow logic to first attempt key_file
- Read password from file and pass to decrypt_master_key
Explicity specify '-k' for key_location
Signed-off-by: Roland Vet <RlndVt@protonmail.com>
-rw-r--r-- | src/commands/cmd_mount.rs | 37 | ||||
-rw-r--r-- | src/key.rs | 12 |
2 files changed, 45 insertions, 4 deletions
diff --git a/src/commands/cmd_mount.rs b/src/commands/cmd_mount.rs index eef7e1d6..0462cbde 100644 --- a/src/commands/cmd_mount.rs +++ b/src/commands/cmd_mount.rs @@ -128,6 +128,14 @@ fn get_devices_by_uuid(uuid: Uuid) -> anyhow::Result<Vec<(PathBuf, bch_sb_handle #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] pub struct Cli { + /// Path to password key file + /// + /// Precedes key_location: if the filesystem can be decrypted by the + /// specified key_file; it is decrypted. (i.e. Regardless if "fail" + /// is specified for key_location.) + #[arg(short = 'f', long)] + key_file: Option<PathBuf>, + /// Where the password would be loaded from. /// /// Possible values are: @@ -143,7 +151,7 @@ pub struct Cli { /// Where the filesystem should be mounted. If not set, then the filesystem /// won't actually be mounted. But all steps preceeding mounting the /// filesystem (e.g. asking for passphrase) will still be performed. - mountpoint: Option<std::path::PathBuf>, + mountpoint: Option<PathBuf>, /// Mount options #[arg(short, default_value = "")] @@ -196,8 +204,31 @@ fn cmd_mount_inner(opt: Cli) -> anyhow::Result<()> { if sbs.len() == 0 { Err(anyhow::anyhow!("No device found from specified parameters"))?; - } else if unsafe { bcachefs::bch2_sb_is_encrypted(sbs[0].sb) } { - key::prepare_key(&sbs[0], opt.key_location)?; + } + // Check if the filesystem's master key is encrypted + if unsafe { bcachefs::bch2_sb_is_encrypted(sbs[0].sb) } { + // Filesystem's master key is encrypted, attempt to decrypt + // First by key_file, if available + let fallback_to_prepare_key = if let Some(key_file) = &opt.key_file { + match key::read_from_key_file(&sbs[0], key_file.as_path()) { + Ok(()) => { + // Decryption succeeded + false + } + Err(err) => { + // Decryption failed, fall back to prepare_key + error!("Failed to decrypt using key_file: {}", err); + true + } + } + } else { + // No key_file specified, fall back to prepare_key + true + }; + // If decryption by key_file was unsuccesful, prompt for password (or follow key_policy) + if fallback_to_prepare_key { + key::prepare_key(&sbs[0], opt.key_location)?; + }; } if let Some(mountpoint) = opt.mountpoint { @@ -1,4 +1,4 @@ -use std::{fmt, io::{stdin, IsTerminal}}; +use std::{fmt, fs, io::{stdin, IsTerminal}}; use log::{info}; use bch_bindgen::bcachefs::bch_sb_handle; @@ -150,6 +150,16 @@ fn decrypt_master_key(sb: &bch_sb_handle, pass: String) -> anyhow::Result<()> { } } +pub fn read_from_key_file(sb: &bch_sb_handle, key_file: &std::path::Path) -> anyhow::Result<()> { + // Attempts to decrypt the master key by key_file + // Return true if decryption was successful, false otherwise + info!("Attempting to decrypt master key for filesystem {}, using key file {}", sb.sb().uuid(), key_file.display()); + // Read the contents of the key file into a string + let pass = fs::read_to_string(key_file)?; + // Call decrypt_master_key with the read string + decrypt_master_key(sb, pass) +} + pub fn prepare_key(sb: &bch_sb_handle, password: KeyLocation) -> anyhow::Result<()> { info!("checking if key exists for filesystem {}", sb.sb().uuid()); match password { |