Skip to content

Commit 97410b3

Browse files
committed
Allow parallel encryption, reencryption and decryption operations
1 parent a5b3288 commit 97410b3

File tree

3 files changed

+175
-111
lines changed

3 files changed

+175
-111
lines changed

src/engine/strat_engine/cmd.rs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,6 @@ const CLEVIS_EXEC_NAMES: &[&str] = &[
111111
CLEVIS_REGEN,
112112
JOSE,
113113
JQ,
114-
CRYPTSETUP,
115114
CURL,
116115
TPM2_CREATEPRIMARY,
117116
TPM2_UNSEAL,
@@ -132,6 +131,7 @@ static EXECUTABLES: LazyLock<HashMap<String, Option<PathBuf>>> = LazyLock::new(|
132131
THIN_METADATA_SIZE.to_string(),
133132
find_executable(THIN_METADATA_SIZE),
134133
),
134+
(CRYPTSETUP.to_string(), find_executable(CRYPTSETUP)),
135135
]
136136
.iter()
137137
.cloned()
@@ -575,3 +575,38 @@ pub fn thin_metadata_size(
575575
)))
576576
}
577577
}
578+
579+
pub fn run_encrypt(path: &Path) -> StratisResult<()> {
580+
get_persistent_keyring()?;
581+
let mut cmd = Command::new(CRYPTSETUP);
582+
cmd.arg("reencrypt")
583+
.arg("--encrypt")
584+
.arg("--resume-only")
585+
.arg("--token-only")
586+
.arg(path);
587+
588+
execute_cmd(&mut cmd)
589+
}
590+
591+
pub fn run_reencrypt(path: &Path) -> StratisResult<()> {
592+
get_persistent_keyring()?;
593+
let mut cmd = Command::new(CRYPTSETUP);
594+
cmd.arg("reencrypt")
595+
.arg("--resume-only")
596+
.arg("--token-only")
597+
.arg(path);
598+
599+
execute_cmd(&mut cmd)
600+
}
601+
602+
pub fn run_decrypt(path: &Path) -> StratisResult<()> {
603+
get_persistent_keyring()?;
604+
let mut cmd = Command::new(CRYPTSETUP);
605+
cmd.arg("reencrypt")
606+
.arg("--decrypt")
607+
.arg("--resume-only")
608+
.arg("--token-only")
609+
.arg(path);
610+
611+
execute_cmd(&mut cmd)
612+
}

src/engine/strat_engine/crypt/handle/v2.rs

