use std::{fs::File, io::Write, path::PathBuf};
use clap::Parser;
use cosmian_kms_client::{
KmsClient,
kmip_2_1::requests::decrypt_request,
read_bytes_from_file,
reexport::cosmian_kms_client_utils::rsa_utils::{HashFn, RsaEncryptionAlgorithm},
};
use crate::{
actions::kms::{console, labels::KEY_ID, shared::get_key_uid},
error::result::{KmsCliResult, KmsCliResultHelper},
};
#[derive(Parser, Debug)]
#[clap(verbatim_doc_comment)]
pub struct DecryptAction {
#[clap(required = true, name = "FILE")]
pub(crate) input_file: 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(
long = "encryption-algorithm",
short = 'e',
default_value = "ckm-rsa-pkcs-oaep"
)]
pub(crate) encryption_algorithm: RsaEncryptionAlgorithm,
#[clap(long = "hashing-algorithm", short = 's', default_value = "sha256")]
pub(crate) hash_fn: HashFn,
#[clap(required = false, long, short = 'o')]
pub(crate) output_file: Option<PathBuf>,
}
impl DecryptAction {
pub async fn run(&self, kms_rest_client: KmsClient) -> KmsCliResult<()> {
let data = read_bytes_from_file(&self.input_file)
.with_context(|| "Cannot read bytes from the file to decrypt")?;
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,
None,
Some(
self.encryption_algorithm
.to_cryptographic_parameters(self.hash_fn),
),
);
let decrypt_response = kms_rest_client
.decrypt(decrypt_request)
.await
.with_context(|| "Can't execute the query on the kms server")?;
let plaintext = decrypt_response
.data
.context("Decrypt with RSA: the plaintext is empty")?;
let output_file = self
.output_file
.clone()
.unwrap_or_else(|| self.input_file.clone().with_extension("plain"));
let mut buffer =
File::create(&output_file).with_context(|| "Fail to write the plain file")?;
buffer
.write_all(&plaintext)
.with_context(|| "Fail to write the plain file")?;
let stdout = format!(
"The decrypted file is available at {}",
output_file.display()
);
let mut stdout = console::Stdout::new(&stdout);
stdout.set_tags(self.tags.as_ref());
stdout.write()?;
Ok(())
}
}