#[cfg(feature = "legacy-pqclean")]
use crate::core::{CryptographicFunctions, KeyControlVariant};
use crate::{
cryptography::{
hmac_sign::{Operation, Sign, SignType},
*,
},
error::*,
};
use chacha20::{
cipher::{generic_array::GenericArray, KeyIvInit, StreamCipher},
XChaCha20,
};
use hex;
use rand::{rngs::OsRng, RngCore};
use std::{fs, result::Result};
pub fn generate_nonce() -> [u8; 24] {
let mut nonce = [0u8; 24];
OsRng.fill_bytes(&mut nonce);
nonce
}
impl CipherChaCha {
pub fn new(infos: CryptographicInformation, nonce: Option<String>) -> Self {
let nonce: [u8; 24] = match nonce {
Some(nonce) => hex::decode(nonce)
.expect("An error occoured while decoding hex!")
.try_into()
.unwrap(),
None => generate_nonce(),
};
CipherChaCha {
infos,
sharedsecret: Vec::new(),
nonce,
}
}
pub fn get_data(&self) -> Result<Vec<u8>, CryptError> {
let data = &self.infos.content()?;
let data = data.to_vec();
Ok(data)
}
pub fn set_shared_secret(&mut self, sharedsecret: Vec<u8>) -> &Self {
self.sharedsecret = sharedsecret;
self
}
pub fn sharedsecret(&self) -> Result<&[u8], CryptError> {
Ok(&self.sharedsecret)
}
pub fn set_nonce(&mut self, nonce: [u8; 24]) -> &[u8; 24] {
self.nonce = nonce;
&self.nonce
}
pub fn nonce(&self) -> &[u8; 24] {
&self.nonce
}
#[allow(dead_code)]
fn cryptography(&mut self) -> Result<(Vec<u8>, Vec<u8>), CryptError> {
let passphrase = self.infos.passphrase()?.to_vec();
let file_contained = self.infos.contains_file()?;
if file_contained && self.infos.metadata.content_type == ContentType::File {
let content = fs::read(self.infos.location()?).unwrap();
self.infos.set_data(&content)?;
}
match self.infos.metadata.process()? {
Process::Encryption => {
let (encrypted_data, nonce_vec) = self.process_data()?;
let mut hmac = Sign::new(
encrypted_data,
passphrase,
Operation::Sign,
SignType::Sha512,
);
let data = hmac.hmac();
if self.infos.safe()? {
self.infos.set_data(&data)?;
self.infos.safe_file()?;
}
Ok((data, nonce_vec))
}
Process::Decryption => {
let mut verifier = Sign::new(
self.infos.content()?.to_vec(),
passphrase,
Operation::Verify,
SignType::Sha512,
);
let data = verifier.hmac();
self.infos.set_data(&data)?;
let (decrypted, nonce_vec) = self.process_data()?;
if self.infos.safe()? {
self.infos.set_data(&decrypted)?;
self.infos.safe_file()?;
}
Ok((decrypted, nonce_vec))
}
}
}
#[allow(dead_code)]
fn process_data(&self) -> Result<(Vec<u8>, Vec<u8>), CryptError> {
let data = &self.infos.content()?;
let sharedsecret = self.sharedsecret()?;
let nonce = self.nonce();
let mut encrypted_data = data.to_vec();
let mut cipher = XChaCha20::new(
GenericArray::from_slice(sharedsecret),
GenericArray::from_slice(nonce),
);
cipher.apply_keystream(&mut encrypted_data);
Ok((encrypted_data, nonce.to_vec()))
}
}
#[cfg(feature = "legacy-pqclean")]
impl CryptographicFunctions for CipherChaCha {
fn encrypt(&mut self, public_key: Vec<u8>) -> Result<(Vec<u8>, Vec<u8>), CryptError> {
let key = KeyControlVariant::new(self.infos.metadata.key_type()?);
let (sharedsecret, ciphertext) = key.encap(&public_key)?;
let _ = self.set_shared_secret(sharedsecret);
let (encrypted_data, nonce) = self.cryptography()?;
println!("Please write down this nonce: {}", hex::encode(nonce));
Ok((encrypted_data, ciphertext))
}
fn decrypt(&mut self, secret_key: Vec<u8>, ciphertext: Vec<u8>) -> Result<Vec<u8>, CryptError> {
let key = KeyControlVariant::new(self.infos.metadata.key_type()?);
let sharedsecret = key.decap(&secret_key, &ciphertext)?;
let _ = self.set_shared_secret(sharedsecret);
let (decrypted_data, _nonce) = self.cryptography()?;
Ok(decrypted_data)
}
}