summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRoland Vet <RlndVt@protonmail.com>2024-02-18 09:32:19 +0100
committerRoland Vet <RlndVt@protonmail.com>2024-02-22 21:12:49 +0100
commitd67643f24cf3b47d89ddf889a87de656e50be8bb (patch)
tree813b63b1c046469b0f4594f1d81283974d80439f /src
parent0ff96b2a0fda48df57bbb47573aabeb493995a94 (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>
Diffstat (limited to 'src')
-rw-r--r--src/commands/cmd_mount.rs37
-rw-r--r--src/key.rs12
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 {
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 {