use crate::client::AppClient;
use crate::errors::AppError;
use crate::AppContext;
use bincode::{deserialize, serialize};
use miscreant::aead::Aead;
use miscreant::aead::Aes128SivAead;
use safe_core::{utils, Client, CoreError};
use serde_derive::{Deserialize, Serialize};
use threshold_crypto::{Ciphertext, PublicKey};
#[derive(Debug)]
pub enum CipherOpt {
PlainText,
Symmetric,
Asymmetric {
peer_encrypt_key: PublicKey,
},
}
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone, Serialize, Deserialize)]
enum WireFormat {
Plain(Vec<u8>),
Symmetric {
nonce: Vec<u8>,
cipher_text: Vec<u8>,
},
Asymmetric(Ciphertext),
}
impl CipherOpt {
pub fn encrypt(&self, plain_text: &[u8], app_ctx: &AppContext) -> Result<Vec<u8>, AppError> {
match *self {
Self::PlainText => Ok(serialize(&WireFormat::Plain(plain_text.to_owned()))?),
Self::Symmetric => {
let nonce = utils::generate_nonce().to_vec();
let sym_enc_key = app_ctx.sym_enc_key()?;
let mut cipher = Aes128SivAead::new(&**sym_enc_key);
let cipher_text = cipher.seal(&nonce, &[], plain_text);
let wire_format = WireFormat::Symmetric { nonce, cipher_text };
Ok(serialize(&wire_format)?)
}
Self::Asymmetric {
ref peer_encrypt_key,
} => {
let cipher_text = peer_encrypt_key.encrypt(plain_text);
Ok(serialize(&WireFormat::Asymmetric(cipher_text))?)
}
}
}
pub async fn decrypt(
cipher_text: &[u8],
app_ctx: &AppContext,
client: &AppClient,
) -> Result<Vec<u8>, AppError> {
if cipher_text.is_empty() {
return Ok(Vec::new());
}
match deserialize::<WireFormat>(cipher_text)? {
WireFormat::Plain(plain_text) => Ok(plain_text),
WireFormat::Symmetric { nonce, cipher_text } => {
let sym_enc_key = app_ctx.sym_enc_key()?;
let mut cipher = Aes128SivAead::new(&**sym_enc_key);
Ok(cipher
.open(&nonce, &[], &cipher_text)
.map_err(|_| CoreError::SymmetricDecipherFailure)?)
}
WireFormat::Asymmetric(cipher_text) => {
let asym_sk = client.secret_encryption_key().await;
asym_sk
.decrypt(&cipher_text)
.ok_or_else(|| AppError::from(CoreError::AsymmetricDecipherFailure))
}
}
}
}