diff options
author | Thomas Mühlbacher <tmuehlbacher@posteo.net> | 2024-06-26 18:17:53 +0200 |
---|---|---|
committer | Thomas Mühlbacher <tmuehlbacher@posteo.net> | 2024-06-26 19:14:45 +0200 |
commit | ee5f3719d33ae3ff227aaeda686c7faba33b847d (patch) | |
tree | dcff6059015a6f909d2c81dbad52a3a9dc03c065 | |
parent | 795585e2899f9f785b284339cd7b0097747998c4 (diff) |
refactor(key): split up unlocking functions
This is more similar to the existing C code, which is already in nice
small chunks.
Signed-off-by: Thomas Mühlbacher <tmuehlbacher@posteo.net>
-rw-r--r-- | src/key.rs | 68 |
1 files changed, 42 insertions, 26 deletions
@@ -11,7 +11,7 @@ use std::{ use anyhow::{anyhow, ensure, Result}; use bch_bindgen::{ bcachefs::{self, bch_key, bch_sb_handle}, - c::{bch2_chacha_encrypt_key, bch_sb_field_crypt}, + c::{bch2_chacha_encrypt_key, bch_encrypted_key, bch_sb_field_crypt}, keyutils::{self, keyctl_search}, }; use byteorder::{LittleEndian, ReadBytesExt}; @@ -69,44 +69,24 @@ impl KeyHandle { } pub fn new(sb: &bch_sb_handle, passphrase: &Passphrase) -> Result<Self> { - let bch_key_magic = BCH_KEY_MAGIC.as_bytes().read_u64::<LittleEndian>().unwrap(); - - let crypt = sb.sb().crypt().unwrap(); - let crypt_ptr = (crypt as *const bch_sb_field_crypt).cast_mut(); - - let mut output: bch_key = - unsafe { bcachefs::derive_passphrase(crypt_ptr, passphrase.get().as_ptr()) }; - - let mut key = *crypt.key(); - - let ret = unsafe { - bch2_chacha_encrypt_key( - ptr::addr_of_mut!(output), - sb.sb().nonce(), - ptr::addr_of_mut!(key).cast(), - mem::size_of_val(&key), - ) - }; - - ensure!(ret == 0, "chacha decryption failure"); - ensure!(key.magic == bch_key_magic, "failed to verify passphrase"); - let key_name = Self::format_key_name(&sb.sb().uuid()); let key_name = CStr::as_ptr(&key_name); let key_type = c_str!("user"); + let (passphrase_key, _sb_key) = passphrase.check(sb)?; + let key_id = unsafe { keyutils::add_key( key_type, key_name, - ptr::addr_of!(output).cast(), - mem::size_of_val(&output), + ptr::addr_of!(passphrase_key).cast(), + mem::size_of_val(&passphrase_key), keyutils::KEY_SPEC_USER_KEYRING, ) }; if key_id > 0 { - info!("Found key in keyring"); + info!("Added key to keyring"); Ok(KeyHandle { _uuid: sb.sb().uuid(), _id: c_long::from(key_id), @@ -197,4 +177,40 @@ impl Passphrase { Ok(Self(CString::new(passphrase.trim_end_matches('\n'))?)) } + + fn derive(&self, crypt: &bch_sb_field_crypt) -> bch_key { + let crypt_ptr = (crypt as *const bch_sb_field_crypt).cast_mut(); + + unsafe { bcachefs::derive_passphrase(crypt_ptr, self.get().as_ptr()) } + } + + pub fn check(&self, sb: &bch_sb_handle) -> Result<(bch_key, bch_encrypted_key)> { + let bch_key_magic = BCH_KEY_MAGIC.as_bytes().read_u64::<LittleEndian>().unwrap(); + + let crypt = sb + .sb() + .crypt() + .ok_or_else(|| anyhow!("filesystem is not encrypted"))?; + let mut sb_key = *crypt.key(); + + ensure!( + sb_key.magic != bch_key_magic, + "filesystem does not have encryption key" + ); + + let mut passphrase_key: bch_key = self.derive(crypt); + + let ret = unsafe { + bch2_chacha_encrypt_key( + ptr::addr_of_mut!(passphrase_key), + sb.sb().nonce(), + ptr::addr_of_mut!(sb_key).cast(), + mem::size_of_val(&sb_key), + ) + }; + ensure!(ret == 0, "error encrypting key"); + ensure!(sb_key.magic == bch_key_magic, "incorrect passphrase"); + + Ok((passphrase_key, sb_key)) + } } |