use std::path::PathBuf;
use clap::Parser;
use cosmian_kms_client::{
KmsClient,
cosmian_kmip::kmip_2_1::kmip_types::CryptographicAlgorithm,
kmip_2_1::{kmip_types::CryptographicParameters, requests::decrypt_request},
read_bytes_from_file, read_bytes_from_files_to_bulk, write_bulk_decrypted_data,
write_single_decrypted_data,
};
use cosmian_logger::debug;
use crate::{
actions::kms::{labels::KEY_ID, shared::get_key_uid},
error::result::{KmsCliResult, KmsCliResultHelper},
};
#[derive(Parser, Debug)]
pub struct DecryptAction {
#[clap(required = true, name = "FILE")]
pub(crate) input_files: Vec<PathBuf>,
#[clap(long = KEY_ID, short = 'k', group = "key-tags")]
pub(crate) key_id: Option<String>,
#[clap(long = "tag", short = 't', value_name = "TAG", group = "key-tags")]
pub(crate) tags: Option<Vec<String>>,
#[clap(required = false, long, short = 'o')]
pub(crate) output_file: Option<PathBuf>,
#[clap(required = false, long, short)]
pub(crate) authentication_data: Option<String>,
}
impl DecryptAction {
pub async fn run(&self, kms_rest_client: KmsClient) -> KmsCliResult<()> {
let (cryptographic_algorithm, data) = if self.input_files.len() > 1 {
(
CryptographicAlgorithm::CoverCryptBulk,
read_bytes_from_files_to_bulk(&self.input_files).with_context(
|| "Cannot read bytes from encrypted files to LEB-serialize them",
)?,
)
} else {
let first_file = self
.input_files
.first()
.context("No input files provided")?;
(
CryptographicAlgorithm::CoverCrypt,
read_bytes_from_file(first_file).with_context(
|| "Cannot read bytes from encrypted files to LEB-serialize them",
)?,
)
};
let id = get_key_uid(self.key_id.as_ref(), self.tags.as_ref(), KEY_ID)?;
let decrypt_request = decrypt_request(
&id,
None,
data,
None,
self.authentication_data
.as_deref()
.map(|s| s.as_bytes().to_vec()),
Some(CryptographicParameters {
cryptographic_algorithm: Some(cryptographic_algorithm),
..Default::default()
}),
);
debug!("{decrypt_request}");
let decrypt_response = kms_rest_client
.decrypt(decrypt_request)
.await
.with_context(|| "Can't execute the query on the kms server")?;
let cleartext = decrypt_response.data.context("The plain data are empty")?;
if cryptographic_algorithm == CryptographicAlgorithm::CoverCryptBulk {
write_bulk_decrypted_data(&cleartext, &self.input_files, self.output_file.as_ref())?;
} else {
let first_file = self
.input_files
.first()
.context("No input files provided")?;
write_single_decrypted_data(&cleartext, first_file, self.output_file.as_ref())?;
}
Ok(())
}
}