From d67643f24cf3b47d89ddf889a87de656e50be8bb Mon Sep 17 00:00:00 2001 From: Roland Vet Date: Sun, 18 Feb 2024 09:32:19 +0100 Subject: [PATCH] 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 --- src/commands/cmd_mount.rs | 37 ++++++++++++++++++++++++++++++++++--- 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, + /// 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, + mountpoint: Option, /// 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 { diff --git a/src/key.rs b/src/key.rs index 4e6991c5..0fc2034c 100644 --- a/src/key.rs +++ b/src/key.rs @@ -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 {