Lines changed: 66 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ use crate::{
3535
engine::MAX_STRATIS_PASS_SIZE,
3636
strat_engine::{
3737
backstore::{backstore::v2, get_devno_from_path, get_logical_sector_size},
38-
cmd::{clevis_luks_bind, clevis_luks_regen, clevis_luks_unbind},
38+
cmd::{
39+
clevis_luks_bind, clevis_luks_regen, clevis_luks_unbind, run_decrypt, run_encrypt,
40+
},
3941
crypt::{
4042
consts::{
4143
DEFAULT_CRYPT_DATA_OFFSET_V2, DEFAULT_CRYPT_KEYSLOTS_SIZE,
@@ -818,38 +820,43 @@ impl CryptHandle {
818820
sector_size: u32,
819821
key_info: (u32, SizedKeyMemory),
820822
) -> StratisResult<()> {
821-
let mut device = acquire_crypt_device(unencrypted_path)?;
822-
let activation_name = &format_crypt_backstore_name(&pool_uuid).to_string();
823-
let (keyslot, key) = key_info;
824-
device.reencrypt_handle().reencrypt_init_by_passphrase(
825-
Some(activation_name),
826-
key.as_ref(),
827-
None,
828-
Some(keyslot),
829-
Some(("aes", "xts-plain64")),
830-
CryptParamsReencrypt {
831-
mode: CryptReencryptModeInfo::Encrypt,
832-
direction: CryptReencryptDirectionInfo::Forward,
833-
resilience: "checksum".to_string(),
834-
hash: "sha256".to_string(),
835-
data_shift: 0,
836-
max_hotzone_size: 0,
837-
device_size: 0,
838-
luks2: Some(CryptParamsLuks2 {
839-
data_alignment: 0,
840-
data_device: None,
841-
integrity: None,
842-
integrity_params: None,
843-
pbkdf: None,
844-
label: None,
845-
sector_size,
846-
subsystem: None,
847-
}),
848-
flags: CryptReencrypt::RESUME_ONLY,
849-
},
850-
)?;
823+
{
824+
let mut device = acquire_crypt_device(unencrypted_path)?;
825+
let activation_name = &format_crypt_backstore_name(&pool_uuid).to_string();
826+
let (keyslot, key) = key_info;
827+
device.reencrypt_handle().reencrypt_init_by_passphrase(
828+
Some(activation_name),
829+
key.as_ref(),
830+
None,
831+
Some(keyslot),
832+
Some(("aes", "xts-plain64")),
833+
CryptParamsReencrypt {
834+
mode: CryptReencryptModeInfo::Encrypt,
835+
direction: CryptReencryptDirectionInfo::Forward,
836+
resilience: "checksum".to_string(),
837+
hash: "sha256".to_string(),
838+
data_shift: 0,
839+
max_hotzone_size: 0,
840+
device_size: 0,
841+
luks2: Some(CryptParamsLuks2 {
842+
data_alignment: 0,
843+
data_device: None,
844+
integrity: None,
845+
integrity_params: None,
846+
pbkdf: None,
847+
label: None,
848+
sector_size,
849+
subsystem: None,
850+
}),
851+
flags: CryptReencrypt::RESUME_ONLY,
852+
},
853+
)?;
854+
}
855+
851856
info!("Starting encryption operation on pool with UUID {pool_uuid}; may take a while");
852-
device.reencrypt_handle().reencrypt2::<()>(None, None)?;
857+
// The corresponding libcryptsetup call is device.reencrypt_handle().reencrypt2::<()>(None, None)?;
858+
run_encrypt(unencrypted_path)?;
859+
853860
Ok(())
854861
}
855862

@@ -894,31 +901,35 @@ impl CryptHandle {
894901

895902
/// Decrypt the crypt device for an encrypted pool.
896903
pub fn decrypt(&self, pool_uuid: PoolUuid) -> StratisResult<()> {
897-
let activation_name = format_crypt_backstore_name(&pool_uuid);
898-
let mut device = acquire_crypt_device(self.luks2_device_path())?;
899-
let (keyslot, key) = get_passphrase(&mut device, self.encryption_info())?
900-
.either(|(keyslot, _, key)| (keyslot, key), |tup| tup);
904+
{
905+
let activation_name = format_crypt_backstore_name(&pool_uuid);
906+
let mut device = acquire_crypt_device(self.luks2_device_path())?;
907+
let (keyslot, key) = get_passphrase(&mut device, self.encryption_info())?
908+
.either(|(keyslot, _, key)| (keyslot, key), |tup| tup);
909+
910+
device.reencrypt_handle().reencrypt_init_by_passphrase(
911+
Some(&activation_name.to_string()),
912+
key.as_ref(),
913+
Some(keyslot),
914+
None,
915+
None,
916+
CryptParamsReencrypt {
917+
mode: CryptReencryptModeInfo::Decrypt,
918+
direction: CryptReencryptDirectionInfo::Forward,
919+
resilience: "checksum".to_string(),
920+
hash: "sha256".to_string(),
921+
data_shift: 0,
922+
max_hotzone_size: 0,
923+
device_size: 0,
924+
luks2: None,
925+
flags: CryptReencrypt::empty(),
926+
},
927+
)?;
928+
}
901929

902-
device.reencrypt_handle().reencrypt_init_by_passphrase(
903-
Some(&activation_name.to_string()),
904-
key.as_ref(),
905-
Some(keyslot),
906-
None,
907-
None,
908-
CryptParamsReencrypt {
909-
mode: CryptReencryptModeInfo::Decrypt,
910-
direction: CryptReencryptDirectionInfo::Forward,
911-
resilience: "checksum".to_string(),
912-
hash: "sha256".to_string(),
913-
data_shift: 0,
914-
max_hotzone_size: 0,
915-
device_size: 0,
916-
luks2: None,
917-
flags: CryptReencrypt::empty(),
918-
},
919-
)?;
920930
info!("Starting decryption operation on pool with UUID {pool_uuid}; may take a while");
921-
device.reencrypt_handle().reencrypt2::<()>(None, None)?;
931+
// the corresponding libcryptsetup call is device.reencrypt_handle().reencrypt2::<()>(None, None)?;
932+
run_decrypt(self.luks2_device_path())?;
922933
Ok(())
923934
}
924935

src/engine/strat_engine/crypt/shared.rs

Lines changed: 73 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1101,6 +1101,33 @@ pub fn handle_setup_reencrypt(
11011101
luks2_path: &Path,
11021102
encryption_info: &EncryptionInfo,
11031103
) -> StratisResult<(u32, SizedKeyMemory, u32)> {
1104+
fn set_up_reencryption_token(
1105+
device: &mut CryptDevice,
1106+
new_keyslot: u32,
1107+
ts: u32,
1108+
mut token_contents: Value,
1109+
) -> StratisResult<()> {
1110+
if let Some(obj) = token_contents.as_object_mut() {
1111+
let tokens = match obj.remove(TOKEN_KEYSLOTS_KEY) {
1112+
Some(Value::Array(mut v)) => {
1113+
v.push(Value::String(new_keyslot.to_string()));
1114+
Value::Array(v)
1115+
}
1116+
Some(_) | None => {
1117+
return Err(StratisError::Msg(format!(
1118+
"Could not find appropriate formatted value for {TOKEN_KEYSLOTS_KEY}"
1119+
)));
1120+
}
1121+
};
1122+
obj.insert(TOKEN_KEYSLOTS_KEY.to_string(), tokens);
1123+
}
1124+
device
1125+
.token_handle()
1126+
.json_set(TokenInput::ReplaceToken(ts, &token_contents))?;
1127+
1128+
Ok(())
1129+
}
1130+
11041131
let mut device = acquire_crypt_device(luks2_path)?;
11051132

11061133
let mut keys = get_all_passphrases(&mut device, encryption_info)?;
@@ -1113,7 +1140,7 @@ pub fn handle_setup_reencrypt(
11131140
let (single_ts, single_key) = keys
11141141
.pop()
11151142
.ok_or_else(|| StratisError::Msg("No unlock methods found".to_string()))?;
1116-
let mut single_token_contents = device.token_handle().json_get(single_ts)?;
1143+
let single_token_contents = device.token_handle().json_get(single_ts)?;
11171144
let single_keyslot = get_keyslot_number(&mut device, single_ts)?.ok_or_else(|| {
11181145
StratisError::Msg(format!(
11191146
"Could not find keyslot associated with token slot {single_ts}"
@@ -1126,16 +1153,13 @@ pub fn handle_setup_reencrypt(
11261153
single_key.as_ref(),
11271154
CryptVolumeKey::NO_SEGMENT,
11281155
)?;
1129-
if let Some(obj) = single_token_contents.as_object_mut() {
1130-
obj.remove(TOKEN_KEYSLOTS_KEY);
1131-
obj.insert(
1132-
TOKEN_KEYSLOTS_KEY.to_string(),
1133-
Value::Array(vec![Value::String(single_new_keyslot.to_string())]),
1134-
);
1135-
}
1136-
device
1137-
.token_handle()
1138-
.json_set(TokenInput::ReplaceToken(single_ts, &single_token_contents))?;
1156+
1157+
set_up_reencryption_token(
1158+
&mut device,
1159+
single_new_keyslot,
1160+
single_ts,
1161+
single_token_contents,
1162+
)?;
11391163

11401164
let mut new_vk = SafeMemHandle::alloc(STRATIS_MEK_SIZE)?;
11411165
device.volume_key_handle().get(
@@ -1145,24 +1169,15 @@ pub fn handle_setup_reencrypt(
11451169
)?;
11461170

11471171
for (ts, key) in other_keys {
1148-
let mut token_contents = device.token_handle().json_get(ts)?;
1172+
let token_contents = device.token_handle().json_get(ts)?;
11491173

11501174
let new_keyslot = device.keyslot_handle().add_by_key(
11511175
None,
11521176
Some(Either::Left(new_vk.as_ref())),
11531177
key.as_ref(),
11541178
CryptVolumeKey::NO_SEGMENT | CryptVolumeKey::DIGEST_REUSE,
11551179
)?;
1156-
if let Some(obj) = token_contents.as_object_mut() {
1157-
obj.remove(TOKEN_KEYSLOTS_KEY);
1158-
obj.insert(
1159-
TOKEN_KEYSLOTS_KEY.to_string(),
1160-
Value::Array(vec![Value::String(new_keyslot.to_string())]),
1161-
);
1162-
}
1163-
device
1164-
.token_handle()
1165-
.json_set(TokenInput::ReplaceToken(ts, &token_contents))?;
1180+
set_up_reencryption_token(&mut device, new_keyslot, ts, token_contents)?;
11661181
}
11671182

11681183
Ok((single_keyslot, single_key, single_new_keyslot))
@@ -1179,41 +1194,44 @@ pub fn handle_do_reencrypt(
11791194
single_key: SizedKeyMemory,
11801195
single_new_keyslot: u32,
11811196
) -> StratisResult<()> {
1182-
let mut device = acquire_crypt_device(luks2_path)?;
1183-
1184-
let cipher = device.status_handle().get_cipher()?;
1185-
let cipher_mode = device.status_handle().get_cipher_mode()?;
1186-
let sector_size = convert_int!(get_sector_size(Some(&mut device)), i32, u32)?;
1187-
device.reencrypt_handle().reencrypt_init_by_passphrase(
1188-
Some(device_name),
1189-
single_key.as_ref(),
1190-
Some(single_keyslot),
1191-
Some(single_new_keyslot),
1192-
Some((&cipher, &cipher_mode)),
1193-
CryptParamsReencrypt {
1194-
mode: CryptReencryptModeInfo::Reencrypt,
1195-
direction: CryptReencryptDirectionInfo::Forward,
1196-
resilience: "checksum".to_string(),
1197-
hash: "sha256".to_string(),
1198-
data_shift: 0,
1199-
max_hotzone_size: 0,
1200-
device_size: 0,
1201-
luks2: Some(CryptParamsLuks2 {
1202-
data_alignment: 0,
1203-
data_device: None,
1204-
integrity: None,
1205-
integrity_params: None,
1206-
pbkdf: None,
1207-
label: None,
1208-
sector_size,
1209-
subsystem: None,
1210-
}),
1211-
flags: CryptReencrypt::empty(),
1212-
},
1213-
)?;
1197+
{
1198+
let mut device = acquire_crypt_device(luks2_path)?;
1199+
1200+
let cipher = device.status_handle().get_cipher()?;
1201+
let cipher_mode = device.status_handle().get_cipher_mode()?;
1202+
let sector_size = convert_int!(get_sector_size(Some(&mut device)), i32, u32)?;
1203+
device.reencrypt_handle().reencrypt_init_by_passphrase(
1204+
Some(device_name),
1205+
single_key.as_ref(),
1206+
Some(single_keyslot),
1207+
Some(single_new_keyslot),
1208+
Some((&cipher, &cipher_mode)),
1209+
CryptParamsReencrypt {
1210+
mode: CryptReencryptModeInfo::Reencrypt,
1211+
direction: CryptReencryptDirectionInfo::Forward,
1212+
resilience: "checksum".to_string(),
1213+
hash: "sha256".to_string(),
1214+
data_shift: 0,
1215+
max_hotzone_size: 0,
1216+
device_size: 0,
1217+
luks2: Some(CryptParamsLuks2 {
1218+
data_alignment: 0,
1219+
data_device: None,
1220+
integrity: None,
1221+
integrity_params: None,
1222+
pbkdf: None,
1223+
label: None,
1224+
sector_size,
1225+
subsystem: None,
1226+
}),
1227+
flags: CryptReencrypt::empty(),
1228+
},
1229+
)?;
1230+
}
12141231

12151232
info!("Starting reencryption operation on pool with UUID {pool_uuid}; may take a while");
1216-
device.reencrypt_handle().reencrypt2::<()>(None, None)?;
1233+
// The corresponding libcryptsetup call is device.reencrypt_handle().reencrypt2::<()>(None, None)?;
1234+
cmd::run_reencrypt(luks2_path)?;
12171235

12181236
Ok(())
12191237
}

0 commit comments

Comments
 (0)