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>
This commit is contained in:
Roland Vet 2024-02-18 09:32:19 +01:00
parent 0ff96b2a0f
commit d67643f24c
2 changed files with 45 additions and 4 deletions

View File

@ -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 {

View File

@ -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 {